Skip to content

Commit 46fc153

Browse files
committed
fix(http): return URL in Response
Attach reponseURL or X-Request-URL to Response. Closes #5165
1 parent 4332ccf commit 46fc153

File tree

4 files changed

+54
-4
lines changed

4 files changed

+54
-4
lines changed

modules/angular2/src/http/backends/jsonp_backend.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ export class JSONPConnection_ extends JSONPConnection {
5757
_dom.cleanup(script);
5858
if (!this._finished) {
5959
let responseOptions =
60-
new ResponseOptions({body: JSONP_ERR_NO_CALLBACK, type: ResponseTypes.Error});
60+
new ResponseOptions({body: JSONP_ERR_NO_CALLBACK, type: ResponseTypes.Error, url});
6161
if (isPresent(baseResponseOptions)) {
6262
responseOptions = baseResponseOptions.merge(responseOptions);
6363
}
6464
responseObserver.error(new Response(responseOptions));
6565
return;
6666
}
6767

68-
let responseOptions = new ResponseOptions({body: this._responseData});
68+
let responseOptions = new ResponseOptions({body: this._responseData, url});
6969
if (isPresent(this.baseResponseOptions)) {
7070
responseOptions = this.baseResponseOptions.merge(responseOptions);
7171
}

modules/angular2/src/http/backends/xhr_backend.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {Injectable} from 'angular2/angular2';
88
import {BrowserXhr} from './browser_xhr';
99
import {isPresent} from 'angular2/src/facade/lang';
1010
import {Observable} from 'angular2/angular2';
11-
import {isSuccess} from '../http_utils';
11+
import {isSuccess, getResponseURL} from '../http_utils';
1212
/**
1313
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
1414
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
@@ -39,6 +39,8 @@ export class XHRConnection implements Connection {
3939

4040
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
4141

42+
let url = getResponseURL(_xhr);
43+
4244
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
4345
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
4446

@@ -48,7 +50,7 @@ export class XHRConnection implements Connection {
4850
if (status === 0) {
4951
status = body ? 200 : 0;
5052
}
51-
var responseOptions = new ResponseOptions({body, status, headers});
53+
var responseOptions = new ResponseOptions({body, status, headers, url});
5254
if (isPresent(baseResponseOptions)) {
5355
responseOptions = baseResponseOptions.merge(responseOptions);
5456
}

modules/angular2/src/http/http_utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,14 @@ export function normalizeMethodName(method): RequestMethods {
1717

1818
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);
1919

20+
export function getResponseURL(xhr: any): string {
21+
if ('responseURL' in xhr) {
22+
return xhr.responseURL;
23+
}
24+
if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
25+
return xhr.getResponseHeader('X-Request-URL');
26+
}
27+
return;
28+
}
29+
2030
export {isJsObject} from 'angular2/src/facade/lang';

modules/angular2/test/http/backends/xhr_backend_spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class MockBrowserXHR extends BrowserXhr {
4141
callbacks = new Map<string, Function>();
4242
status: number;
4343
responseHeaders: string;
44+
responseURL: string;
4445
constructor() {
4546
super();
4647
var spy = new SpyObject();
@@ -56,10 +57,14 @@ class MockBrowserXHR extends BrowserXhr {
5657

5758
setResponseText(value) { this.responseText = value; }
5859

60+
setResponseURL(value) { this.responseURL = value; }
61+
5962
setResponseHeaders(value) { this.responseHeaders = value; }
6063

6164
getAllResponseHeaders() { return this.responseHeaders || ''; }
6265

66+
getResponseHeader(key) { return Headers.fromResponseHeaderString(this.responseHeaders).get(key); }
67+
6368
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
6469

6570
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
@@ -285,6 +290,39 @@ export function main() {
285290
existingXHRs[0].setStatusCode(statusCode);
286291
existingXHRs[0].dispatchEvent('load');
287292
}));
293+
294+
it('should add the responseURL to the response', inject([AsyncTestCompleter], async => {
295+
var statusCode = 200;
296+
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
297+
new ResponseOptions({status: statusCode}));
298+
299+
connection.response.subscribe(res => {
300+
expect(res.url).toEqual('http://google.com');
301+
async.done();
302+
});
303+
304+
existingXHRs[0].setResponseURL('http://google.com');
305+
existingXHRs[0].setStatusCode(statusCode);
306+
existingXHRs[0].dispatchEvent('load');
307+
}));
308+
309+
it('should add use the X-Request-URL in CORS situations',
310+
inject([AsyncTestCompleter], async => {
311+
var statusCode = 200;
312+
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
313+
new ResponseOptions({status: statusCode}));
314+
var responseHeaders = `X-Request-URL: http://somedomain.com
315+
Foo: Bar`
316+
317+
connection.response.subscribe(res => {
318+
expect(res.url).toEqual('http://somedomain.com');
319+
async.done();
320+
});
321+
322+
existingXHRs[0].setResponseHeaders(responseHeaders);
323+
existingXHRs[0].setStatusCode(statusCode);
324+
existingXHRs[0].dispatchEvent('load');
325+
}));
288326
});
289327
});
290328
}

0 commit comments

Comments
 (0)