@wiajs/request 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.github/ISSUE_TEMPLATE.md +56 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  3. package/.github/stale.yml +19 -0
  4. package/.swcrc +57 -0
  5. package/.travis.yml +21 -0
  6. package/CHANGELOG.md +717 -0
  7. package/CONTRIBUTING.md +81 -0
  8. package/biome.json +44 -0
  9. package/codecov.yml +2 -0
  10. package/disabled.appveyor.yml +36 -0
  11. package/dist/request.cjs +1476 -0
  12. package/dist/request.mjs +1474 -0
  13. package/examples/README.md +135 -0
  14. package/gulpfile.js +71 -0
  15. package/package.json +1 -2
  16. package/release.sh +45 -0
  17. package/tests/browser/karma.conf.js +57 -0
  18. package/tests/browser/ssl/ca.crt +14 -0
  19. package/tests/browser/ssl/server.crt +14 -0
  20. package/tests/browser/ssl/server.key +15 -0
  21. package/tests/browser/start.js +37 -0
  22. package/tests/browser/test.js +34 -0
  23. package/tests/fixtures/har.json +158 -0
  24. package/tests/googledoodle.jpg +0 -0
  25. package/tests/server.js +142 -0
  26. package/tests/squid.conf +76 -0
  27. package/tests/ssl/ca/README.md +8 -0
  28. package/tests/ssl/ca/ca.cnf +20 -0
  29. package/tests/ssl/ca/ca.crl +0 -0
  30. package/tests/ssl/ca/ca.crt +17 -0
  31. package/tests/ssl/ca/ca.csr +13 -0
  32. package/tests/ssl/ca/ca.key +18 -0
  33. package/tests/ssl/ca/ca.srl +1 -0
  34. package/tests/ssl/ca/client-enc.key +30 -0
  35. package/tests/ssl/ca/client.cnf +20 -0
  36. package/tests/ssl/ca/client.crt +20 -0
  37. package/tests/ssl/ca/client.csr +18 -0
  38. package/tests/ssl/ca/client.key +27 -0
  39. package/tests/ssl/ca/gen-all-certs.sh +6 -0
  40. package/tests/ssl/ca/gen-client.sh +25 -0
  41. package/tests/ssl/ca/gen-localhost.sh +22 -0
  42. package/tests/ssl/ca/gen-server.sh +18 -0
  43. package/tests/ssl/ca/localhost.cnf +20 -0
  44. package/tests/ssl/ca/localhost.crt +20 -0
  45. package/tests/ssl/ca/localhost.csr +18 -0
  46. package/tests/ssl/ca/localhost.js +33 -0
  47. package/tests/ssl/ca/localhost.key +27 -0
  48. package/tests/ssl/ca/server.cnf +19 -0
  49. package/tests/ssl/ca/server.crt +25 -0
  50. package/tests/ssl/ca/server.csr +29 -0
  51. package/tests/ssl/ca/server.js +34 -0
  52. package/tests/ssl/ca/server.key +51 -0
  53. package/tests/ssl/npm-ca.crt +16 -0
  54. package/tests/ssl/test.crt +15 -0
  55. package/tests/ssl/test.key +15 -0
  56. package/tests/test-agent.js +102 -0
  57. package/tests/test-agentOptions.js +51 -0
  58. package/tests/test-api.js +33 -0
  59. package/tests/test-aws.js +123 -0
  60. package/tests/test-baseUrl.js +133 -0
  61. package/tests/test-basic-auth.js +221 -0
  62. package/tests/test-bearer-auth.js +187 -0
  63. package/tests/test-body.js +154 -0
  64. package/tests/test-cookies.js +130 -0
  65. package/tests/test-defaults.js +340 -0
  66. package/tests/test-digest-auth.js +232 -0
  67. package/tests/test-emptyBody.js +56 -0
  68. package/tests/test-errors.js +108 -0
  69. package/tests/test-event-forwarding.js +39 -0
  70. package/tests/test-follow-all-303.js +45 -0
  71. package/tests/test-follow-all.js +57 -0
  72. package/tests/test-form-data-error.js +85 -0
  73. package/tests/test-form-data.js +133 -0
  74. package/tests/test-form-urlencoded.js +73 -0
  75. package/tests/test-form.js +101 -0
  76. package/tests/test-gzip.js +296 -0
  77. package/tests/test-har.js +175 -0
  78. package/tests/test-hawk.js +187 -0
  79. package/tests/test-headers.js +305 -0
  80. package/tests/test-http-signature.js +110 -0
  81. package/tests/test-httpModule.js +112 -0
  82. package/tests/test-https.js +116 -0
  83. package/tests/test-isUrl.js +120 -0
  84. package/tests/test-json-request.js +117 -0
  85. package/tests/test-localAddress.js +49 -0
  86. package/tests/test-multipart-encoding.js +147 -0
  87. package/tests/test-multipart.js +129 -0
  88. package/tests/test-node-debug.js +95 -0
  89. package/tests/test-oauth.js +721 -0
  90. package/tests/test-onelineproxy.js +61 -0
  91. package/tests/test-option-reuse.js +54 -0
  92. package/tests/test-options-convenience-method.js +52 -0
  93. package/tests/test-params.js +101 -0
  94. package/tests/test-piped-redirect.js +55 -0
  95. package/tests/test-pipes.js +383 -0
  96. package/tests/test-pool.js +148 -0
  97. package/tests/test-promise.js +53 -0
  98. package/tests/test-proxy-connect.js +80 -0
  99. package/tests/test-proxy.js +304 -0
  100. package/tests/test-qs.js +135 -0
  101. package/tests/test-redirect-auth.js +131 -0
  102. package/tests/test-redirect-complex.js +93 -0
  103. package/tests/test-redirect.js +449 -0
  104. package/tests/test-rfc3986.js +106 -0
  105. package/tests/test-stream.js +36 -0
  106. package/tests/test-timeout.js +260 -0
  107. package/tests/test-timing.js +147 -0
  108. package/tests/test-toJSON.js +45 -0
  109. package/tests/test-tunnel.js +466 -0
  110. package/tests/test-unix.js +74 -0
  111. package/tests/unicycle.jpg +0 -0
  112. package/request.js +0 -1553
  113. package/src/ZlibTransform.js +0 -27
  114. package/src/caseless.js +0 -118
  115. package/src/index.js +0 -122
  116. package/src/request.js +0 -967
  117. package/src/utils.js +0 -274
@@ -0,0 +1,108 @@
1
+ 'use strict'
2
+
3
+ var request = require('../index')
4
+ var tape = require('tape')
5
+
6
+ var local = 'http://localhost:0/asdf'
7
+
8
+ tape('without uri', function (t) {
9
+ t.throws(function () {
10
+ request({})
11
+ }, /^Error: options\.uri is a required argument$/)
12
+ t.end()
13
+ })
14
+
15
+ tape('invalid uri 1', function (t) {
16
+ t.throws(function () {
17
+ request({
18
+ uri: 'this-is-not-a-valid-uri'
19
+ })
20
+ }, /^Error: Invalid URI/)
21
+ t.end()
22
+ })
23
+
24
+ tape('invalid uri 2', function (t) {
25
+ t.throws(function () {
26
+ request({
27
+ uri: 'github.com/uri-is-not-valid-without-protocol'
28
+ })
29
+ }, /^Error: Invalid URI/)
30
+ t.end()
31
+ })
32
+
33
+ tape('invalid uri + NO_PROXY', function (t) {
34
+ process.env.NO_PROXY = 'google.com'
35
+ t.throws(function () {
36
+ request({
37
+ uri: 'invalid'
38
+ })
39
+ }, /^Error: Invalid URI/)
40
+ delete process.env.NO_PROXY
41
+ t.end()
42
+ })
43
+
44
+ tape('deprecated unix URL', function (t) {
45
+ t.throws(function () {
46
+ request({
47
+ uri: 'unix://path/to/socket/and/then/request/path'
48
+ })
49
+ }, /^Error: `unix:\/\/` URL scheme is no longer supported/)
50
+ t.end()
51
+ })
52
+
53
+ tape('invalid body', function (t) {
54
+ t.throws(function () {
55
+ request({
56
+ uri: local, body: {}
57
+ })
58
+ }, /^Error: Argument error, options\.body\.$/)
59
+ t.end()
60
+ })
61
+
62
+ tape('invalid multipart', function (t) {
63
+ t.throws(function () {
64
+ request({
65
+ uri: local,
66
+ multipart: 'foo'
67
+ })
68
+ }, /^Error: Argument error, options\.multipart\.$/)
69
+ t.end()
70
+ })
71
+
72
+ tape('multipart without body 1', function (t) {
73
+ t.throws(function () {
74
+ request({
75
+ uri: local,
76
+ multipart: [ {} ]
77
+ })
78
+ }, /^Error: Body attribute missing in multipart\.$/)
79
+ t.end()
80
+ })
81
+
82
+ tape('multipart without body 2', function (t) {
83
+ t.throws(function () {
84
+ request(local, {
85
+ multipart: [ {} ]
86
+ })
87
+ }, /^Error: Body attribute missing in multipart\.$/)
88
+ t.end()
89
+ })
90
+
91
+ tape('head method with a body', function (t) {
92
+ t.throws(function () {
93
+ request(local, {
94
+ method: 'HEAD',
95
+ body: 'foo'
96
+ })
97
+ }, /HTTP HEAD requests MUST NOT include a request body/)
98
+ t.end()
99
+ })
100
+
101
+ tape('head method with a body 2', function (t) {
102
+ t.throws(function () {
103
+ request.head(local, {
104
+ body: 'foo'
105
+ })
106
+ }, /HTTP HEAD requests MUST NOT include a request body/)
107
+ t.end()
108
+ })
@@ -0,0 +1,39 @@
1
+ 'use strict'
2
+
3
+ var server = require('./server')
4
+ var request = require('../index')
5
+ var tape = require('tape')
6
+
7
+ var s = server.createServer()
8
+
9
+ tape('setup', function (t) {
10
+ s.listen(0, function () {
11
+ s.on('/', function (req, res) {
12
+ res.writeHead(200, { 'content-type': 'text/plain' })
13
+ res.write('waited')
14
+ res.end()
15
+ })
16
+ t.end()
17
+ })
18
+ })
19
+
20
+ tape('should emit socket event', function (t) {
21
+ t.plan(4)
22
+
23
+ var req = request(s.url, function (err, res, body) {
24
+ t.equal(err, null)
25
+ t.equal(res.statusCode, 200)
26
+ t.equal(body, 'waited')
27
+ })
28
+
29
+ req.on('socket', function (socket) {
30
+ var requestSocket = req.req.socket
31
+ t.equal(requestSocket, socket)
32
+ })
33
+ })
34
+
35
+ tape('cleanup', function (t) {
36
+ s.close(function () {
37
+ t.end()
38
+ })
39
+ })
@@ -0,0 +1,45 @@
1
+ 'use strict'
2
+
3
+ var http = require('http')
4
+ var request = require('../index')
5
+ var tape = require('tape')
6
+
7
+ var server = http.createServer(function (req, res) {
8
+ if (req.method === 'POST') {
9
+ res.setHeader('location', req.url)
10
+ res.statusCode = 303
11
+ res.end('try again')
12
+ } else {
13
+ res.end('ok')
14
+ }
15
+ })
16
+
17
+ tape('setup', function (t) {
18
+ server.listen(0, function () {
19
+ server.url = 'http://localhost:' + this.address().port
20
+ t.end()
21
+ })
22
+ })
23
+
24
+ tape('followAllRedirects with 303', function (t) {
25
+ var redirects = 0
26
+
27
+ request.post({
28
+ url: server.url + '/foo',
29
+ followAllRedirects: true,
30
+ form: { foo: 'bar' }
31
+ }, function (err, res, body) {
32
+ t.equal(err, null)
33
+ t.equal(body, 'ok')
34
+ t.equal(redirects, 1)
35
+ t.end()
36
+ }).on('redirect', function () {
37
+ redirects++
38
+ })
39
+ })
40
+
41
+ tape('cleanup', function (t) {
42
+ server.close(function () {
43
+ t.end()
44
+ })
45
+ })
@@ -0,0 +1,57 @@
1
+ 'use strict'
2
+
3
+ var http = require('http')
4
+ var request = require('../index')
5
+ var tape = require('tape')
6
+
7
+ var server = http.createServer(function (req, res) {
8
+ // redirect everything 3 times, no matter what.
9
+ var c = req.headers.cookie
10
+
11
+ if (!c) {
12
+ c = 0
13
+ } else {
14
+ c = +c.split('=')[1] || 0
15
+ }
16
+
17
+ if (c > 3) {
18
+ res.end('ok')
19
+ return
20
+ }
21
+
22
+ res.setHeader('set-cookie', 'c=' + (c + 1))
23
+ res.setHeader('location', req.url)
24
+ res.statusCode = 302
25
+ res.end('try again')
26
+ })
27
+
28
+ tape('setup', function (t) {
29
+ server.listen(0, function () {
30
+ server.url = 'http://localhost:' + this.address().port
31
+ t.end()
32
+ })
33
+ })
34
+
35
+ tape('followAllRedirects', function (t) {
36
+ var redirects = 0
37
+
38
+ request.post({
39
+ url: server.url + '/foo',
40
+ followAllRedirects: true,
41
+ jar: true,
42
+ form: { foo: 'bar' }
43
+ }, function (err, res, body) {
44
+ t.equal(err, null)
45
+ t.equal(body, 'ok')
46
+ t.equal(redirects, 4)
47
+ t.end()
48
+ }).on('redirect', function () {
49
+ redirects++
50
+ })
51
+ })
52
+
53
+ tape('cleanup', function (t) {
54
+ server.close(function () {
55
+ t.end()
56
+ })
57
+ })
@@ -0,0 +1,85 @@
1
+ 'use strict'
2
+
3
+ var request = require('../index')
4
+ var server = require('./server')
5
+ var tape = require('tape')
6
+
7
+ var s = server.createServer()
8
+
9
+ tape('setup', function (t) {
10
+ s.listen(0, function () {
11
+ t.end()
12
+ })
13
+ })
14
+
15
+ tape('re-emit formData errors', function (t) {
16
+ s.on('/', function (req, res) {
17
+ res.writeHead(400)
18
+ res.end()
19
+ t.fail('The form-data error did not abort the request.')
20
+ })
21
+
22
+ request.post(s.url, function (err, res, body) {
23
+ t.equal(err.message, 'form-data: Arrays are not supported.')
24
+ setTimeout(function () {
25
+ t.end()
26
+ }, 10)
27
+ }).form().append('field', ['value1', 'value2'])
28
+ })
29
+
30
+ tape('omit content-length header if the value is set to NaN', function (t) {
31
+ // returns chunked HTTP response which is streamed to the 2nd HTTP request in the form data
32
+ s.on('/chunky', server.createChunkResponse(
33
+ ['some string',
34
+ 'some other string'
35
+ ]))
36
+
37
+ // accepts form data request
38
+ s.on('/stream', function (req, resp) {
39
+ req.on('data', function (chunk) {
40
+ // consume the request body
41
+ })
42
+ req.on('end', function () {
43
+ resp.writeHead(200)
44
+ resp.end()
45
+ })
46
+ })
47
+
48
+ var sendStreamRequest = function (stream) {
49
+ request.post({
50
+ uri: s.url + '/stream',
51
+ formData: {
52
+ param: stream
53
+ }
54
+ }, function (err, res) {
55
+ t.error(err, 'request failed')
56
+ t.end()
57
+ })
58
+ }
59
+
60
+ request.get({
61
+ uri: s.url + '/chunky'
62
+ }).on('response', function (res) {
63
+ sendStreamRequest(res)
64
+ })
65
+ })
66
+
67
+ // TODO: remove this test after form-data@2.0 starts stringifying null values
68
+ tape('form-data should throw on null value', function (t) {
69
+ t.throws(function () {
70
+ request({
71
+ method: 'POST',
72
+ url: s.url,
73
+ formData: {
74
+ key: null
75
+ }
76
+ })
77
+ }, TypeError)
78
+ t.end()
79
+ })
80
+
81
+ tape('cleanup', function (t) {
82
+ s.close(function () {
83
+ t.end()
84
+ })
85
+ })
@@ -0,0 +1,133 @@
1
+ 'use strict'
2
+
3
+ var http = require('http')
4
+ var path = require('path')
5
+ var mime = require('mime-types')
6
+ var request = require('../index')
7
+ var fs = require('fs')
8
+ var tape = require('tape')
9
+
10
+ function runTest (t, options) {
11
+ var remoteFile = path.join(__dirname, 'googledoodle.jpg')
12
+ var localFile = path.join(__dirname, 'unicycle.jpg')
13
+ var multipartFormData = {}
14
+
15
+ var server = http.createServer(function (req, res) {
16
+ if (req.url === '/file') {
17
+ res.writeHead(200, {'content-type': 'image/jpg', 'content-length': 7187})
18
+ res.end(fs.readFileSync(remoteFile), 'binary')
19
+ return
20
+ }
21
+
22
+ if (options.auth) {
23
+ if (!req.headers.authorization) {
24
+ res.writeHead(401, {'www-authenticate': 'Basic realm="Private"'})
25
+ res.end()
26
+ return
27
+ } else {
28
+ t.ok(req.headers.authorization === 'Basic ' + Buffer.from('user:pass').toString('base64'))
29
+ }
30
+ }
31
+
32
+ t.ok(/multipart\/form-data; boundary=--------------------------\d+/
33
+ .test(req.headers['content-type']))
34
+
35
+ // temp workaround
36
+ var data = ''
37
+ req.setEncoding('utf8')
38
+
39
+ req.on('data', function (d) {
40
+ data += d
41
+ })
42
+
43
+ req.on('end', function () {
44
+ // check for the fields' traces
45
+
46
+ // 1st field : my_field
47
+ t.ok(data.indexOf('form-data; name="my_field"') !== -1)
48
+ t.ok(data.indexOf(multipartFormData.my_field) !== -1)
49
+
50
+ // 2nd field : my_buffer
51
+ t.ok(data.indexOf('form-data; name="my_buffer"') !== -1)
52
+ t.ok(data.indexOf(multipartFormData.my_buffer) !== -1)
53
+
54
+ // 3rd field : my_file
55
+ t.ok(data.indexOf('form-data; name="my_file"') !== -1)
56
+ t.ok(data.indexOf('; filename="' + path.basename(multipartFormData.my_file.path) + '"') !== -1)
57
+ // check for unicycle.jpg traces
58
+ t.ok(data.indexOf('2005:06:21 01:44:12') !== -1)
59
+ t.ok(data.indexOf('Content-Type: ' + mime.lookup(multipartFormData.my_file.path)) !== -1)
60
+
61
+ // 4th field : remote_file
62
+ t.ok(data.indexOf('form-data; name="remote_file"') !== -1)
63
+ t.ok(data.indexOf('; filename="' + path.basename(multipartFormData.remote_file.path) + '"') !== -1)
64
+
65
+ // 5th field : file with metadata
66
+ t.ok(data.indexOf('form-data; name="secret_file"') !== -1)
67
+ t.ok(data.indexOf('Content-Disposition: form-data; name="secret_file"; filename="topsecret.jpg"') !== -1)
68
+ t.ok(data.indexOf('Content-Type: image/custom') !== -1)
69
+
70
+ // 6th field : batch of files
71
+ t.ok(data.indexOf('form-data; name="batch"') !== -1)
72
+ t.ok(data.match(/form-data; name="batch"/g).length === 2)
73
+
74
+ // check for http://localhost:nnnn/file traces
75
+ t.ok(data.indexOf('Photoshop ICC') !== -1)
76
+ t.ok(data.indexOf('Content-Type: ' + mime.lookup(remoteFile)) !== -1)
77
+
78
+ res.writeHead(200)
79
+ res.end(options.json ? JSON.stringify({status: 'done'}) : 'done')
80
+ })
81
+ })
82
+
83
+ server.listen(0, function () {
84
+ var url = 'http://localhost:' + this.address().port
85
+ // @NOTE: multipartFormData properties must be set here so that my_file read stream does not leak in node v0.8
86
+ multipartFormData.my_field = 'my_value'
87
+ multipartFormData.my_buffer = Buffer.from([1, 2, 3])
88
+ multipartFormData.my_file = fs.createReadStream(localFile)
89
+ multipartFormData.remote_file = request(url + '/file')
90
+ multipartFormData.secret_file = {
91
+ value: fs.createReadStream(localFile),
92
+ options: {
93
+ filename: 'topsecret.jpg',
94
+ contentType: 'image/custom'
95
+ }
96
+ }
97
+ multipartFormData.batch = [
98
+ fs.createReadStream(localFile),
99
+ fs.createReadStream(localFile)
100
+ ]
101
+
102
+ var reqOptions = {
103
+ url: url + '/upload',
104
+ formData: multipartFormData
105
+ }
106
+ if (options.json) {
107
+ reqOptions.json = true
108
+ }
109
+ if (options.auth) {
110
+ reqOptions.auth = {user: 'user', pass: 'pass', sendImmediately: false}
111
+ }
112
+ request.post(reqOptions, function (err, res, body) {
113
+ t.equal(err, null)
114
+ t.equal(res.statusCode, 200)
115
+ t.deepEqual(body, options.json ? {status: 'done'} : 'done')
116
+ server.close(function () {
117
+ t.end()
118
+ })
119
+ })
120
+ })
121
+ }
122
+
123
+ tape('multipart formData', function (t) {
124
+ runTest(t, {json: false})
125
+ })
126
+
127
+ tape('multipart formData + JSON', function (t) {
128
+ runTest(t, {json: true})
129
+ })
130
+
131
+ tape('multipart formData + basic auth', function (t) {
132
+ runTest(t, {json: false, auth: true})
133
+ })
@@ -0,0 +1,73 @@
1
+ 'use strict'
2
+
3
+ var http = require('http')
4
+ var request = require('../index')
5
+ var tape = require('tape')
6
+
7
+ function runTest (t, options, index) {
8
+ var server = http.createServer(function (req, res) {
9
+ if (index === 0 || index === 3) {
10
+ t.equal(req.headers['content-type'], 'application/x-www-form-urlencoded')
11
+ } else {
12
+ t.equal(req.headers['content-type'], 'application/x-www-form-urlencoded; charset=UTF-8')
13
+ }
14
+ t.equal(req.headers['content-length'], '21')
15
+ t.equal(req.headers.accept, 'application/json')
16
+
17
+ var data = ''
18
+ req.setEncoding('utf8')
19
+
20
+ req.on('data', function (d) {
21
+ data += d
22
+ })
23
+
24
+ req.on('end', function () {
25
+ t.equal(data, 'some=url&encoded=data')
26
+
27
+ res.writeHead(200)
28
+ res.end('done')
29
+ })
30
+ })
31
+
32
+ server.listen(0, function () {
33
+ var url = 'http://localhost:' + this.address().port
34
+ var r = request.post(url, options, function (err, res, body) {
35
+ t.equal(err, null)
36
+ t.equal(res.statusCode, 200)
37
+ t.equal(body, 'done')
38
+ server.close(function () {
39
+ t.end()
40
+ })
41
+ })
42
+ if (!options.form && !options.body) {
43
+ r.form({some: 'url', encoded: 'data'})
44
+ }
45
+ })
46
+ }
47
+
48
+ var cases = [
49
+ {
50
+ form: {some: 'url', encoded: 'data'},
51
+ json: true
52
+ },
53
+ {
54
+ headers: {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
55
+ form: {some: 'url', encoded: 'data'},
56
+ json: true
57
+ },
58
+ {
59
+ headers: {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
60
+ body: 'some=url&encoded=data',
61
+ json: true
62
+ },
63
+ {
64
+ // body set via .form() method
65
+ json: true
66
+ }
67
+ ]
68
+
69
+ cases.forEach(function (options, index) {
70
+ tape('application/x-www-form-urlencoded ' + index, function (t) {
71
+ runTest(t, options, index)
72
+ })
73
+ })
@@ -0,0 +1,101 @@
1
+ 'use strict'
2
+
3
+ var http = require('http')
4
+ var path = require('path')
5
+ var mime = require('mime-types')
6
+ var request = require('../index')
7
+ var fs = require('fs')
8
+ var tape = require('tape')
9
+
10
+ tape('multipart form append', function (t) {
11
+ var remoteFile = path.join(__dirname, 'googledoodle.jpg')
12
+ var localFile = path.join(__dirname, 'unicycle.jpg')
13
+ var totalLength = null
14
+ var FIELDS = []
15
+
16
+ var server = http.createServer(function (req, res) {
17
+ if (req.url === '/file') {
18
+ res.writeHead(200, {'content-type': 'image/jpg', 'content-length': 7187})
19
+ res.end(fs.readFileSync(remoteFile), 'binary')
20
+ return
21
+ }
22
+
23
+ t.ok(/multipart\/form-data; boundary=--------------------------\d+/
24
+ .test(req.headers['content-type']))
25
+
26
+ // temp workaround
27
+ var data = ''
28
+ req.setEncoding('utf8')
29
+
30
+ req.on('data', function (d) {
31
+ data += d
32
+ })
33
+
34
+ req.on('end', function () {
35
+ var field
36
+ // check for the fields' traces
37
+
38
+ // 1st field : my_field
39
+ field = FIELDS.shift()
40
+ t.ok(data.indexOf('form-data; name="' + field.name + '"') !== -1)
41
+ t.ok(data.indexOf(field.value) !== -1)
42
+
43
+ // 2nd field : my_buffer
44
+ field = FIELDS.shift()
45
+ t.ok(data.indexOf('form-data; name="' + field.name + '"') !== -1)
46
+ t.ok(data.indexOf(field.value) !== -1)
47
+
48
+ // 3rd field : my_file
49
+ field = FIELDS.shift()
50
+ t.ok(data.indexOf('form-data; name="' + field.name + '"') !== -1)
51
+ t.ok(data.indexOf('; filename="' + path.basename(field.value.path) + '"') !== -1)
52
+ // check for unicycle.jpg traces
53
+ t.ok(data.indexOf('2005:06:21 01:44:12') !== -1)
54
+ t.ok(data.indexOf('Content-Type: ' + mime.lookup(field.value.path)) !== -1)
55
+
56
+ // 4th field : remote_file
57
+ field = FIELDS.shift()
58
+ t.ok(data.indexOf('form-data; name="' + field.name + '"') !== -1)
59
+ t.ok(data.indexOf('; filename="' + path.basename(field.value.path) + '"') !== -1)
60
+ // check for http://localhost:nnnn/file traces
61
+ t.ok(data.indexOf('Photoshop ICC') !== -1)
62
+ t.ok(data.indexOf('Content-Type: ' + mime.lookup(remoteFile)) !== -1)
63
+
64
+ t.ok(+req.headers['content-length'] === totalLength)
65
+
66
+ res.writeHead(200)
67
+ res.end('done')
68
+
69
+ t.equal(FIELDS.length, 0)
70
+ })
71
+ })
72
+
73
+ server.listen(0, function () {
74
+ var url = 'http://localhost:' + this.address().port
75
+ FIELDS = [
76
+ { name: 'my_field', value: 'my_value' },
77
+ { name: 'my_buffer', value: Buffer.from([1, 2, 3]) },
78
+ { name: 'my_file', value: fs.createReadStream(localFile) },
79
+ { name: 'remote_file', value: request(url + '/file') }
80
+ ]
81
+
82
+ var req = request.post(url + '/upload', function (err, res, body) {
83
+ t.equal(err, null)
84
+ t.equal(res.statusCode, 200)
85
+ t.equal(body, 'done')
86
+ server.close(function () {
87
+ t.end()
88
+ })
89
+ })
90
+ var form = req.form()
91
+
92
+ FIELDS.forEach(function (field) {
93
+ form.append(field.name, field.value)
94
+ })
95
+
96
+ form.getLength(function (err, length) {
97
+ t.equal(err, null)
98
+ totalLength = length
99
+ })
100
+ })
101
+ })