diff --git a/packages/platform-server/src/http.ts b/packages/platform-server/src/http.ts index 1cd67c7d45..49b07490de 100644 --- a/packages/platform-server/src/http.ts +++ b/packages/platform-server/src/http.ts @@ -15,6 +15,14 @@ import {Observable} from 'rxjs/Observable'; import {Observer} from 'rxjs/Observer'; import {Subscription} from 'rxjs/Subscription'; +const isAbsoluteUrl = /^[a-zA-Z\-\+.]+:\/\//; + +function validateRequestUrl(url: string): void { + if (!isAbsoluteUrl.test(url)) { + throw new Error(`URLs requested via Http on the server must be absolute. URL: ${url}`); + } +} + @Injectable() export class ServerXhr implements BrowserXhr { build(): XMLHttpRequest { return new xhr2.XMLHttpRequest(); } @@ -30,6 +38,7 @@ export class ZoneMacroTaskConnection implements Connection { lastConnection: Connection; constructor(public request: Request, backend: XHRBackend) { + validateRequestUrl(request.url); this.response = new Observable((observer: Observer) => { let task: Task = null; let scheduled: boolean = false; diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index 4ea5b4f925..1bf08703b4 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -426,10 +426,10 @@ export function main() { NgZone.assertInAngularZone(); mock.connections.subscribe((mc: MockConnection) => { NgZone.assertInAngularZone(); - expect(mc.request.url).toBe('/testing'); + expect(mc.request.url).toBe('http://localhost/testing'); mc.mockRespond(new Response(new ResponseOptions({body: 'success!', status: 200}))); }); - http.get('/testing').subscribe(resp => { + http.get('http://localhost/testing').subscribe(resp => { NgZone.assertInAngularZone(); expect(resp.text()).toBe('success!'); }); @@ -449,7 +449,9 @@ export function main() { expect(ref.injector.get(NgZone).hasPendingMacrotasks).toBeTruthy(); mc.mockRespond(new Response(new ResponseOptions({body: 'success!', status: 200}))); }); - http.get('/testing').subscribe(resp => { expect(resp.text()).toBe('success!'); }); + http.get('http://localhost/testing').subscribe(resp => { + expect(resp.text()).toBe('success!'); + }); }); }); })); @@ -466,7 +468,9 @@ export function main() { expect(ref.injector.get(NgZone).hasPendingMacrotasks).toBeTruthy(); mc.mockRespond(new Response(new ResponseOptions({body: 'success!', status: 200}))); }); - http.get('/testing').subscribe(resp => { expect(resp.text()).toBe('success!'); }); + http.get('http://localhost/testing').subscribe(resp => { + expect(resp.text()).toBe('success!'); + }); }); }); })); @@ -483,10 +487,22 @@ export function main() { expect(ref.injector.get(NgZone).hasPendingMacrotasks).toBeTruthy(); mc.mockRespond(new Response(new ResponseOptions({body: 'success!', status: 200}))); }); - http.get('/testing').subscribe(resp => { expect(resp.text()).toBe('success!'); }); + http.get('http://localhost/testing').subscribe(resp => { + expect(resp.text()).toBe('success!'); + }); }); }); })); + it('throws when given a relative URL', async(() => { + const platform = platformDynamicServer( + [{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + platform.bootstrapModule(ExampleModule).then(ref => { + const http = ref.injector.get(Http); + expect(() => http.get('/testing')) + .toThrowError( + 'URLs requested via Http on the server must be absolute. URL: /testing'); + }); + })); }); }); }