Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: regression in header case-insensitivity #188

Merged
merged 2 commits into from
Nov 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/helpers/headers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module.exports = {
/**
* Given a headers object retrieve the contents of a header out of it via a case-insensitive key.
*
* @param {object} headers
* @param {string} name
* @return {string}
*/
getHeader: (headers, name) => {
return headers[Object.keys(headers).find(k => k.toLowerCase() === name.toLowerCase())]
},

/**
* Given a headers object retrieve a specific header out of it via a case-insensitive key.
*
* @param {object} headers
* @param {string} name
* @return {string}
*/
getHeaderName: (headers, name) => {
return Object.keys(headers).find(k => {
if (k.toLowerCase() === name.toLowerCase()) {
return k
}
})
},

/**
* Determine if a given case-insensitive header exists within a header object.
*
* @param {object} headers
* @param {string} name
* @return {(integer|boolean)}
*/
hasHeader: (headers, name) => {
return Boolean(Object.keys(headers).find(k => k.toLowerCase() === name.toLowerCase()))
}
}
10 changes: 9 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var es = require('event-stream')
var MultiPartForm = require('form-data')
var qs = require('querystring')
var reducer = require('./helpers/reducer')
var helpers = require('./helpers/headers')
var targets = require('./targets')
var url = require('url')
var validate = require('har-validator/lib/async')
Expand Down Expand Up @@ -165,7 +166,14 @@ HTTPSnippet.prototype.prepare = function (request) {
}

request.postData.boundary = boundary
request.headersObj['content-type'] = 'multipart/form-data; boundary=' + boundary

// Since headers are case-sensitive we need to see if there's an existing `Content-Type` header that we can
// override.
const contentTypeHeader = helpers.hasHeader(request.headersObj, 'content-type')
? helpers.getHeaderName(request.headersObj, 'content-type')
: 'content-type'

request.headersObj[contentTypeHeader] = 'multipart/form-data; boundary=' + boundary
}
break

Expand Down
13 changes: 7 additions & 6 deletions src/targets/clojure/clj_http.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

var Keyword = function (name) {
this.name = name
Expand Down Expand Up @@ -101,15 +102,15 @@ module.exports = function (source, options) {
case 'application/json':
params['content-type'] = new Keyword('json')
params['form-params'] = source.postData.jsonObj
delete params.headers['content-type']
delete params.headers[helpers.getHeaderName(params.headers, 'content-type')]
break
case 'application/x-www-form-urlencoded':
params['form-params'] = source.postData.paramsObj
delete params.headers['content-type']
delete params.headers[helpers.getHeaderName(params.headers, 'content-type')]
break
case 'text/plain':
params.body = source.postData.text
delete params.headers['content-type']
delete params.headers[helpers.getHeaderName(params.headers, 'content-type')]
break
case 'multipart/form-data':
params.multipart = source.postData.params.map(function (x) {
Expand All @@ -121,14 +122,14 @@ module.exports = function (source, options) {
content: x.value}
}
})
delete params.headers['content-type']
delete params.headers[helpers.getHeaderName(params.headers, 'content-type')]
break
}

switch (params.headers.accept) {
switch (helpers.getHeader(params.headers, 'accept')) {
case 'application/json':
params.accept = new Keyword('json')
delete params.headers.accept
delete params.headers[helpers.getHeaderName(params.headers, 'accept')]
break
}

Expand Down
5 changes: 3 additions & 2 deletions src/targets/csharp/httpclient.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

function getDecompressionMethods (source) {
var acceptEncoding = source.allHeaders['accept-encoding']
var acceptEncoding = helpers.getHeader(source.allHeaders, 'accept-encoding')
if (!acceptEncoding) {
return [] // no decompression
}
Expand Down Expand Up @@ -67,7 +68,7 @@ module.exports = function (source, options) {
code.push(1, 'RequestUri = new Uri("%s"),', source.fullUrl)

var headers = Object.keys(source.allHeaders).filter(function (header) {
switch (header) {
switch (header.toLowerCase()) {
case 'content-type':
case 'content-length':
case 'accept-encoding':
Expand Down
7 changes: 6 additions & 1 deletion src/targets/csharp/restsharp.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

module.exports = function (source, options) {
var code = new CodeBuilder()
Expand Down Expand Up @@ -31,7 +32,11 @@ module.exports = function (source, options) {
}

if (source.postData.text) {
code.push('request.AddParameter("%s", %s, ParameterType.RequestBody);', source.allHeaders['content-type'], JSON.stringify(source.postData.text))
code.push(
'request.AddParameter("%s", %s, ParameterType.RequestBody);',
helpers.getHeader(source.allHeaders, 'content-type'),
JSON.stringify(source.postData.text)
)
}

code.push('IRestResponse response = client.Execute(request);')
Expand Down
8 changes: 6 additions & 2 deletions src/targets/javascript/jquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

module.exports = function (source, options) {
var opts = Object.assign({
Expand Down Expand Up @@ -50,9 +51,12 @@ module.exports = function (source, options) {
settings.data = '[form]'

// remove the contentType header
if (~settings.headers['content-type'].indexOf('boundary')) {
delete settings.headers['content-type']
if (helpers.hasHeader(settings.headers, 'content-type')) {
if (helpers.getHeader(settings.headers, 'content-type').indexOf('boundary')) {
delete settings.headers[helpers.getHeaderName(settings.headers, 'content-type')]
}
}

code.blank()
break

Expand Down
7 changes: 5 additions & 2 deletions src/targets/javascript/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

module.exports = function (source, options) {
var opts = Object.assign({
Expand All @@ -34,8 +35,10 @@ module.exports = function (source, options) {
})

// remove the contentType header
if (source.allHeaders['content-type'].indexOf('boundary')) {
delete source.allHeaders['content-type']
if (helpers.hasHeader(source.allHeaders, 'content-type')) {
if (helpers.getHeader(source.allHeaders, 'content-type').indexOf('boundary')) {
delete source.allHeaders[helpers.getHeaderName(source.allHeaders, 'content-type')]
}
}

code.blank()
Expand Down
7 changes: 5 additions & 2 deletions src/targets/php/http2.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'use strict'

var helpers = require('./helpers')
var headerHelpers = require('../../helpers/headers')
var CodeBuilder = require('../../helpers/code-builder')

module.exports = function (source, options) {
Expand Down Expand Up @@ -65,8 +66,10 @@ module.exports = function (source, options) {
)

// remove the contentType header
if (~source.headersObj['content-type'].indexOf('boundary')) {
delete source.headersObj['content-type']
if (headerHelpers.hasHeader(source.headersObj, 'content-type')) {
if (headerHelpers.getHeader(source.headersObj, 'content-type').indexOf('boundary')) {
delete source.headersObj[headerHelpers.getHeaderName(source.headersObj, 'content-type')]
}
}

code.blank()
Expand Down
3 changes: 2 additions & 1 deletion src/targets/powershell/common.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

var CodeBuilder = require('../../helpers/code-builder')
var helpers = require('../../helpers/headers')

module.exports = function (command) {
return function (source, options) {
Expand Down Expand Up @@ -44,7 +45,7 @@ module.exports = function (command) {
}

if (source.postData.text) {
commandOptions.push("-ContentType '" + source.allHeaders['content-type'] + "'")
commandOptions.push("-ContentType '" + helpers.getHeader(source.allHeaders, 'content-type') + "'")
commandOptions.push("-Body '" + source.postData.text + "'")
}

Expand Down
6 changes: 3 additions & 3 deletions src/targets/r/httr.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ module.exports = function (source, options) {
var accept

for (head in headers) {
if (head === 'accept') {
if (head.toLowerCase() === 'accept') {
accept = ', accept("' + headers[head] + '")'
headerCount = headerCount - 1
} else if (head === 'cookie') {
} else if (head.toLowerCase() === 'cookie') {
cookies = ', set_cookies(`' + headers[head].replace(/;/g, '", `').replace(/` /g, '`').replace(/=/g, '` = "') + '")'
headerCount = headerCount - 1
} else if (head !== 'content-type') {
} else if (head.toLowerCase() !== 'content-type') {
header = header + head.replace('-', '_') + " = '" + headers[head]
if (headerCount > 1) { header = header + "', " }
}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/c/libcurl/multipart-form-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "content-type: multipart/form-data; boundary=---011000010111000001101001");
headers = curl_slist_append(headers, "Content-Type: multipart/form-data; boundary=---011000010111000001101001");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var client = new RestClient("http://mockbin.com/har");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001");
request.AddHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001");
request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
2 changes: 1 addition & 1 deletion test/fixtures/output/go/native/multipart-form-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001")
req.Header.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")

res, _ := http.DefaultClient.Do(req)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
AsyncHttpClient client = new DefaultAsyncHttpClient();
client.prepare("POST", "http://mockbin.com/har")
.setHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.setHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.setBody("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n")
.execute()
.toCompletableFuture()
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/java/nethttp/multipart-form-data.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://mockbin.com/har"))
.header("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.method("POST", HttpRequest.BodyPublishers.ofString("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/java/okhttp/multipart-form-data.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Request request = new Request.Builder()
.url("http://mockbin.com/har")
.post(body)
.addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.addHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.build();

Response response = client.newCall(request).execute();
2 changes: 1 addition & 1 deletion test/fixtures/output/java/unirest/multipart-form-data.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
HttpResponse<String> response = Unirest.post("http://mockbin.com/har")
.header("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n")
.asString();
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ form.append("foo", "bar");
const options = {
method: 'POST',
url: 'http://mockbin.com/har',
headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'},
headers: {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'},
data: '[form]'
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ form.append("foo", "bar");
fetch("http://mockbin.com/har", {
"method": "POST",
"headers": {
"content-type": "multipart/form-data; boundary=---011000010111000001101001"
"Content-Type": "multipart/form-data; boundary=---011000010111000001101001"
}
})
.then(response => {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/kotlin/okhttp/multipart-form-data.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ val body = RequestBody.create(mediaType, "-----011000010111000001101001\r\nConte
val request = Request.Builder()
.url("http://mockbin.com/har")
.post(body)
.addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.addHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.build()

val response = client.newCall(request).execute()
2 changes: 1 addition & 1 deletion test/fixtures/output/node/axios/multipart-form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var axios = require("axios").default;
var options = {
method: 'POST',
url: 'http://mockbin.com/har',
headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'},
headers: {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'},
data: '-----011000010111000001101001\r\nContent-Disposition: form-data; name="foo"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n'
};

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/node/fetch/multipart-form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let url = 'http://mockbin.com/har';

let options = {
method: 'POST',
headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}
headers: {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'}
};

options.body = formData;
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/node/native/multipart-form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const options = {
"port": null,
"path": "/har",
"headers": {
"content-type": "multipart/form-data; boundary=---011000010111000001101001"
"Content-Type": "multipart/form-data; boundary=---011000010111000001101001"
}
};

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/node/request/multipart-form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const request = require('request');
const options = {
method: 'POST',
url: 'http://mockbin.com/har',
headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'},
headers: {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'},
formData: {foo: 'bar'}
};

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/node/unirest/multipart-form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const unirest = require("unirest");
const req = unirest("POST", "http://mockbin.com/har");

req.headers({
"content-type": "multipart/form-data; boundary=---011000010111000001101001"
"Content-Type": "multipart/form-data; boundary=---011000010111000001101001"
});

req.multipart([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"multipart/form-data; boundary=---011000010111000001101001" };
NSDictionary *headers = @{ @"Content-Type": @"multipart/form-data; boundary=---011000010111000001101001" };
NSArray *parameters = @[ @{ @"name": @"foo", @"value": @"bar" } ];
NSString *boundary = @"---011000010111000001101001";

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/output/ocaml/cohttp/multipart-form-data.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ open Cohttp
open Lwt

let uri = Uri.of_string "http://mockbin.com/har" in
let headers = Header.add (Header.init ()) "content-type" "multipart/form-data; boundary=---011000010111000001101001" in
let headers = Header.add (Header.init ()) "Content-Type" "multipart/form-data; boundary=---011000010111000001101001" in
let body = Cohttp_lwt_body.of_string "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n" in

Client.call ~headers ~body `POST uri
Expand Down
Loading