2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
import {StringWrapper, isPresent} from '../src/facade/lang';
|
|
|
|
|
2016-05-26 18:47:20 -04:00
|
|
|
import {Body} from './body';
|
|
|
|
import {ContentType, RequestMethod, ResponseContentType} from './enums';
|
2015-04-29 02:07:55 -04:00
|
|
|
import {Headers} from './headers';
|
2015-09-21 03:46:16 -04:00
|
|
|
import {normalizeMethodName} from './http_utils';
|
2016-06-08 19:38:52 -04:00
|
|
|
import {RequestArgs} from './interfaces';
|
|
|
|
import {URLSearchParams} from './url_search_params';
|
|
|
|
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2015-06-09 18:18:57 -04:00
|
|
|
// TODO(jeffbcross): properly implement body accessors
|
|
|
|
/**
|
2015-06-24 03:27:07 -04:00
|
|
|
* Creates `Request` instances from provided values.
|
2015-06-09 18:18:57 -04:00
|
|
|
*
|
|
|
|
* The Request's interface is inspired by the Request constructor defined in the [Fetch
|
|
|
|
* Spec](https://fetch.spec.whatwg.org/#request-class),
|
|
|
|
* but is considered a static value whose body can be accessed many times. There are other
|
|
|
|
* differences in the implementation, but this is the most significant.
|
2015-09-17 19:35:49 -04:00
|
|
|
*
|
|
|
|
* `Request` instances are typically created by higher-level classes, like {@link Http} and
|
|
|
|
* {@link Jsonp}, but it may occasionally be useful to explicitly create `Request` instances.
|
|
|
|
* One such example is when creating services that wrap higher-level services, like {@link Http},
|
|
|
|
* where it may be useful to generate a `Request` with arbitrary headers and search params.
|
|
|
|
*
|
2015-09-24 04:32:43 -04:00
|
|
|
* ```typescript
|
2016-04-28 20:50:03 -04:00
|
|
|
* import {Injectable, Injector} from '@angular/core';
|
|
|
|
* import {HTTP_PROVIDERS, Http, Request, RequestMethod} from '@angular/http';
|
2015-09-17 19:35:49 -04:00
|
|
|
*
|
|
|
|
* @Injectable()
|
|
|
|
* class AutoAuthenticator {
|
|
|
|
* constructor(public http:Http) {}
|
|
|
|
* request(url:string) {
|
|
|
|
* return this.http.request(new Request({
|
2015-12-03 16:44:14 -05:00
|
|
|
* method: RequestMethod.Get,
|
2015-09-17 19:35:49 -04:00
|
|
|
* url: url,
|
|
|
|
* search: 'password=123'
|
|
|
|
* }));
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
2015-10-11 01:11:13 -04:00
|
|
|
* var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, AutoAuthenticator]);
|
2015-09-17 19:35:49 -04:00
|
|
|
* var authenticator = injector.get(AutoAuthenticator);
|
2015-10-07 06:41:27 -04:00
|
|
|
* authenticator.request('people.json').subscribe(res => {
|
2015-09-17 19:35:49 -04:00
|
|
|
* //URL should have included '?password=123'
|
|
|
|
* console.log('people', res.json());
|
|
|
|
* });
|
|
|
|
* ```
|
2016-06-27 15:27:23 -04:00
|
|
|
*
|
|
|
|
* @experimental
|
2015-06-09 18:18:57 -04:00
|
|
|
*/
|
2016-05-26 18:47:20 -04:00
|
|
|
export class Request extends Body {
|
2015-06-09 18:18:57 -04:00
|
|
|
/**
|
|
|
|
* Http method with which to perform the request.
|
|
|
|
*/
|
2015-12-03 16:44:14 -05:00
|
|
|
method: RequestMethod;
|
2015-06-09 18:18:57 -04:00
|
|
|
/**
|
2015-09-17 19:35:49 -04:00
|
|
|
* {@link Headers} instance
|
2015-04-29 02:07:55 -04:00
|
|
|
*/
|
2015-06-09 18:18:57 -04:00
|
|
|
headers: Headers;
|
2015-06-19 15:14:12 -04:00
|
|
|
/** Url of the remote resource */
|
|
|
|
url: string;
|
2016-02-26 06:25:55 -05:00
|
|
|
/** Type of the request body **/
|
|
|
|
private contentType: ContentType;
|
2016-02-24 16:57:35 -05:00
|
|
|
/** Enable use credentials */
|
|
|
|
withCredentials: boolean;
|
2016-05-26 18:47:20 -04:00
|
|
|
/** Buffer to store the response */
|
|
|
|
responseType: ResponseContentType;
|
2015-10-10 12:37:29 -04:00
|
|
|
constructor(requestOptions: RequestArgs) {
|
2016-05-26 18:47:20 -04:00
|
|
|
super();
|
2015-06-24 03:27:07 -04:00
|
|
|
// TODO: assert that url is present
|
2015-07-13 14:47:10 -04:00
|
|
|
let url = requestOptions.url;
|
2015-06-19 15:14:12 -04:00
|
|
|
this.url = requestOptions.url;
|
2015-07-13 14:47:10 -04:00
|
|
|
if (isPresent(requestOptions.search)) {
|
|
|
|
let search = requestOptions.search.toString();
|
|
|
|
if (search.length > 0) {
|
|
|
|
let prefix = '?';
|
|
|
|
if (StringWrapper.contains(this.url, '?')) {
|
|
|
|
prefix = (this.url[this.url.length - 1] == '&') ? '' : '&';
|
|
|
|
}
|
|
|
|
// TODO: just delete search-query-looking string in url?
|
|
|
|
this.url = url + prefix + search;
|
|
|
|
}
|
|
|
|
}
|
2015-06-19 15:14:12 -04:00
|
|
|
this._body = requestOptions.body;
|
2015-09-21 03:46:16 -04:00
|
|
|
this.method = normalizeMethodName(requestOptions.method);
|
2015-04-29 02:07:55 -04:00
|
|
|
// TODO(jeffbcross): implement behavior
|
|
|
|
// Defaults to 'omit', consistent with browser
|
|
|
|
// TODO(jeffbcross): implement behavior
|
2015-06-24 03:27:07 -04:00
|
|
|
this.headers = new Headers(requestOptions.headers);
|
2016-07-22 11:37:32 -04:00
|
|
|
this.contentType = this.detectContentType();
|
2016-02-24 16:57:35 -05:00
|
|
|
this.withCredentials = requestOptions.withCredentials;
|
2016-05-26 18:47:20 -04:00
|
|
|
this.responseType = requestOptions.responseType;
|
2016-02-26 06:25:55 -05:00
|
|
|
}
|
|
|
|
|
2016-07-22 11:37:32 -04:00
|
|
|
/**
|
|
|
|
* Returns the content type enum based on header options.
|
|
|
|
*/
|
|
|
|
detectContentType(): ContentType {
|
|
|
|
switch (this.headers.get('content-type')) {
|
|
|
|
case 'application/json':
|
|
|
|
return ContentType.JSON;
|
|
|
|
case 'application/x-www-form-urlencoded':
|
|
|
|
return ContentType.FORM;
|
|
|
|
case 'multipart/form-data':
|
|
|
|
return ContentType.FORM_DATA;
|
|
|
|
case 'text/plain':
|
|
|
|
case 'text/html':
|
|
|
|
return ContentType.TEXT;
|
|
|
|
case 'application/octet-stream':
|
|
|
|
return ContentType.BLOB;
|
|
|
|
default:
|
|
|
|
return this.detectContentTypeFromBody();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-26 06:25:55 -05:00
|
|
|
/**
|
|
|
|
* Returns the content type of request's body based on its type.
|
|
|
|
*/
|
2016-07-22 11:37:32 -04:00
|
|
|
detectContentTypeFromBody(): ContentType {
|
2016-02-26 06:25:55 -05:00
|
|
|
if (this._body == null) {
|
|
|
|
return ContentType.NONE;
|
|
|
|
} else if (this._body instanceof URLSearchParams) {
|
|
|
|
return ContentType.FORM;
|
|
|
|
} else if (this._body instanceof FormData) {
|
|
|
|
return ContentType.FORM_DATA;
|
|
|
|
} else if (this._body instanceof Blob) {
|
|
|
|
return ContentType.BLOB;
|
|
|
|
} else if (this._body instanceof ArrayBuffer) {
|
|
|
|
return ContentType.ARRAY_BUFFER;
|
|
|
|
} else if (this._body && typeof this._body == 'object') {
|
|
|
|
return ContentType.JSON;
|
|
|
|
} else {
|
|
|
|
return ContentType.TEXT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the request's body according to its type. If body is undefined, return
|
|
|
|
* null.
|
|
|
|
*/
|
|
|
|
getBody(): any {
|
|
|
|
switch (this.contentType) {
|
|
|
|
case ContentType.JSON:
|
2016-07-18 17:20:03 -04:00
|
|
|
return this.text();
|
2016-02-26 06:25:55 -05:00
|
|
|
case ContentType.FORM:
|
|
|
|
return this.text();
|
|
|
|
case ContentType.FORM_DATA:
|
|
|
|
return this._body;
|
|
|
|
case ContentType.TEXT:
|
|
|
|
return this.text();
|
|
|
|
case ContentType.BLOB:
|
|
|
|
return this.blob();
|
|
|
|
case ContentType.ARRAY_BUFFER:
|
|
|
|
return this.arrayBuffer();
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2015-04-29 02:07:55 -04:00
|
|
|
}
|
2016-02-26 06:25:55 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
const noop = function() {};
|
2016-02-26 06:25:55 -05:00
|
|
|
const w = typeof window == 'object' ? window : noop;
|
2016-06-08 18:45:15 -04:00
|
|
|
const FormData = (w as any /** TODO #9100 */)['FormData'] || noop;
|
|
|
|
const Blob = (w as any /** TODO #9100 */)['Blob'] || noop;
|
|
|
|
const ArrayBuffer = (w as any /** TODO #9100 */)['ArrayBuffer'] || noop;
|