@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,131 @@
1
+ 'use strict'
2
+
3
+ var server = require('./server')
4
+ var request = require('../index')
5
+ var util = require('util')
6
+ var tape = require('tape')
7
+ var destroyable = require('server-destroy')
8
+
9
+ var s = server.createServer()
10
+ var ss = server.createSSLServer()
11
+
12
+ destroyable(s)
13
+ destroyable(ss)
14
+
15
+ // always send basic auth and allow non-strict SSL
16
+ request = request.defaults({
17
+ auth: {
18
+ user: 'test',
19
+ pass: 'testing'
20
+ },
21
+ rejectUnauthorized: false
22
+ })
23
+
24
+ // redirect.from(proto, host).to(proto, host) returns an object with keys:
25
+ // src : source URL
26
+ // dst : destination URL
27
+ var redirect = {
28
+ from: function (fromProto, fromHost) {
29
+ return {
30
+ to: function (toProto, toHost) {
31
+ var fromPort = (fromProto === 'http' ? s.port : ss.port)
32
+ var toPort = (toProto === 'http' ? s.port : ss.port)
33
+ return {
34
+ src: util.format(
35
+ '%s://%s:%d/to/%s/%s',
36
+ fromProto, fromHost, fromPort, toProto, toHost),
37
+ dst: util.format(
38
+ '%s://%s:%d/from/%s/%s',
39
+ toProto, toHost, toPort, fromProto, fromHost)
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ function handleRequests (srv) {
47
+ ['http', 'https'].forEach(function (proto) {
48
+ ['localhost', '127.0.0.1'].forEach(function (host) {
49
+ srv.on(util.format('/to/%s/%s', proto, host), function (req, res) {
50
+ var r = redirect
51
+ .from(srv.protocol, req.headers.host.split(':')[0])
52
+ .to(proto, host)
53
+ res.writeHead(301, {
54
+ location: r.dst
55
+ })
56
+ res.end()
57
+ })
58
+
59
+ srv.on(util.format('/from/%s/%s', proto, host), function (req, res) {
60
+ res.end('auth: ' + (req.headers.authorization || '(nothing)'))
61
+ })
62
+ })
63
+ })
64
+ }
65
+
66
+ handleRequests(s)
67
+ handleRequests(ss)
68
+
69
+ function runTest (name, redir, expectAuth) {
70
+ tape('redirect to ' + name, function (t) {
71
+ request(redir.src, function (err, res, body) {
72
+ t.equal(err, null)
73
+ t.equal(res.request.uri.href, redir.dst)
74
+ t.equal(res.statusCode, 200)
75
+ t.equal(body, expectAuth
76
+ ? 'auth: Basic dGVzdDp0ZXN0aW5n'
77
+ : 'auth: (nothing)')
78
+ t.end()
79
+ })
80
+ })
81
+ }
82
+
83
+ function addTests () {
84
+ runTest('same host and protocol',
85
+ redirect.from('http', 'localhost').to('http', 'localhost'),
86
+ true)
87
+
88
+ runTest('same host different protocol',
89
+ redirect.from('http', 'localhost').to('https', 'localhost'),
90
+ true)
91
+
92
+ runTest('different host same protocol',
93
+ redirect.from('https', '127.0.0.1').to('https', 'localhost'),
94
+ false)
95
+
96
+ runTest('different host and protocol',
97
+ redirect.from('http', 'localhost').to('https', '127.0.0.1'),
98
+ false)
99
+ }
100
+
101
+ tape('setup', function (t) {
102
+ s.listen(0, function () {
103
+ ss.listen(0, function () {
104
+ addTests()
105
+ tape('cleanup', function (t) {
106
+ s.destroy(function () {
107
+ ss.destroy(function () {
108
+ t.end()
109
+ })
110
+ })
111
+ })
112
+ t.end()
113
+ })
114
+ })
115
+ })
116
+
117
+ tape('redirect URL helper', function (t) {
118
+ t.deepEqual(
119
+ redirect.from('http', 'localhost').to('https', '127.0.0.1'),
120
+ {
121
+ src: util.format('http://localhost:%d/to/https/127.0.0.1', s.port),
122
+ dst: util.format('https://127.0.0.1:%d/from/http/localhost', ss.port)
123
+ })
124
+ t.deepEqual(
125
+ redirect.from('https', 'localhost').to('http', 'localhost'),
126
+ {
127
+ src: util.format('https://localhost:%d/to/http/localhost', ss.port),
128
+ dst: util.format('http://localhost:%d/from/https/localhost', s.port)
129
+ })
130
+ t.end()
131
+ })
@@ -0,0 +1,93 @@
1
+ 'use strict'
2
+
3
+ var server = require('./server')
4
+ var request = require('../index')
5
+ var events = require('events')
6
+ var tape = require('tape')
7
+ var destroyable = require('server-destroy')
8
+
9
+ var s = server.createServer()
10
+ var ss = server.createSSLServer()
11
+ var e = new events.EventEmitter()
12
+
13
+ destroyable(s)
14
+ destroyable(ss)
15
+
16
+ function bouncy (s, serverUrl) {
17
+ var redirs = {
18
+ a: 'b',
19
+ b: 'c',
20
+ c: 'd',
21
+ d: 'e',
22
+ e: 'f',
23
+ f: 'g',
24
+ g: 'h',
25
+ h: 'end'
26
+ }
27
+
28
+ var perm = true
29
+ Object.keys(redirs).forEach(function (p) {
30
+ var t = redirs[p]
31
+
32
+ // switch type each time
33
+ var type = perm ? 301 : 302
34
+ perm = !perm
35
+ s.on('/' + p, function (req, res) {
36
+ setTimeout(function () {
37
+ res.writeHead(type, { location: serverUrl + '/' + t })
38
+ res.end()
39
+ }, Math.round(Math.random() * 25))
40
+ })
41
+ })
42
+
43
+ s.on('/end', function (req, res) {
44
+ var key = req.headers['x-test-key']
45
+ e.emit('hit-' + key, key)
46
+ res.writeHead(200)
47
+ res.end(key)
48
+ })
49
+ }
50
+
51
+ tape('setup', function (t) {
52
+ s.listen(0, function () {
53
+ ss.listen(0, function () {
54
+ bouncy(s, ss.url)
55
+ bouncy(ss, s.url)
56
+ t.end()
57
+ })
58
+ })
59
+ })
60
+
61
+ tape('lots of redirects', function (t) {
62
+ var n = 10
63
+ t.plan(n * 4)
64
+
65
+ function doRedirect (i) {
66
+ var key = 'test_' + i
67
+ request({
68
+ url: (i % 2 ? s.url : ss.url) + '/a',
69
+ headers: { 'x-test-key': key },
70
+ rejectUnauthorized: false
71
+ }, function (err, res, body) {
72
+ t.equal(err, null)
73
+ t.equal(res.statusCode, 200)
74
+ t.equal(body, key)
75
+ })
76
+
77
+ e.once('hit-' + key, function (v) {
78
+ t.equal(v, key)
79
+ })
80
+ }
81
+
82
+ for (var i = 0; i < n; i++) {
83
+ doRedirect(i)
84
+ }
85
+ })
86
+
87
+ tape('cleanup', function (t) {
88
+ s.destroy(function () {
89
+ ss.destroy(function () {
90
+ t.end()
91
+ })
92
+ })
93
+ })
@@ -0,0 +1,449 @@
1
+ 'use strict'
2
+
3
+ var server = require('./server')
4
+ var assert = require('assert')
5
+ var request = require('../index')
6
+ var tape = require('tape')
7
+ var http = require('http')
8
+ var destroyable = require('server-destroy')
9
+
10
+ var s = server.createServer()
11
+ var ss = server.createSSLServer()
12
+ var hits = {}
13
+ var jar = request.jar()
14
+
15
+ destroyable(s)
16
+ destroyable(ss)
17
+
18
+ s.on('/ssl', function (req, res) {
19
+ res.writeHead(302, {
20
+ location: ss.url + '/'
21
+ })
22
+ res.end()
23
+ })
24
+
25
+ ss.on('/', function (req, res) {
26
+ res.writeHead(200)
27
+ res.end('SSL')
28
+ })
29
+
30
+ function createRedirectEndpoint (code, label, landing) {
31
+ s.on('/' + label, function (req, res) {
32
+ hits[label] = true
33
+ res.writeHead(code, {
34
+ 'location': s.url + '/' + landing,
35
+ 'set-cookie': 'ham=eggs'
36
+ })
37
+ res.end()
38
+ })
39
+ }
40
+
41
+ function createLandingEndpoint (landing) {
42
+ s.on('/' + landing, function (req, res) {
43
+ // Make sure the cookie doesn't get included twice, see #139:
44
+ // Make sure cookies are set properly after redirect
45
+ assert.equal(req.headers.cookie, 'foo=bar; quux=baz; ham=eggs')
46
+ hits[landing] = true
47
+ res.writeHead(200, {'x-response': req.method.toUpperCase() + ' ' + landing})
48
+ res.end(req.method.toUpperCase() + ' ' + landing)
49
+ })
50
+ }
51
+
52
+ function bouncer (code, label, hops) {
53
+ var hop
54
+ var landing = label + '_landing'
55
+ var currentLabel
56
+ var currentLanding
57
+
58
+ hops = hops || 1
59
+
60
+ if (hops === 1) {
61
+ createRedirectEndpoint(code, label, landing)
62
+ } else {
63
+ for (hop = 0; hop < hops; hop++) {
64
+ currentLabel = (hop === 0) ? label : label + '_' + (hop + 1)
65
+ currentLanding = (hop === hops - 1) ? landing : label + '_' + (hop + 2)
66
+
67
+ createRedirectEndpoint(code, currentLabel, currentLanding)
68
+ }
69
+ }
70
+
71
+ createLandingEndpoint(landing)
72
+ }
73
+
74
+ tape('setup', function (t) {
75
+ s.listen(0, function () {
76
+ ss.listen(0, function () {
77
+ bouncer(301, 'temp')
78
+ bouncer(301, 'double', 2)
79
+ bouncer(301, 'treble', 3)
80
+ bouncer(302, 'perm')
81
+ bouncer(302, 'nope')
82
+ bouncer(307, 'fwd')
83
+ t.end()
84
+ })
85
+ })
86
+ })
87
+
88
+ tape('permanent bounce', function (t) {
89
+ jar.setCookie('quux=baz', s.url)
90
+ hits = {}
91
+ request({
92
+ uri: s.url + '/perm',
93
+ jar: jar,
94
+ headers: { cookie: 'foo=bar' }
95
+ }, function (err, res, body) {
96
+ t.equal(err, null)
97
+ t.equal(res.statusCode, 200)
98
+ t.ok(hits.perm, 'Original request is to /perm')
99
+ t.ok(hits.perm_landing, 'Forward to permanent landing URL')
100
+ t.equal(body, 'GET perm_landing', 'Got permanent landing content')
101
+ t.end()
102
+ })
103
+ })
104
+
105
+ tape('preserve HEAD method when using followAllRedirects', function (t) {
106
+ jar.setCookie('quux=baz', s.url)
107
+ hits = {}
108
+ request({
109
+ method: 'HEAD',
110
+ uri: s.url + '/perm',
111
+ followAllRedirects: true,
112
+ jar: jar,
113
+ headers: { cookie: 'foo=bar' }
114
+ }, function (err, res, body) {
115
+ t.equal(err, null)
116
+ t.equal(res.statusCode, 200)
117
+ t.ok(hits.perm, 'Original request is to /perm')
118
+ t.ok(hits.perm_landing, 'Forward to permanent landing URL')
119
+ t.equal(res.headers['x-response'], 'HEAD perm_landing', 'Got permanent landing content')
120
+ t.end()
121
+ })
122
+ })
123
+
124
+ tape('temporary bounce', function (t) {
125
+ hits = {}
126
+ request({
127
+ uri: s.url + '/temp',
128
+ jar: jar,
129
+ headers: { cookie: 'foo=bar' }
130
+ }, function (err, res, body) {
131
+ t.equal(err, null)
132
+ t.equal(res.statusCode, 200)
133
+ t.ok(hits.temp, 'Original request is to /temp')
134
+ t.ok(hits.temp_landing, 'Forward to temporary landing URL')
135
+ t.equal(body, 'GET temp_landing', 'Got temporary landing content')
136
+ t.end()
137
+ })
138
+ })
139
+
140
+ tape('prevent bouncing', function (t) {
141
+ hits = {}
142
+ request({
143
+ uri: s.url + '/nope',
144
+ jar: jar,
145
+ headers: { cookie: 'foo=bar' },
146
+ followRedirect: false
147
+ }, function (err, res, body) {
148
+ t.equal(err, null)
149
+ t.equal(res.statusCode, 302)
150
+ t.ok(hits.nope, 'Original request to /nope')
151
+ t.ok(!hits.nope_landing, 'No chasing the redirect')
152
+ t.equal(res.statusCode, 302, 'Response is the bounce itself')
153
+ t.end()
154
+ })
155
+ })
156
+
157
+ tape('should not follow post redirects by default', function (t) {
158
+ hits = {}
159
+ request.post(s.url + '/temp', {
160
+ jar: jar,
161
+ headers: { cookie: 'foo=bar' }
162
+ }, function (err, res, body) {
163
+ t.equal(err, null)
164
+ t.equal(res.statusCode, 301)
165
+ t.ok(hits.temp, 'Original request is to /temp')
166
+ t.ok(!hits.temp_landing, 'No chasing the redirect when post')
167
+ t.equal(res.statusCode, 301, 'Response is the bounce itself')
168
+ t.end()
169
+ })
170
+ })
171
+
172
+ tape('should follow post redirects when followallredirects true', function (t) {
173
+ hits = {}
174
+ request.post({
175
+ uri: s.url + '/temp',
176
+ followAllRedirects: true,
177
+ jar: jar,
178
+ headers: { cookie: 'foo=bar' }
179
+ }, function (err, res, body) {
180
+ t.equal(err, null)
181
+ t.equal(res.statusCode, 200)
182
+ t.ok(hits.temp, 'Original request is to /temp')
183
+ t.ok(hits.temp_landing, 'Forward to temporary landing URL')
184
+ t.equal(body, 'GET temp_landing', 'Got temporary landing content')
185
+ t.end()
186
+ })
187
+ })
188
+
189
+ tape('should follow post redirects when followallredirects true and followOriginalHttpMethod is enabled', function (t) {
190
+ hits = {}
191
+ request.post({
192
+ uri: s.url + '/temp',
193
+ followAllRedirects: true,
194
+ followOriginalHttpMethod: true,
195
+ jar: jar,
196
+ headers: { cookie: 'foo=bar' }
197
+ }, function (err, res, body) {
198
+ t.equal(err, null)
199
+ t.equal(res.statusCode, 200)
200
+ t.ok(hits.temp, 'Original request is to /temp')
201
+ t.ok(hits.temp_landing, 'Forward to temporary landing URL')
202
+ t.equal(body, 'POST temp_landing', 'Got temporary landing content')
203
+ t.end()
204
+ })
205
+ })
206
+
207
+ tape('should not follow post redirects when followallredirects false', function (t) {
208
+ hits = {}
209
+ request.post({
210
+ uri: s.url + '/temp',
211
+ followAllRedirects: false,
212
+ jar: jar,
213
+ headers: { cookie: 'foo=bar' }
214
+ }, function (err, res, body) {
215
+ t.equal(err, null)
216
+ t.equal(res.statusCode, 301)
217
+ t.ok(hits.temp, 'Original request is to /temp')
218
+ t.ok(!hits.temp_landing, 'No chasing the redirect')
219
+ t.equal(res.statusCode, 301, 'Response is the bounce itself')
220
+ t.end()
221
+ })
222
+ })
223
+
224
+ tape('should not follow delete redirects by default', function (t) {
225
+ hits = {}
226
+ request.del(s.url + '/temp', {
227
+ jar: jar,
228
+ headers: { cookie: 'foo=bar' }
229
+ }, function (err, res, body) {
230
+ t.equal(err, null)
231
+ t.ok(res.statusCode >= 301 && res.statusCode < 400, 'Status is a redirect')
232
+ t.ok(hits.temp, 'Original request is to /temp')
233
+ t.ok(!hits.temp_landing, 'No chasing the redirect when delete')
234
+ t.equal(res.statusCode, 301, 'Response is the bounce itself')
235
+ t.end()
236
+ })
237
+ })
238
+
239
+ tape('should not follow delete redirects even if followredirect is set to true', function (t) {
240
+ hits = {}
241
+ request.del(s.url + '/temp', {
242
+ followRedirect: true,
243
+ jar: jar,
244
+ headers: { cookie: 'foo=bar' }
245
+ }, function (err, res, body) {
246
+ t.equal(err, null)
247
+ t.equal(res.statusCode, 301)
248
+ t.ok(hits.temp, 'Original request is to /temp')
249
+ t.ok(!hits.temp_landing, 'No chasing the redirect when delete')
250
+ t.equal(res.statusCode, 301, 'Response is the bounce itself')
251
+ t.end()
252
+ })
253
+ })
254
+
255
+ tape('should follow delete redirects when followallredirects true', function (t) {
256
+ hits = {}
257
+ request.del(s.url + '/temp', {
258
+ followAllRedirects: true,
259
+ jar: jar,
260
+ headers: { cookie: 'foo=bar' }
261
+ }, function (err, res, body) {
262
+ t.equal(err, null)
263
+ t.equal(res.statusCode, 200)
264
+ t.ok(hits.temp, 'Original request is to /temp')
265
+ t.ok(hits.temp_landing, 'Forward to temporary landing URL')
266
+ t.equal(body, 'GET temp_landing', 'Got temporary landing content')
267
+ t.end()
268
+ })
269
+ })
270
+
271
+ tape('should follow 307 delete redirects when followallredirects true', function (t) {
272
+ hits = {}
273
+ request.del(s.url + '/fwd', {
274
+ followAllRedirects: true,
275
+ jar: jar,
276
+ headers: { cookie: 'foo=bar' }
277
+ }, function (err, res, body) {
278
+ t.equal(err, null)
279
+ t.equal(res.statusCode, 200)
280
+ t.ok(hits.fwd, 'Original request is to /fwd')
281
+ t.ok(hits.fwd_landing, 'Forward to temporary landing URL')
282
+ t.equal(body, 'DELETE fwd_landing', 'Got temporary landing content')
283
+ t.end()
284
+ })
285
+ })
286
+
287
+ tape('double bounce', function (t) {
288
+ hits = {}
289
+ request({
290
+ uri: s.url + '/double',
291
+ jar: jar,
292
+ headers: { cookie: 'foo=bar' }
293
+ }, function (err, res, body) {
294
+ t.equal(err, null)
295
+ t.equal(res.statusCode, 200)
296
+ t.ok(hits.double, 'Original request is to /double')
297
+ t.ok(hits.double_2, 'Forward to temporary landing URL')
298
+ t.ok(hits.double_landing, 'Forward to landing URL')
299
+ t.equal(body, 'GET double_landing', 'Got temporary landing content')
300
+ t.end()
301
+ })
302
+ })
303
+
304
+ tape('double bounce terminated after first redirect', function (t) {
305
+ function filterDouble (response) {
306
+ return (response.headers.location || '').indexOf('double_2') === -1
307
+ }
308
+
309
+ hits = {}
310
+ request({
311
+ uri: s.url + '/double',
312
+ jar: jar,
313
+ headers: { cookie: 'foo=bar' },
314
+ followRedirect: filterDouble
315
+ }, function (err, res, body) {
316
+ t.equal(err, null)
317
+ t.equal(res.statusCode, 301)
318
+ t.ok(hits.double, 'Original request is to /double')
319
+ t.equal(res.headers.location, s.url + '/double_2', 'Current location should be ' + s.url + '/double_2')
320
+ t.end()
321
+ })
322
+ })
323
+
324
+ tape('triple bounce terminated after second redirect', function (t) {
325
+ function filterTreble (response) {
326
+ return (response.headers.location || '').indexOf('treble_3') === -1
327
+ }
328
+
329
+ hits = {}
330
+ request({
331
+ uri: s.url + '/treble',
332
+ jar: jar,
333
+ headers: { cookie: 'foo=bar' },
334
+ followRedirect: filterTreble
335
+ }, function (err, res, body) {
336
+ t.equal(err, null)
337
+ t.equal(res.statusCode, 301)
338
+ t.ok(hits.treble, 'Original request is to /treble')
339
+ t.equal(res.headers.location, s.url + '/treble_3', 'Current location should be ' + s.url + '/treble_3')
340
+ t.end()
341
+ })
342
+ })
343
+
344
+ tape('http to https redirect', function (t) {
345
+ hits = {}
346
+ request.get({
347
+ uri: require('url').parse(s.url + '/ssl'),
348
+ rejectUnauthorized: false
349
+ }, function (err, res, body) {
350
+ t.equal(err, null)
351
+ t.equal(res.statusCode, 200)
352
+ t.equal(body, 'SSL', 'Got SSL redirect')
353
+ t.end()
354
+ })
355
+ })
356
+
357
+ tape('should have referer header by default when following redirect', function (t) {
358
+ request.post({
359
+ uri: s.url + '/temp',
360
+ jar: jar,
361
+ followAllRedirects: true,
362
+ headers: { cookie: 'foo=bar' }
363
+ }, function (err, res, body) {
364
+ t.equal(err, null)
365
+ t.equal(res.statusCode, 200)
366
+ t.end()
367
+ })
368
+ .on('redirect', function () {
369
+ t.equal(this.headers.referer, s.url + '/temp')
370
+ })
371
+ })
372
+
373
+ tape('should not have referer header when removeRefererHeader is true', function (t) {
374
+ request.post({
375
+ uri: s.url + '/temp',
376
+ jar: jar,
377
+ followAllRedirects: true,
378
+ removeRefererHeader: true,
379
+ headers: { cookie: 'foo=bar' }
380
+ }, function (err, res, body) {
381
+ t.equal(err, null)
382
+ t.equal(res.statusCode, 200)
383
+ t.end()
384
+ })
385
+ .on('redirect', function () {
386
+ t.equal(this.headers.referer, undefined)
387
+ })
388
+ })
389
+
390
+ tape('should preserve referer header set in the initial request when removeRefererHeader is true', function (t) {
391
+ request.post({
392
+ uri: s.url + '/temp',
393
+ jar: jar,
394
+ followAllRedirects: true,
395
+ removeRefererHeader: true,
396
+ headers: { cookie: 'foo=bar', referer: 'http://awesome.com' }
397
+ }, function (err, res, body) {
398
+ t.equal(err, null)
399
+ t.equal(res.statusCode, 200)
400
+ t.end()
401
+ })
402
+ .on('redirect', function () {
403
+ t.equal(this.headers.referer, 'http://awesome.com')
404
+ })
405
+ })
406
+
407
+ tape('should use same agent class on redirect', function (t) {
408
+ var agent
409
+ var calls = 0
410
+ var agentOptions = {}
411
+
412
+ function FakeAgent (agentOptions) {
413
+ var createConnection
414
+
415
+ agent = new http.Agent(agentOptions)
416
+ createConnection = agent.createConnection
417
+ agent.createConnection = function () {
418
+ calls++
419
+ return createConnection.apply(agent, arguments)
420
+ }
421
+
422
+ return agent
423
+ }
424
+
425
+ hits = {}
426
+ request.get({
427
+ uri: s.url + '/temp',
428
+ jar: jar,
429
+ headers: { cookie: 'foo=bar' },
430
+ agentOptions: agentOptions,
431
+ agentClass: FakeAgent
432
+ }, function (err, res, body) {
433
+ t.equal(err, null)
434
+ t.equal(res.statusCode, 200)
435
+ t.equal(body, 'GET temp_landing', 'Got temporary landing content')
436
+ t.equal(calls, 2)
437
+ t.ok(this.agent === agent, 'Reinstantiated the user-specified agent')
438
+ t.ok(this.agentOptions === agentOptions, 'Reused agent options')
439
+ t.end()
440
+ })
441
+ })
442
+
443
+ tape('cleanup', function (t) {
444
+ s.destroy(function () {
445
+ ss.destroy(function () {
446
+ t.end()
447
+ })
448
+ })
449
+ })