Skip to content

Commit fcaa6f3

Browse files
committed
Merge pull request #55 from github/test-redirect
Test Atomic HTTP redirect handling
2 parents 9b1ddc9 + 2c61395 commit fcaa6f3

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

README.md

+17
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,23 @@ fetch('/users')
162162
})
163163
```
164164

165+
### Response URL caveat
166+
167+
The `Response` object has a URL attribute for the final responded resource.
168+
Usually this is the same as the `Request` url, but in the case of a redirect,
169+
its all transparent. Newer versions of XHR include a `responseURL` attribute
170+
that returns this value. But not every browser supports this. The compromise
171+
requires setting a special server side header to tell the browser what URL it
172+
just requested (yeah, I know browsers).
173+
174+
``` ruby
175+
response.headers['X-Request-URL'] = request.url
176+
```
177+
178+
If you want `response.url` to be reliable, you'll want to set this header. The
179+
day that you ditch this polyfill and use native fetch only, you can remove the
180+
header hack.
181+
165182
## Browser Support
166183

167184
![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png)

fetch.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@
180180
var options = {
181181
status: status,
182182
statusText: xhr.statusText,
183-
headers: headers(xhr)
183+
headers: headers(xhr),
184+
url: xhr.responseURL || xhr.getResponseHeader('X-Request-URL')
184185
}
185186
resolve(new Response(xhr.responseText, options))
186187
}
@@ -210,6 +211,7 @@
210211
this.status = options.status
211212
this.statusText = options.statusText
212213
this.headers = options.headers
214+
this.url = options.url || ''
213215
}
214216

215217
Body.call(Response.prototype)

test/server.js

+25-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,33 @@ var routes = {
2020
}));
2121
})
2222
},
23-
'/hello': function(res) {
24-
res.writeHead(200, {'Content-Type': 'text/plain'});
23+
'/hello': function(res, req) {
24+
res.writeHead(200, {
25+
'Content-Type': 'text/plain',
26+
'X-Request-URL': 'http://' + req.headers.host + req.url
27+
});
2528
res.end('hi');
2629
},
30+
'/redirect/301': function(res) {
31+
res.writeHead(301, {'Location': '/hello'});
32+
res.end();
33+
},
34+
'/redirect/302': function(res) {
35+
res.writeHead(302, {'Location': '/hello'});
36+
res.end();
37+
},
38+
'/redirect/303': function(res) {
39+
res.writeHead(303, {'Location': '/hello'});
40+
res.end();
41+
},
42+
'/redirect/307': function(res) {
43+
res.writeHead(307, {'Location': '/hello'});
44+
res.end();
45+
},
46+
'/redirect/308': function(res) {
47+
res.writeHead(308, {'Location': '/hello'});
48+
res.end();
49+
},
2750
'/boom': function(res) {
2851
res.writeHead(500, {'Content-Type': 'text/plain'});
2952
res.end('boom');

test/test.js

+53
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,56 @@ promiseTest('supports HTTP DELETE', 2, function() {
196196
equal(request.data, '')
197197
})
198198
})
199+
200+
promiseTest('handles 301 redirect response', 3, function() {
201+
return fetch('/redirect/301').then(function(response) {
202+
equal(response.status, 200)
203+
equal(response.url ? new URL(response.url).pathname : null, '/hello')
204+
return response.text()
205+
}).then(function(body) {
206+
equal(body, 'hi')
207+
})
208+
})
209+
210+
promiseTest('handles 302 redirect response', 3, function() {
211+
return fetch('/redirect/302').then(function(response) {
212+
equal(response.status, 200)
213+
equal(response.url ? new URL(response.url).pathname : null, '/hello')
214+
return response.text()
215+
}).then(function(body) {
216+
equal(body, 'hi')
217+
})
218+
})
219+
220+
promiseTest('handles 303 redirect response', 3, function() {
221+
return fetch('/redirect/303').then(function(response) {
222+
equal(response.status, 200)
223+
equal(response.url ? new URL(response.url).pathname : null, '/hello')
224+
return response.text()
225+
}).then(function(body) {
226+
equal(body, 'hi')
227+
})
228+
})
229+
230+
promiseTest('handles 307 redirect response', 3, function() {
231+
return fetch('/redirect/307').then(function(response) {
232+
equal(response.status, 200)
233+
equal(response.url ? new URL(response.url).pathname : null, '/hello')
234+
return response.text()
235+
}).then(function(body) {
236+
equal(body, 'hi')
237+
})
238+
})
239+
240+
// PhantomJS doesn't support 308 redirects
241+
if (!navigator.userAgent.match(/PhantomJS/)) {
242+
promiseTest('handles 308 redirect response', 3, function() {
243+
return fetch('/redirect/308').then(function(response) {
244+
equal(response.status, 200)
245+
equal(response.url ? new URL(response.url).pathname : null, '/hello')
246+
return response.text()
247+
}).then(function(body) {
248+
equal(body, 'hi')
249+
})
250+
})
251+
}

0 commit comments

Comments
 (0)