Skip to content

Commit 39adab1

Browse files
irvinlimdarrenjennings
authored andcommitted
feat(target/http) add raw HTTP request string (RFC 7230) (#99)
* feat(option) default autoContentLength to true * test(fixtures) add test fixtures
1 parent 642fbe4 commit 39adab1

File tree

19 files changed

+222
-3
lines changed

19 files changed

+222
-3
lines changed

src/targets/http/http1.1.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @description
3+
* HTTP code snippet generator to generate raw HTTP/1.1 request strings,
4+
* in accordance to the RFC 7230 (and RFC 7231) specifications.
5+
*
6+
* @author
7+
* @irvinlim
8+
*
9+
* For any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
10+
*/
11+
12+
'use strict'
13+
14+
var CRLF = '\r\n'
15+
var CodeBuilder = require('../../helpers/code-builder')
16+
var util = require('util')
17+
18+
/**
19+
* Request follows the request message format in accordance to RFC 7230, Section 3.
20+
* Each section is prepended with the RFC and section number.
21+
* See more at https://tools.ietf.org/html/rfc7230#section-3.
22+
*/
23+
module.exports = function (source, options) {
24+
var opts = Object.assign(
25+
{
26+
absoluteURI: false,
27+
autoContentLength: true,
28+
autoHost: true
29+
},
30+
options
31+
)
32+
33+
// RFC 7230 Section 3. Message Format
34+
// All lines have no indentation, and should be terminated with CRLF.
35+
var code = new CodeBuilder('', CRLF)
36+
37+
// RFC 7230 Section 5.3. Request Target
38+
// Determines if the Request-Line should use 'absolute-form' or 'origin-form'.
39+
// Basically it means whether the "http://domain.com" will prepend the full url.
40+
var requestUrl = opts.absoluteURI ? source.fullUrl : source.uriObj.path
41+
42+
// RFC 7230 Section 3.1.1. Request-Line
43+
code.push('%s %s %s', source.method, requestUrl, source.httpVersion)
44+
45+
// 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+
var keyCapitalized = key.toLowerCase().replace(/(^|-)(\w)/g, function (x) {
49+
return x.toUpperCase()
50+
})
51+
52+
code.push(
53+
'%s',
54+
util.format('%s: %s', keyCapitalized, source.allHeaders[key])
55+
)
56+
})
57+
58+
// RFC 7230 Section 5.4. Host
59+
// Automatically set Host header if option is on and on header already exists.
60+
if (opts.autoHost && Object.keys(source.allHeaders).indexOf('host') === -1) {
61+
code.push('Host: %s', source.uriObj.host)
62+
}
63+
64+
// RFC 7230 Section 3.3.3. Message Body Length
65+
// Automatically set Content-Length header if option is on, postData is present and no header already exists.
66+
if (
67+
opts.autoContentLength &&
68+
source.postData.text &&
69+
Object.keys(source.allHeaders).indexOf('content-length') === -1
70+
) {
71+
code.push(
72+
'Content-Length: %d',
73+
Buffer.byteLength(source.postData.text, 'ascii')
74+
)
75+
}
76+
77+
// Add extra line after header section.
78+
code.blank()
79+
80+
// Separate header section and message body section.
81+
var headerSection = code.join()
82+
var messageBody = ''
83+
84+
// RFC 7230 Section 3.3. Message Body
85+
if (source.postData.text) {
86+
messageBody = source.postData.text
87+
}
88+
89+
// RFC 7230 Section 3. Message Format
90+
// Extra CRLF separating the headers from the body.
91+
return headerSection + CRLF + messageBody
92+
}
93+
94+
module.exports.info = {
95+
key: '1.1',
96+
title: 'HTTP/1.1',
97+
link: 'https://tools.ietf.org/html/rfc7230',
98+
description: 'HTTP/1.1 request string in accordance with RFC 7230'
99+
}

src/targets/http/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
'use strict'
2+
3+
module.exports = {
4+
info: {
5+
key: 'http',
6+
title: 'HTTP',
7+
extname: '',
8+
default: '1.1'
9+
},
10+
11+
'1.1': require('./http1.1')
12+
}

src/targets/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
clojure: require('./clojure'),
66
csharp: require('./csharp'),
77
go: require('./go'),
8+
http: require('./http'),
89
java: require('./java'),
910
javascript: require('./javascript'),
1011
node: require('./node'),

test/fixtures/available-targets.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
"extname": ".m",
138138
"default": "nsurlsession",
139139
"clients": [
140-
{
140+
{
141141
"key": "nsurlsession",
142142
"title": "NSURLSession",
143143
"link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html",
@@ -151,7 +151,7 @@
151151
"extname": ".swift",
152152
"default": "nsurlsession",
153153
"clients": [
154-
{
154+
{
155155
"key": "nsurlsession",
156156
"title": "NSURLSession",
157157
"link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html",
@@ -165,7 +165,7 @@
165165
"extname": ".go",
166166
"default": "native",
167167
"clients": [
168-
{
168+
{
169169
"key": "native",
170170
"title": "NewRequest",
171171
"link": "http://golang.org/pkg/net/http/#NewRequest",
@@ -268,5 +268,19 @@
268268
"title": "Invoke-RestMethod"
269269
}
270270
]
271+
},
272+
{
273+
"default": "1.1",
274+
"extname": "",
275+
"key": "http",
276+
"title": "HTTP",
277+
"clients": [
278+
{
279+
"description": "HTTP/1.1 request string in accordance with RFC 7230",
280+
"key": "1.1",
281+
"link": "https://tools.ietf.org/html/rfc7230",
282+
"title": "HTTP/1.1"
283+
}
284+
]
271285
}
272286
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
POST /har HTTP/1.1
2+
Content-Type: application/x-www-form-urlencoded
3+
Host: mockbin.com
4+
Content-Length: 19
5+
6+
foo=bar&hello=world
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
POST /har HTTP/1.1
2+
Content-Type: application/json
3+
Host: mockbin.com
4+
Content-Length: 118
5+
6+
{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
POST /har HTTP/1.1
2+
Cookie: foo=bar; bar=baz
3+
Host: mockbin.com
4+
5+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
PROPFIND /har HTTP/1.1
2+
Host: mockbin.com
3+
4+

test/fixtures/output/http/1.1/full

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
POST /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1
2+
Cookie: foo=bar; bar=baz
3+
Accept: application/json
4+
Content-Type: application/x-www-form-urlencoded
5+
Host: mockbin.com
6+
Content-Length: 7
7+
8+
foo=bar
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
GET /har HTTP/1.1
2+
Accept: application/json
3+
X-Foo: Bar
4+
Host: mockbin.com
5+
6+

0 commit comments

Comments
 (0)