UNPKG

@angular/http

Version:
1,562 lines (1,548 loc) 71.4 kB
/** * @license Angular v7.2.16 * (c) 2010-2019 Google LLC. https://angular.io/ * License: MIT */ import { Injectable, NgModule, Version } from '@angular/core'; import { Observable } from 'rxjs'; import { ɵgetDOM } from '@angular/platform-browser'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * A backend for http that uses the `XMLHttpRequest` browser API. * * Take care not to evaluate this in non-browser contexts. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class BrowserXhr { constructor() { } /** * @return {?} */ build() { return (/** @type {?} */ ((new XMLHttpRequest()))); } } BrowserXhr.decorators = [ { type: Injectable } ]; /** @nocollapse */ BrowserXhr.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @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 */ /** @enum {number} */ const RequestMethod = { Get: 0, Post: 1, Put: 2, Delete: 3, Options: 4, Head: 5, Patch: 6, }; RequestMethod[RequestMethod.Get] = 'Get'; RequestMethod[RequestMethod.Post] = 'Post'; RequestMethod[RequestMethod.Put] = 'Put'; RequestMethod[RequestMethod.Delete] = 'Delete'; RequestMethod[RequestMethod.Options] = 'Options'; RequestMethod[RequestMethod.Head] = 'Head'; RequestMethod[RequestMethod.Patch] = 'Patch'; /** @enum {number} */ const ReadyState = { Unsent: 0, Open: 1, HeadersReceived: 2, Loading: 3, Done: 4, Cancelled: 5, }; ReadyState[ReadyState.Unsent] = 'Unsent'; ReadyState[ReadyState.Open] = 'Open'; ReadyState[ReadyState.HeadersReceived] = 'HeadersReceived'; ReadyState[ReadyState.Loading] = 'Loading'; ReadyState[ReadyState.Done] = 'Done'; ReadyState[ReadyState.Cancelled] = 'Cancelled'; /** @enum {number} */ const ResponseType = { Basic: 0, Cors: 1, Default: 2, Error: 3, Opaque: 4, }; ResponseType[ResponseType.Basic] = 'Basic'; ResponseType[ResponseType.Cors] = 'Cors'; ResponseType[ResponseType.Default] = 'Default'; ResponseType[ResponseType.Error] = 'Error'; ResponseType[ResponseType.Opaque] = 'Opaque'; /** @enum {number} */ const ContentType = { NONE: 0, JSON: 1, FORM: 2, FORM_DATA: 3, TEXT: 4, BLOB: 5, ARRAY_BUFFER: 6, }; ContentType[ContentType.NONE] = 'NONE'; ContentType[ContentType.JSON] = 'JSON'; ContentType[ContentType.FORM] = 'FORM'; ContentType[ContentType.FORM_DATA] = 'FORM_DATA'; ContentType[ContentType.TEXT] = 'TEXT'; ContentType[ContentType.BLOB] = 'BLOB'; ContentType[ContentType.ARRAY_BUFFER] = 'ARRAY_BUFFER'; /** @enum {number} */ const ResponseContentType = { Text: 0, Json: 1, ArrayBuffer: 2, Blob: 3, }; ResponseContentType[ResponseContentType.Text] = 'Text'; ResponseContentType[ResponseContentType.Json] = 'Json'; ResponseContentType[ResponseContentType.ArrayBuffer] = 'ArrayBuffer'; ResponseContentType[ResponseContentType.Blob] = 'Blob'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @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 */ /** * Polyfill for [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers), as * specified in the [Fetch Spec](https://fetch.spec.whatwg.org/#headers-class). * * The only known difference between this `Headers` implementation and the spec is the * lack of an `entries` method. * * \@usageNotes * ### Example * * ``` * import {Headers} from '\@angular/http'; * * var firstHeaders = new Headers(); * firstHeaders.append('Content-Type', 'image/jpeg'); * console.log(firstHeaders.get('Content-Type')) //'image/jpeg' * * // Create headers from Plain Old JavaScript Object * var secondHeaders = new Headers({ * 'X-My-Custom-Header': 'Angular' * }); * console.log(secondHeaders.get('X-My-Custom-Header')); //'Angular' * * var thirdHeaders = new Headers(secondHeaders); * console.log(thirdHeaders.get('X-My-Custom-Header')); //'Angular' * ``` * * @deprecated see https://angular.io/guide/http * \@publicApi */ class Headers { // TODO(vicb): any -> string|string[] /** * @param {?=} headers */ constructor(headers) { /** * \@internal header names are lower case */ this._headers = new Map(); /** * \@internal map lower case names to actual names */ this._normalizedNames = new Map(); if (!headers) { return; } if (headers instanceof Headers) { headers.forEach((values, name) => { values.forEach(value => this.append(name, value)); }); return; } Object.keys(headers).forEach((name) => { /** @type {?} */ const values = Array.isArray(headers[name]) ? headers[name] : [headers[name]]; this.delete(name); values.forEach(value => this.append(name, value)); }); } /** * Returns a new Headers instance from the given DOMString of Response Headers * @param {?} headersString * @return {?} */ static fromResponseHeaderString(headersString) { /** @type {?} */ const headers = new Headers(); headersString.split('\n').forEach(line => { /** @type {?} */ const index = line.indexOf(':'); if (index > 0) { /** @type {?} */ const name = line.slice(0, index); /** @type {?} */ const value = line.slice(index + 1).trim(); headers.set(name, value); } }); return headers; } /** * Appends a header to existing list of header values for a given header name. * @param {?} name * @param {?} value * @return {?} */ append(name, value) { /** @type {?} */ const values = this.getAll(name); if (values === null) { this.set(name, value); } else { values.push(value); } } /** * Deletes all header values for the given name. * @param {?} name * @return {?} */ delete(name) { /** @type {?} */ const lcName = name.toLowerCase(); this._normalizedNames.delete(lcName); this._headers.delete(lcName); } /** * @param {?} fn * @return {?} */ forEach(fn) { this._headers.forEach((values, lcName) => fn(values, this._normalizedNames.get(lcName), this._headers)); } /** * Returns first header that matches given name. * @param {?} name * @return {?} */ get(name) { /** @type {?} */ const values = this.getAll(name); if (values === null) { return null; } return values.length > 0 ? values[0] : null; } /** * Checks for existence of header by given name. * @param {?} name * @return {?} */ has(name) { return this._headers.has(name.toLowerCase()); } /** * Returns the names of the headers * @return {?} */ keys() { return Array.from(this._normalizedNames.values()); } /** * Sets or overrides header value for given name. * @param {?} name * @param {?} value * @return {?} */ set(name, value) { if (Array.isArray(value)) { if (value.length) { this._headers.set(name.toLowerCase(), [value.join(',')]); } } else { this._headers.set(name.toLowerCase(), [value]); } this.mayBeSetNormalizedName(name); } /** * Returns values of all headers. * @return {?} */ values() { return Array.from(this._headers.values()); } /** * Returns string of all headers. * @return {?} */ // TODO(vicb): returns {[name: string]: string[]} toJSON() { /** @type {?} */ const serialized = {}; this._headers.forEach((values, name) => { /** @type {?} */ const split = []; values.forEach(v => split.push(...v.split(','))); serialized[(/** @type {?} */ (this._normalizedNames.get(name)))] = split; }); return serialized; } /** * Returns list of header values for a given name. * @param {?} name * @return {?} */ getAll(name) { return this.has(name) ? this._headers.get(name.toLowerCase()) || null : null; } /** * This method is not implemented. * @return {?} */ entries() { throw new Error('"entries" method is not implemented on Headers class'); } /** * @private * @param {?} name * @return {?} */ mayBeSetNormalizedName(name) { /** @type {?} */ const lcName = name.toLowerCase(); if (!this._normalizedNames.has(lcName)) { this._normalizedNames.set(lcName, name); } } } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Creates a response options object to be optionally provided when instantiating a * {\@link Response}. * * This class is based on the `ResponseInit` description in the [Fetch * Spec](https://fetch.spec.whatwg.org/#responseinit). * * All values are null by default. Typical defaults can be found in the * {\@link BaseResponseOptions} class, which sub-classes `ResponseOptions`. * * This class may be used in tests to build {\@link Response Responses} for * mock responses (see {\@link MockBackend}). * * \@usageNotes * ### Example * * ```typescript * import {ResponseOptions, Response} from '\@angular/http'; * * var options = new ResponseOptions({ * body: '{"name":"Jeff"}' * }); * var res = new Response(options); * * console.log('res.json():', res.json()); // Object {name: "Jeff"} * ``` * * @deprecated see https://angular.io/guide/http * \@publicApi */ class ResponseOptions { /** * @param {?=} opts */ constructor(opts = {}) { const { body, status, headers, statusText, type, url } = opts; this.body = body != null ? body : null; this.status = status != null ? status : null; this.headers = headers != null ? headers : null; this.statusText = statusText != null ? statusText : null; this.type = type != null ? type : null; this.url = url != null ? url : null; } /** * Creates a copy of the `ResponseOptions` instance, using the optional input as values to * override * existing values. This method will not change the values of the instance on which it is being * called. * * This may be useful when sharing a base `ResponseOptions` object inside tests, * where certain properties may change from test to test. * * \@usageNotes * ### Example * * ```typescript * import {ResponseOptions, Response} from '\@angular/http'; * * var options = new ResponseOptions({ * body: {name: 'Jeff'} * }); * var res = new Response(options.merge({ * url: 'https://google.com' * })); * console.log('options.url:', options.url); // null * console.log('res.json():', res.json()); // Object {name: "Jeff"} * console.log('res.url:', res.url); // https://google.com * ``` * @param {?=} options * @return {?} */ merge(options) { return new ResponseOptions({ body: options && options.body != null ? options.body : this.body, status: options && options.status != null ? options.status : this.status, headers: options && options.headers != null ? options.headers : this.headers, statusText: options && options.statusText != null ? options.statusText : this.statusText, type: options && options.type != null ? options.type : this.type, url: options && options.url != null ? options.url : this.url, }); } } /** * Subclass of {\@link ResponseOptions}, with default values. * * Default values: * * status: 200 * * headers: empty {\@link Headers} object * * This class could be extended and bound to the {\@link ResponseOptions} class * when configuring an {\@link Injector}, in order to override the default options * used by {\@link Http} to create {\@link Response Responses}. * * \@usageNotes * ### Example * * ```typescript * import {provide} from '\@angular/core'; * import {bootstrap} from '\@angular/platform-browser/browser'; * import {HTTP_PROVIDERS, Headers, Http, BaseResponseOptions, ResponseOptions} from * '\@angular/http'; * import {App} from './myapp'; * * class MyOptions extends BaseResponseOptions { * headers:Headers = new Headers({network: 'github'}); * } * * bootstrap(App, [HTTP_PROVIDERS, {provide: ResponseOptions, useClass: MyOptions}]); * ``` * * The options could also be extended when manually creating a {\@link Response} * object. * * ### Example * * ``` * import {BaseResponseOptions, Response} from '\@angular/http'; * * var options = new BaseResponseOptions(); * var res = new Response(options.merge({ * body: 'Angular', * headers: new Headers({framework: 'angular'}) * })); * console.log('res.headers.get("framework"):', res.headers.get('framework')); // angular * console.log('res.text():', res.text()); // Angular; * ``` * * @deprecated see https://angular.io/guide/http * \@publicApi */ class BaseResponseOptions extends ResponseOptions { constructor() { super({ status: 200, statusText: 'Ok', type: ResponseType.Default, headers: new Headers() }); } } BaseResponseOptions.decorators = [ { type: Injectable } ]; /** @nocollapse */ BaseResponseOptions.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @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 */ /** * Abstract class from which real backends are derived. * * The primary purpose of a `ConnectionBackend` is to create new connections to fulfill a given * {\@link Request}. * * @deprecated see https://angular.io/guide/http * \@publicApi * @abstract */ class ConnectionBackend { } /** * Abstract class from which real connections are derived. * * @deprecated see https://angular.io/guide/http * \@publicApi * @abstract */ class Connection { } /** * An XSRFStrategy configures XSRF protection (e.g. via headers) on an HTTP request. * * @deprecated see https://angular.io/guide/http * \@publicApi * @abstract */ class XSRFStrategy { } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @param {?} method * @return {?} */ function normalizeMethodName(method) { if (typeof method !== 'string') return method; switch (method.toUpperCase()) { case 'GET': return RequestMethod.Get; case 'POST': return RequestMethod.Post; case 'PUT': return RequestMethod.Put; case 'DELETE': return RequestMethod.Delete; case 'OPTIONS': return RequestMethod.Options; case 'HEAD': return RequestMethod.Head; case 'PATCH': return RequestMethod.Patch; } throw new Error(`Invalid request method. The method "${method}" is not supported.`); } /** @type {?} */ const isSuccess = (status) => (status >= 200 && status < 300); /** * @param {?} xhr * @return {?} */ function getResponseURL(xhr) { if ('responseURL' in xhr) { return xhr.responseURL; } if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { return xhr.getResponseHeader('X-Request-URL'); } return null; } /** * @param {?} input * @return {?} */ function stringToArrayBuffer(input) { /** @type {?} */ const view = new Uint16Array(input.length); for (let i = 0, strLen = input.length; i < strLen; i++) { view[i] = input.charCodeAt(i); } return view.buffer; } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @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 */ /** * @param {?=} rawParams * @return {?} */ function paramParser(rawParams = '') { /** @type {?} */ const map = new Map(); if (rawParams.length > 0) { /** @type {?} */ const params = rawParams.split('&'); params.forEach((param) => { /** @type {?} */ const eqIdx = param.indexOf('='); const [key, val] = eqIdx == -1 ? [param, ''] : [param.slice(0, eqIdx), param.slice(eqIdx + 1)]; /** @type {?} */ const list = map.get(key) || []; list.push(val); map.set(key, list); }); } return map; } /** * @deprecated see https://angular.io/guide/http * \@publicApi * */ class QueryEncoder { /** * @param {?} key * @return {?} */ encodeKey(key) { return standardEncoding(key); } /** * @param {?} value * @return {?} */ encodeValue(value) { return standardEncoding(value); } } /** * @param {?} v * @return {?} */ function standardEncoding(v) { return encodeURIComponent(v) .replace(/%40/gi, '@') .replace(/%3A/gi, ':') .replace(/%24/gi, '$') .replace(/%2C/gi, ',') .replace(/%3B/gi, ';') .replace(/%2B/gi, '+') .replace(/%3D/gi, '=') .replace(/%3F/gi, '?') .replace(/%2F/gi, '/'); } /** * Map-like representation of url search parameters, based on * [URLSearchParams](https://url.spec.whatwg.org/#urlsearchparams) in the url living standard, * with several extensions for merging URLSearchParams objects: * - setAll() * - appendAll() * - replaceAll() * * This class accepts an optional second parameter of ${\@link QueryEncoder}, * which is used to serialize parameters before making a request. By default, * `QueryEncoder` encodes keys and values of parameters using `encodeURIComponent`, * and then un-encodes certain characters that are allowed to be part of the query * according to IETF RFC 3986: https://tools.ietf.org/html/rfc3986. * * These are the characters that are not encoded: `! $ \' ( ) * + , ; A 9 - . _ ~ ? /` * * If the set of allowed query characters is not acceptable for a particular backend, * `QueryEncoder` can be subclassed and provided as the 2nd argument to URLSearchParams. * * ``` * import {URLSearchParams, QueryEncoder} from '\@angular/http'; * class MyQueryEncoder extends QueryEncoder { * encodeKey(k: string): string { * return myEncodingFunction(k); * } * * encodeValue(v: string): string { * return myEncodingFunction(v); * } * } * * let params = new URLSearchParams('', new MyQueryEncoder()); * ``` * @deprecated see https://angular.io/guide/http * \@publicApi */ class URLSearchParams { /** * @param {?=} rawParams * @param {?=} queryEncoder */ constructor(rawParams = '', queryEncoder = new QueryEncoder()) { this.rawParams = rawParams; this.queryEncoder = queryEncoder; this.paramsMap = paramParser(rawParams); } /** * @return {?} */ clone() { /** @type {?} */ const clone = new URLSearchParams('', this.queryEncoder); clone.appendAll(this); return clone; } /** * @param {?} param * @return {?} */ has(param) { return this.paramsMap.has(param); } /** * @param {?} param * @return {?} */ get(param) { /** @type {?} */ const storedParam = this.paramsMap.get(param); return Array.isArray(storedParam) ? storedParam[0] : null; } /** * @param {?} param * @return {?} */ getAll(param) { return this.paramsMap.get(param) || []; } /** * @param {?} param * @param {?} val * @return {?} */ set(param, val) { if (val === void 0 || val === null) { this.delete(param); return; } /** @type {?} */ const list = this.paramsMap.get(param) || []; list.length = 0; list.push(val); this.paramsMap.set(param, list); } // A merge operation // For each name-values pair in `searchParams`, perform `set(name, values[0])` // // E.g: "a=[1,2,3], c=[8]" + "a=[4,5,6], b=[7]" = "a=[4], c=[8], b=[7]" // // TODO(@caitp): document this better /** * @param {?} searchParams * @return {?} */ setAll(searchParams) { searchParams.paramsMap.forEach((value, param) => { /** @type {?} */ const list = this.paramsMap.get(param) || []; list.length = 0; list.push(value[0]); this.paramsMap.set(param, list); }); } /** * @param {?} param * @param {?} val * @return {?} */ append(param, val) { if (val === void 0 || val === null) return; /** @type {?} */ const list = this.paramsMap.get(param) || []; list.push(val); this.paramsMap.set(param, list); } // A merge operation // For each name-values pair in `searchParams`, perform `append(name, value)` // for each value in `values`. // // E.g: "a=[1,2], c=[8]" + "a=[3,4], b=[7]" = "a=[1,2,3,4], c=[8], b=[7]" // // TODO(@caitp): document this better /** * @param {?} searchParams * @return {?} */ appendAll(searchParams) { searchParams.paramsMap.forEach((value, param) => { /** @type {?} */ const list = this.paramsMap.get(param) || []; for (let i = 0; i < value.length; ++i) { list.push(value[i]); } this.paramsMap.set(param, list); }); } // A merge operation // For each name-values pair in `searchParams`, perform `delete(name)`, // followed by `set(name, values)` // // E.g: "a=[1,2,3], c=[8]" + "a=[4,5,6], b=[7]" = "a=[4,5,6], c=[8], b=[7]" // // TODO(@caitp): document this better /** * @param {?} searchParams * @return {?} */ replaceAll(searchParams) { searchParams.paramsMap.forEach((value, param) => { /** @type {?} */ const list = this.paramsMap.get(param) || []; list.length = 0; for (let i = 0; i < value.length; ++i) { list.push(value[i]); } this.paramsMap.set(param, list); }); } /** * @return {?} */ toString() { /** @type {?} */ const paramsList = []; this.paramsMap.forEach((values, k) => { values.forEach(v => paramsList.push(this.queryEncoder.encodeKey(k) + '=' + this.queryEncoder.encodeValue(v))); }); return paramsList.join('&'); } /** * @param {?} param * @return {?} */ delete(param) { this.paramsMap.delete(param); } } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * HTTP request body used by both {\@link Request} and {\@link Response} * https://fetch.spec.whatwg.org/#body * @abstract */ class Body { /** * Attempts to return body as parsed `JSON` object, or raises an exception. * @return {?} */ json() { if (typeof this._body === 'string') { return JSON.parse((/** @type {?} */ (this._body))); } if (this._body instanceof ArrayBuffer) { return JSON.parse(this.text()); } return this._body; } /** * Returns the body as a string, presuming `toString()` can be called on the response body. * * When decoding an `ArrayBuffer`, the optional `encodingHint` parameter determines how the * bytes in the buffer will be interpreted. Valid values are: * * - `legacy` - incorrectly interpret the bytes as UTF-16 (technically, UCS-2). Only characters * in the Basic Multilingual Plane are supported, surrogate pairs are not handled correctly. * In addition, the endianness of the 16-bit octet pairs in the `ArrayBuffer` is not taken * into consideration. This is the default behavior to avoid breaking apps, but should be * considered deprecated. * * - `iso-8859` - interpret the bytes as ISO-8859 (which can be used for ASCII encoded text). * @param {?=} encodingHint * @return {?} */ text(encodingHint = 'legacy') { if (this._body instanceof URLSearchParams) { return this._body.toString(); } if (this._body instanceof ArrayBuffer) { switch (encodingHint) { case 'legacy': return String.fromCharCode.apply(null, new Uint16Array((/** @type {?} */ (this._body)))); case 'iso-8859': return String.fromCharCode.apply(null, new Uint8Array((/** @type {?} */ (this._body)))); default: throw new Error(`Invalid value for encodingHint: ${encodingHint}`); } } if (this._body == null) { return ''; } if (typeof this._body === 'object') { return JSON.stringify(this._body, null, 2); } return this._body.toString(); } /** * Return the body as an ArrayBuffer * @return {?} */ arrayBuffer() { if (this._body instanceof ArrayBuffer) { return (/** @type {?} */ (this._body)); } return stringToArrayBuffer(this.text()); } /** * Returns the request's body as a Blob, assuming that body exists. * @return {?} */ blob() { if (this._body instanceof Blob) { return (/** @type {?} */ (this._body)); } if (this._body instanceof ArrayBuffer) { return new Blob([this._body]); } throw new Error('The request body isn\'t either a blob or an array buffer'); } } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Creates `Response` instances from provided values. * * Though this object isn't * usually instantiated by end-users, it is the primary object interacted with when it comes time to * add data to a view. * * \@usageNotes * ### Example * * ``` * http.request('my-friends.txt').subscribe(response => this.friends = response.text()); * ``` * * The Response's interface is inspired by the Response constructor defined in the [Fetch * Spec](https://fetch.spec.whatwg.org/#response-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. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class Response extends Body { /** * @param {?} responseOptions */ constructor(responseOptions) { super(); this._body = responseOptions.body; this.status = (/** @type {?} */ (responseOptions.status)); this.ok = (this.status >= 200 && this.status <= 299); this.statusText = responseOptions.statusText; this.headers = responseOptions.headers; this.type = (/** @type {?} */ (responseOptions.type)); this.url = (/** @type {?} */ (responseOptions.url)); } /** * @return {?} */ toString() { return `Response with status: ${this.status} ${this.statusText} for URL: ${this.url}`; } } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ let _nextRequestId = 0; /** @type {?} */ const JSONP_HOME = '__ng_jsonp__'; /** @type {?} */ let _jsonpConnections = null; /** * @return {?} */ function _getJsonpConnections() { /** @type {?} */ const w = typeof window == 'object' ? window : {}; if (_jsonpConnections === null) { _jsonpConnections = w[JSONP_HOME] = {}; } return _jsonpConnections; } // Make sure not to evaluate this in a non-browser environment! class BrowserJsonp { // Construct a <script> element with the specified URL /** * @param {?} url * @return {?} */ build(url) { /** @type {?} */ const node = document.createElement('script'); node.src = url; return node; } /** * @return {?} */ nextRequestID() { return `__req${_nextRequestId++}`; } /** * @param {?} id * @return {?} */ requestCallback(id) { return `${JSONP_HOME}.${id}.finished`; } /** * @param {?} id * @param {?} connection * @return {?} */ exposeConnection(id, connection) { /** @type {?} */ const connections = _getJsonpConnections(); connections[id] = connection; } /** * @param {?} id * @return {?} */ removeConnection(id) { /** @type {?} */ const connections = _getJsonpConnections(); connections[id] = null; } // Attach the <script> element to the DOM /** * @param {?} node * @return {?} */ send(node) { document.body.appendChild((/** @type {?} */ ((node)))); } // Remove <script> element from the DOM /** * @param {?} node * @return {?} */ cleanup(node) { if (node.parentNode) { node.parentNode.removeChild((/** @type {?} */ ((node)))); } } } BrowserJsonp.decorators = [ { type: Injectable } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const JSONP_ERR_NO_CALLBACK = 'JSONP injected script did not invoke callback.'; /** @type {?} */ const JSONP_ERR_WRONG_METHOD = 'JSONP requests must use GET request method.'; /** * Base class for an in-flight JSONP request. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class JSONPConnection { /** * \@internal * @param {?} req * @param {?} _dom * @param {?=} baseResponseOptions */ constructor(req, _dom, baseResponseOptions) { this._dom = _dom; this.baseResponseOptions = baseResponseOptions; this._finished = false; if (req.method !== RequestMethod.Get) { throw new TypeError(JSONP_ERR_WRONG_METHOD); } this.request = req; this.response = new Observable((responseObserver) => { this.readyState = ReadyState.Loading; /** @type {?} */ const id = this._id = _dom.nextRequestID(); _dom.exposeConnection(id, this); // Workaround Dart // url = url.replace(/=JSONP_CALLBACK(&|$)/, `generated method`); /** @type {?} */ const callback = _dom.requestCallback(this._id); /** @type {?} */ let url = req.url; if (url.indexOf('=JSONP_CALLBACK&') > -1) { url = url.replace('=JSONP_CALLBACK&', `=${callback}&`); } else if (url.lastIndexOf('=JSONP_CALLBACK') === url.length - '=JSONP_CALLBACK'.length) { url = url.substring(0, url.length - '=JSONP_CALLBACK'.length) + `=${callback}`; } /** @type {?} */ const script = this._script = _dom.build(url); /** @type {?} */ const onLoad = (event) => { if (this.readyState === ReadyState.Cancelled) return; this.readyState = ReadyState.Done; _dom.cleanup(script); if (!this._finished) { /** @type {?} */ let responseOptions = new ResponseOptions({ body: JSONP_ERR_NO_CALLBACK, type: ResponseType.Error, url }); if (baseResponseOptions) { responseOptions = baseResponseOptions.merge(responseOptions); } responseObserver.error(new Response(responseOptions)); return; } /** @type {?} */ let responseOptions = new ResponseOptions({ body: this._responseData, url }); if (this.baseResponseOptions) { responseOptions = this.baseResponseOptions.merge(responseOptions); } responseObserver.next(new Response(responseOptions)); responseObserver.complete(); }; /** @type {?} */ const onError = (error) => { if (this.readyState === ReadyState.Cancelled) return; this.readyState = ReadyState.Done; _dom.cleanup(script); /** @type {?} */ let responseOptions = new ResponseOptions({ body: error.message, type: ResponseType.Error }); if (baseResponseOptions) { responseOptions = baseResponseOptions.merge(responseOptions); } responseObserver.error(new Response(responseOptions)); }; script.addEventListener('load', onLoad); script.addEventListener('error', onError); _dom.send(script); return () => { this.readyState = ReadyState.Cancelled; script.removeEventListener('load', onLoad); script.removeEventListener('error', onError); this._dom.cleanup(script); }; }); } /** * Callback called when the JSONP request completes, to notify the application * of the new data. * @param {?=} data * @return {?} */ finished(data) { // Don't leak connections this._finished = true; this._dom.removeConnection(this._id); if (this.readyState === ReadyState.Cancelled) return; this._responseData = data; } } /** * A {\@link ConnectionBackend} that uses the JSONP strategy of making requests. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class JSONPBackend extends ConnectionBackend { /** * \@internal * @param {?} _browserJSONP * @param {?} _baseResponseOptions */ constructor(_browserJSONP, _baseResponseOptions) { super(); this._browserJSONP = _browserJSONP; this._baseResponseOptions = _baseResponseOptions; } /** * @param {?} request * @return {?} */ createConnection(request) { return new JSONPConnection(request, this._browserJSONP, this._baseResponseOptions); } } JSONPBackend.decorators = [ { type: Injectable } ]; /** @nocollapse */ JSONPBackend.ctorParameters = () => [ { type: BrowserJsonp }, { type: ResponseOptions } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const XSSI_PREFIX = /^\)\]\}',?\n/; /** * Creates connections using `XMLHttpRequest`. Given a fully-qualified * request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the * request. * * This class would typically not be created or interacted with directly inside applications, though * the {\@link MockConnection} may be interacted with in tests. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class XHRConnection { /** * @param {?} req * @param {?} browserXHR * @param {?=} baseResponseOptions */ constructor(req, browserXHR, baseResponseOptions) { this.request = req; this.response = new Observable((responseObserver) => { /** @type {?} */ const _xhr = browserXHR.build(); _xhr.open(RequestMethod[req.method].toUpperCase(), req.url); if (req.withCredentials != null) { _xhr.withCredentials = req.withCredentials; } // load event handler /** @type {?} */ const onLoad = () => { // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) /** @type {?} */ let status = _xhr.status === 1223 ? 204 : _xhr.status; /** @type {?} */ let body = null; // HTTP 204 means no content if (status !== 204) { // responseText is the old-school way of retrieving response (supported by IE8 & 9) // response/responseType properties were introduced in ResourceLoader Level2 spec // (supported by IE10) body = (typeof _xhr.response === 'undefined') ? _xhr.responseText : _xhr.response; // Implicitly strip a potential XSSI prefix. if (typeof body === 'string') { body = body.replace(XSSI_PREFIX, ''); } } // fix status code when it is 0 (0 status is undocumented). // Occurs when accessing file resources or on Android 4.1 stock browser // while retrieving files from application cache. if (status === 0) { status = body ? 200 : 0; } /** @type {?} */ const headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders()); // IE 9 does not provide the way to get URL of response /** @type {?} */ const url = getResponseURL(_xhr) || req.url; /** @type {?} */ const statusText = _xhr.statusText || 'OK'; /** @type {?} */ let responseOptions = new ResponseOptions({ body, status, headers, statusText, url }); if (baseResponseOptions != null) { responseOptions = baseResponseOptions.merge(responseOptions); } /** @type {?} */ const response = new Response(responseOptions); response.ok = isSuccess(status); if (response.ok) { responseObserver.next(response); // TODO(gdi2290): defer complete if array buffer until done responseObserver.complete(); return; } responseObserver.error(response); }; // error event handler /** @type {?} */ const onError = (err) => { /** @type {?} */ let responseOptions = new ResponseOptions({ body: err, type: ResponseType.Error, status: _xhr.status, statusText: _xhr.statusText, }); if (baseResponseOptions != null) { responseOptions = baseResponseOptions.merge(responseOptions); } responseObserver.error(new Response(responseOptions)); }; this.setDetectedContentType(req, _xhr); if (req.headers == null) { req.headers = new Headers(); } if (!req.headers.has('Accept')) { req.headers.append('Accept', 'application/json, text/plain, */*'); } req.headers.forEach((values, name) => _xhr.setRequestHeader((/** @type {?} */ (name)), values.join(','))); // Select the correct buffer type to store the response if (req.responseType != null && _xhr.responseType != null) { switch (req.responseType) { case ResponseContentType.ArrayBuffer: _xhr.responseType = 'arraybuffer'; break; case ResponseContentType.Json: _xhr.responseType = 'json'; break; case ResponseContentType.Text: _xhr.responseType = 'text'; break; case ResponseContentType.Blob: _xhr.responseType = 'blob'; break; default: throw new Error('The selected responseType is not supported'); } } _xhr.addEventListener('load', onLoad); _xhr.addEventListener('error', onError); _xhr.send(this.request.getBody()); return () => { _xhr.removeEventListener('load', onLoad); _xhr.removeEventListener('error', onError); _xhr.abort(); }; }); } /** * @param {?} req * @param {?} _xhr * @return {?} */ setDetectedContentType(req /** TODO Request */, _xhr /** XMLHttpRequest */) { // Skip if a custom Content-Type header is provided if (req.headers != null && req.headers.get('Content-Type') != null) { return; } // Set the detected content type switch (req.contentType) { case ContentType.NONE: break; case ContentType.JSON: _xhr.setRequestHeader('content-type', 'application/json'); break; case ContentType.FORM: _xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); break; case ContentType.TEXT: _xhr.setRequestHeader('content-type', 'text/plain'); break; case ContentType.BLOB: /** @type {?} */ const blob = req.blob(); if (blob.type) { _xhr.setRequestHeader('content-type', blob.type); } break; } } } /** * `XSRFConfiguration` sets up Cross Site Request Forgery (XSRF) protection for the application * using a cookie. See https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) * for more information on XSRF. * * Applications can configure custom cookie and header names by binding an instance of this class * with different `cookieName` and `headerName` values. See the main HTTP documentation for more * details. * * @deprecated see https://angular.io/guide/http * \@publicApi */ class CookieXSRFStrategy { /** * @param {?=} _cookieName * @param {?=} _headerName */ constructor(_cookieName = 'XSRF-TOKEN', _headerName = 'X-XSRF-TOKEN') { this._cookieName = _cookieName; this._headerName = _headerName; } /** * @param {?} req * @return {?} */ configureRequest(req) { /** @type {?} */ const xsrfToken = ɵgetDOM().getCookie(this._cookieName); if (xsrfToken) { req.headers.set(this._headerName, xsrfToken); } } } /** * Creates {\@link XHRConnection} instances. * * This class would typically not be used by end users, but could be * overridden if a different backend implementation should be used, * such as in a node backend. * * \@usageNotes * ### Example * * ``` * import {Http, MyNodeBackend, HTTP_PROVIDERS, BaseRequestOptions} from '\@angular/http'; * \@Component({ * viewProviders: [ * HTTP_PROVIDERS, * {provide: Http, useFactory: (backend, options) => { * return new Http(backend, options); * }, deps: [MyNodeBackend, BaseRequestOptions]}] * }) * class MyComponent { * constructor(http:Http) { * http.request('people.json').subscribe(res => this.people = res.json()); * } * } * ``` * @deprecated see https://angular.io/guide/http * \@publicApi */ class XHRBackend { /** * @param {?} _browserXHR * @param {?} _baseResponseOptions * @param {?} _xsrfStrategy */ constructor(_browserXHR, _baseResponseOptions, _xsrfStrategy) { this._browserXHR = _browserXHR; this._baseResponseOptions = _baseResponseOptions; this._xsrfStrategy = _xsrfStrategy; } /** * @param {?} request * @return {?} */ createConnection(request) { this._xsrfStrategy.configureRequest(request); return new XHRConnection(request, this._browserXHR, this._baseResponseOptions); } } XHRBackend.decorators = [ { type: Injectable } ]; /** @nocollapse */ XHRBackend.ctorParameters = () => [ { type: BrowserXhr }, { type: ResponseOptions }, { type: XSRFStrategy } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Creates a request options object to be optionally provided when instantiating a * {\@link Request}. * * This class is based on the `RequestInit` description in the [Fetch * Spec](https://fetch.spec.whatwg.org/#requestinit). * * All values are null by default. Typical defaults can be found in the {\@link BaseRequestOptions} * class, which sub-classes `RequestOptions`. * * ```typescript * import {RequestOptions, Request, RequestMethod} from '\@angular/http'; * * const options = new RequestOptions({ * method: RequestMethod.Post, * url: 'https://google.com' * }); * const req = new Request(options); * console.log('req.method:', RequestMethod[req.method]); // Post * console.log('options.url:', options.url); // https://google.com * ``` * * @deprecated see https://angular.io/guide/http * \@publicApi */ class RequestOptions { /** * @deprecated from 4.0.0. Use params instead. * @return {?} */ get search() { return this.params; } /** * @deprecated from 4.0.0. Use params instead. * @param {?} params * @return {?} */ set search(params) { this.params = params; } // TODO(Dzmitry): remove search when this.search is removed /** * @param {?=} opts */ constructor(opts = {}) { const { method, headers, body, url, search, params, withCredentials, responseType } = opts; this.method = method != null ? normalizeMethodName(method) : null; this.headers = headers != null ? headers : null; this.body = body != null ? body : null; this.url = url != null ? url : null; this.params = this._mergeSearchParams(params || search); this.withCredentials = withCredentials != null ? withCredentials : null; this.responseType = responseType != null ? responseType : null; } /** * Creates a copy of the `RequestOptions` instance, using the optional input as values to override * existing values. This method will not change the values of the instance on which it is being * called. * * Note that `headers` and `search` will override existing values completely if present in * the `options` object. If these values should be merged, it should be done prior to calling * `merge` on the `RequestOptions` instance. * * ```typescript * import {RequestOptions, Request, RequestMethod} from '\@angular/http'; * * const options = new RequestOptions({ * method: RequestMethod.Post * }); * const req = new Request(options.merge({ * url: 'https://google.com' * })); * console.log('req.method:', RequestMethod[req.method]); // Post * console.log('options.url:', options.url); // null * console.log('req.url:', req.url); // https://google.com * ``` * @param {?=} options * @return {?} */ merge(options) { return new RequestOptions({ method: options && options.method != null ? options.method : this.method, headers: options && options.headers != null ? options.headers : new Headers(this.headers), body: options && options.body != null ? options.body : this.body, url: options && options.url != null ? options.url : this.url, params: options && this._mergeSearchParams(options.params || options.search), withCredentials: options && options.withCredentials != null ? options.withCredentials : this.withCredentials, responseType: options && options.responseType != null ? options.responseType : this.responseType }); } /** * @private * @param {?=} params * @return {?} */ _mergeSearchParams(params) { if (!params) return this.params; if (params instanceof URLSearchParams) { return params.clone(); } if (typeof params === 'string') { return new URLSearchParams(params); } return this._parseParams(params); } /** * @private * @param {?=} objParams * @return {?} */ _parseParams(objParams = {}) { /** @type {?} */ const params = new URL