Skip to content

Commit 97a59c1

Browse files
committed
Tighten up raw header accuracy in HTTP/1.1 snippets
1 parent 9d07b3b commit 97a59c1

File tree

13 files changed

+53
-39
lines changed

13 files changed

+53
-39
lines changed

src/index.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,21 @@ HTTPSnippet.prototype.prepare = function (request) {
168168

169169
request.postData.boundary = boundary
170170

171-
// Since headers are case-sensitive we need to see if there's an existing `Content-Type` header that we can
172-
// override.
173-
const contentTypeHeader = helpers.hasHeader(request.headersObj, 'content-type')
174-
? helpers.getHeaderName(request.headersObj, 'content-type')
175-
: 'content-type'
171+
const multipartContentType = 'multipart/form-data; boundary=' + boundary
176172

177-
request.headersObj[contentTypeHeader] = 'multipart/form-data; boundary=' + boundary
173+
// We need to update the various header states to match the CT to our boundary:
174+
if (helpers.hasHeader(request.headersObj, 'content-type')) {
175+
// Since headers are case-sensitive we need to see if there's an existing `Content-Type`
176+
// header that we can override.
177+
const contentTypeHeader = helpers.getHeaderName(request.headersObj, 'content-type')
178+
request.headersObj[contentTypeHeader] = multipartContentType
179+
180+
const headerEntry = request.headers.findLast(h => h.name.toLowerCase() === 'content-type')
181+
headerEntry.value = multipartContentType
182+
} else {
183+
request.headersObj['Content-Type'] = multipartContentType
184+
request.headers.push({ name: 'Content-Type', value: multipartContentType })
185+
}
178186
}
179187
break
180188

src/targets/http/http1.1.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,27 @@ module.exports = function (source, options) {
4343
code.push('%s %s %s', source.method, requestUrl, source.httpVersion)
4444

4545
// RFC 7231 Section 5. Header Fields
46-
Object.keys(source.allHeaders).forEach(function (key) {
47-
// Capitalize header keys, even though it's not required by the spec.
48-
const keyCapitalized = key.toLowerCase().replace(/(^|-)(\w)/g, function (x) {
49-
return x.toUpperCase()
50-
})
51-
46+
source.headers.forEach((header) => {
5247
code.push(
5348
'%s',
54-
util.format('%s: %s', keyCapitalized, source.allHeaders[key])
49+
util.format('%s: %s', header.name, header.value)
5550
)
5651
})
5752

53+
// Unlike most other snippets, we use the fully raw input here (not headerObj/allHeaders)
54+
// so we need to hook into the prepare() cookie injection logic:
55+
if (source.allHeaders.cookie && !source.headers.find(h => h.name.toLowerCase() === 'cookie')) {
56+
code.push(
57+
'%s',
58+
util.format('%s: %s', 'Cookie', source.allHeaders.cookie)
59+
)
60+
}
61+
62+
const headerKeys = Object.keys(source.allHeaders).map(k => k.toLowerCase())
63+
5864
// RFC 7230 Section 5.4. Host
5965
// Automatically set Host header if option is on and on header already exists.
60-
if (opts.autoHost && Object.keys(source.allHeaders).indexOf('host') === -1) {
66+
if (opts.autoHost && headerKeys.indexOf('host') === -1) {
6167
code.push('Host: %s', source.uriObj.host)
6268
}
6369

@@ -66,7 +72,7 @@ module.exports = function (source, options) {
6672
if (
6773
opts.autoContentLength &&
6874
source.postData.text &&
69-
Object.keys(source.allHeaders).indexOf('content-length') === -1
75+
headerKeys.indexOf('conteTnt-length') === -1
7076
) {
7177
code.push(
7278
'Content-Length: %d',

test/fixtures/output/http/1.1/application-form-encoded

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
POST /har HTTP/1.1
2-
Content-Type: application/x-www-form-urlencoded
2+
content-type: application/x-www-form-urlencoded
33
Host: mockbin.com
44
Content-Length: 19
55

test/fixtures/output/http/1.1/application-json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
POST /har HTTP/1.1
2-
Content-Type: application/json
2+
content-type: application/json
33
Host: mockbin.com
44
Content-Length: 118
55

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
GET /har HTTP/1.1
2-
Accept-Encoding: deflate, gzip, br
2+
accept-encoding: deflate, gzip, br
33
Host: mockbin.com

test/fixtures/output/http/1.1/full

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
POST /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1
2+
accept: application/json
3+
content-type: application/x-www-form-urlencoded
24
Cookie: foo=bar; bar=baz
3-
Accept: application/json
4-
Content-Type: application/x-www-form-urlencoded
55
Host: mockbin.com
66
Content-Length: 7
77

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
GET /har HTTP/1.1
2-
Accept: application/json
3-
X-Foo: Bar
4-
Quoted-Value: "quoted" 'string'
2+
accept: application/json
3+
x-foo: Bar
4+
quoted-value: "quoted" 'string'
55
Host: mockbin.com
66

77

test/fixtures/output/http/1.1/jsonObj-multiline

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
POST /har HTTP/1.1
2-
Content-Type: application/json
2+
content-type: application/json
33
Host: mockbin.com
44
Content-Length: 18
55

test/fixtures/output/http/1.1/jsonObj-null-value

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
POST /har HTTP/1.1
2-
Content-Type: application/json
2+
content-type: application/json
33
Host: mockbin.com
44
Content-Length: 12
55

test/fixtures/output/http/1.1/malicious

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
POST /%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C HTTP/1.1
22
': squote-key-test
3-
Squote-Value-Test: '
4-
Dquote-Value-Test: "
3+
squote-value-test: '
4+
dquote-value-test: "
55
`: backtick-key-test
6-
Backtick-Value-Test: `
6+
backtick-value-test: `
77
$: dollar-key-test
8-
Dollar-Parenthesis-Value-Test: $(
8+
dollar-parenthesis-value-test: $(
99
#: hash-key-test
10-
Hash-Brace-Value-Test: #{
10+
hash-brace-value-test: #{
1111
%: percent-key-test
12-
Percent-Parenthesis-Value-Test: %(
13-
Percent-Brace-Value-Test: %{
14-
Double-Brace-Value-Test: {{
15-
Null-Value-Test: \0
16-
String-Fmt-Value-Test: %s
17-
Slash-Value-Test: \
12+
percent-parenthesis-value-test: %(
13+
percent-brace-value-test: %{
14+
double-brace-value-test: {{
15+
null-value-test: \0
16+
string-fmt-value-test: %s
17+
slash-value-test: \
1818
Host: example.test
1919
Content-Length: 28
2020

0 commit comments

Comments
 (0)