fix(http): return URL in Response
Attach reponseURL or X-Request-URL to Response. Closes #5165
This commit is contained in:
parent
4332ccf72c
commit
46fc153f39
|
@ -57,7 +57,7 @@ export class JSONPConnection_ extends JSONPConnection {
|
||||||
_dom.cleanup(script);
|
_dom.cleanup(script);
|
||||||
if (!this._finished) {
|
if (!this._finished) {
|
||||||
let responseOptions =
|
let responseOptions =
|
||||||
new ResponseOptions({body: JSONP_ERR_NO_CALLBACK, type: ResponseTypes.Error});
|
new ResponseOptions({body: JSONP_ERR_NO_CALLBACK, type: ResponseTypes.Error, url});
|
||||||
if (isPresent(baseResponseOptions)) {
|
if (isPresent(baseResponseOptions)) {
|
||||||
responseOptions = baseResponseOptions.merge(responseOptions);
|
responseOptions = baseResponseOptions.merge(responseOptions);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ export class JSONPConnection_ extends JSONPConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let responseOptions = new ResponseOptions({body: this._responseData});
|
let responseOptions = new ResponseOptions({body: this._responseData, url});
|
||||||
if (isPresent(this.baseResponseOptions)) {
|
if (isPresent(this.baseResponseOptions)) {
|
||||||
responseOptions = this.baseResponseOptions.merge(responseOptions);
|
responseOptions = this.baseResponseOptions.merge(responseOptions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {Injectable} from 'angular2/angular2';
|
||||||
import {BrowserXhr} from './browser_xhr';
|
import {BrowserXhr} from './browser_xhr';
|
||||||
import {isPresent} from 'angular2/src/facade/lang';
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
import {Observable} from 'angular2/angular2';
|
import {Observable} from 'angular2/angular2';
|
||||||
import {isSuccess} from '../http_utils';
|
import {isSuccess, getResponseURL} from '../http_utils';
|
||||||
/**
|
/**
|
||||||
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
||||||
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
|
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
|
||||||
|
@ -39,6 +39,8 @@ export class XHRConnection implements Connection {
|
||||||
|
|
||||||
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
||||||
|
|
||||||
|
let url = getResponseURL(_xhr);
|
||||||
|
|
||||||
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
||||||
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
|
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ export class XHRConnection implements Connection {
|
||||||
if (status === 0) {
|
if (status === 0) {
|
||||||
status = body ? 200 : 0;
|
status = body ? 200 : 0;
|
||||||
}
|
}
|
||||||
var responseOptions = new ResponseOptions({body, status, headers});
|
var responseOptions = new ResponseOptions({body, status, headers, url});
|
||||||
if (isPresent(baseResponseOptions)) {
|
if (isPresent(baseResponseOptions)) {
|
||||||
responseOptions = baseResponseOptions.merge(responseOptions);
|
responseOptions = baseResponseOptions.merge(responseOptions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,14 @@ export function normalizeMethodName(method): RequestMethods {
|
||||||
|
|
||||||
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);
|
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);
|
||||||
|
|
||||||
|
export function getResponseURL(xhr: any): string {
|
||||||
|
if ('responseURL' in xhr) {
|
||||||
|
return xhr.responseURL;
|
||||||
|
}
|
||||||
|
if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
|
||||||
|
return xhr.getResponseHeader('X-Request-URL');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
export {isJsObject} from 'angular2/src/facade/lang';
|
export {isJsObject} from 'angular2/src/facade/lang';
|
||||||
|
|
|
@ -41,6 +41,7 @@ class MockBrowserXHR extends BrowserXhr {
|
||||||
callbacks = new Map<string, Function>();
|
callbacks = new Map<string, Function>();
|
||||||
status: number;
|
status: number;
|
||||||
responseHeaders: string;
|
responseHeaders: string;
|
||||||
|
responseURL: string;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
var spy = new SpyObject();
|
var spy = new SpyObject();
|
||||||
|
@ -56,10 +57,14 @@ class MockBrowserXHR extends BrowserXhr {
|
||||||
|
|
||||||
setResponseText(value) { this.responseText = value; }
|
setResponseText(value) { this.responseText = value; }
|
||||||
|
|
||||||
|
setResponseURL(value) { this.responseURL = value; }
|
||||||
|
|
||||||
setResponseHeaders(value) { this.responseHeaders = value; }
|
setResponseHeaders(value) { this.responseHeaders = value; }
|
||||||
|
|
||||||
getAllResponseHeaders() { return this.responseHeaders || ''; }
|
getAllResponseHeaders() { return this.responseHeaders || ''; }
|
||||||
|
|
||||||
|
getResponseHeader(key) { return Headers.fromResponseHeaderString(this.responseHeaders).get(key); }
|
||||||
|
|
||||||
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
|
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
|
||||||
|
|
||||||
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
|
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
|
||||||
|
@ -285,6 +290,39 @@ export function main() {
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
existingXHRs[0].dispatchEvent('load');
|
existingXHRs[0].dispatchEvent('load');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should add the responseURL to the response', inject([AsyncTestCompleter], async => {
|
||||||
|
var statusCode = 200;
|
||||||
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
|
||||||
|
new ResponseOptions({status: statusCode}));
|
||||||
|
|
||||||
|
connection.response.subscribe(res => {
|
||||||
|
expect(res.url).toEqual('http://google.com');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
existingXHRs[0].setResponseURL('http://google.com');
|
||||||
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
|
existingXHRs[0].dispatchEvent('load');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should add use the X-Request-URL in CORS situations',
|
||||||
|
inject([AsyncTestCompleter], async => {
|
||||||
|
var statusCode = 200;
|
||||||
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
|
||||||
|
new ResponseOptions({status: statusCode}));
|
||||||
|
var responseHeaders = `X-Request-URL: http://somedomain.com
|
||||||
|
Foo: Bar`
|
||||||
|
|
||||||
|
connection.response.subscribe(res => {
|
||||||
|
expect(res.url).toEqual('http://somedomain.com');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
existingXHRs[0].setResponseHeaders(responseHeaders);
|
||||||
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
|
existingXHRs[0].dispatchEvent('load');
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue