feat: remove @angular/http (#27038)
The legacy HTTP package was deprecated in v5 with the launch of @angular/common/http. The legacy package hasn't been published since v7, and will therefore not include a migration. PR Close #27038
This commit is contained in:
parent
fbd281c26e
commit
388dc93cee
|
@ -366,7 +366,6 @@ groups:
|
||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
'packages/common/http/**',
|
'packages/common/http/**',
|
||||||
'packages/http/**',
|
|
||||||
'packages/examples/http/**',
|
'packages/examples/http/**',
|
||||||
'aio/content/guide/http.md',
|
'aio/content/guide/http.md',
|
||||||
'aio/content/examples/http/**',
|
'aio/content/examples/http/**',
|
||||||
|
|
|
@ -7,7 +7,6 @@ Our semver, timed-release cycle and deprecation policy currently applies to thes
|
||||||
- `@angular/common`
|
- `@angular/common`
|
||||||
- `@angular/elements`
|
- `@angular/elements`
|
||||||
- `@angular/forms`
|
- `@angular/forms`
|
||||||
- `@angular/http`
|
|
||||||
- `@angular/platform-browser`
|
- `@angular/platform-browser`
|
||||||
- `@angular/platform-browser-dynamic`
|
- `@angular/platform-browser-dynamic`
|
||||||
- `@angular/platform-server`
|
- `@angular/platform-server`
|
||||||
|
|
|
@ -1,259 +0,0 @@
|
||||||
/** @deprecated */
|
|
||||||
export declare class BaseRequestOptions extends RequestOptions {
|
|
||||||
constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class BaseResponseOptions extends ResponseOptions {
|
|
||||||
constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class BrowserXhr {
|
|
||||||
constructor();
|
|
||||||
build(): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare abstract class Connection {
|
|
||||||
readyState: ReadyState;
|
|
||||||
request: Request;
|
|
||||||
response: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare abstract class ConnectionBackend {
|
|
||||||
abstract createConnection(request: any): Connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class CookieXSRFStrategy implements XSRFStrategy {
|
|
||||||
constructor(_cookieName?: string, _headerName?: string);
|
|
||||||
configureRequest(req: Request): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class Headers {
|
|
||||||
constructor(headers?: Headers | {
|
|
||||||
[name: string]: any;
|
|
||||||
} | null);
|
|
||||||
append(name: string, value: string): void;
|
|
||||||
delete(name: string): void;
|
|
||||||
entries(): void;
|
|
||||||
forEach(fn: (values: string[], name: string | undefined, headers: Map<string, string[]>) => void): void;
|
|
||||||
get(name: string): string | null;
|
|
||||||
getAll(name: string): string[] | null;
|
|
||||||
has(name: string): boolean;
|
|
||||||
keys(): string[];
|
|
||||||
set(name: string, value: string | string[]): void;
|
|
||||||
toJSON(): {
|
|
||||||
[name: string]: any;
|
|
||||||
};
|
|
||||||
values(): string[][];
|
|
||||||
static fromResponseHeaderString(headersString: string): Headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class Http {
|
|
||||||
protected _backend: ConnectionBackend;
|
|
||||||
protected _defaultOptions: RequestOptions;
|
|
||||||
constructor(_backend: ConnectionBackend, _defaultOptions: RequestOptions);
|
|
||||||
delete(url: string, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
get(url: string, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
head(url: string, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
options(url: string, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class HttpModule {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class Jsonp extends Http {
|
|
||||||
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions);
|
|
||||||
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class JSONPBackend extends ConnectionBackend {
|
|
||||||
createConnection(request: Request): JSONPConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class JSONPConnection implements Connection {
|
|
||||||
readyState: ReadyState;
|
|
||||||
request: Request;
|
|
||||||
response: Observable<Response>;
|
|
||||||
finished(data?: any): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class JsonpModule {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class QueryEncoder {
|
|
||||||
encodeKey(key: string): string;
|
|
||||||
encodeValue(value: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare enum ReadyState {
|
|
||||||
Unsent = 0,
|
|
||||||
Open = 1,
|
|
||||||
HeadersReceived = 2,
|
|
||||||
Loading = 3,
|
|
||||||
Done = 4,
|
|
||||||
Cancelled = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class Request extends ɵangular_packages_http_http_f {
|
|
||||||
headers: Headers;
|
|
||||||
method: RequestMethod;
|
|
||||||
responseType: ResponseContentType;
|
|
||||||
url: string;
|
|
||||||
withCredentials: boolean;
|
|
||||||
constructor(requestOptions: ɵangular_packages_http_http_d);
|
|
||||||
detectContentType(): ContentType;
|
|
||||||
detectContentTypeFromBody(): ContentType;
|
|
||||||
getBody(): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare enum RequestMethod {
|
|
||||||
Get = 0,
|
|
||||||
Post = 1,
|
|
||||||
Put = 2,
|
|
||||||
Delete = 3,
|
|
||||||
Options = 4,
|
|
||||||
Head = 5,
|
|
||||||
Patch = 6
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class RequestOptions {
|
|
||||||
body: any;
|
|
||||||
headers: Headers | null;
|
|
||||||
method: RequestMethod | string | null;
|
|
||||||
params: URLSearchParams;
|
|
||||||
responseType: ResponseContentType | null;
|
|
||||||
/** @deprecated */ get search(): URLSearchParams;
|
|
||||||
/** @deprecated */ set search(params: URLSearchParams);
|
|
||||||
url: string | null;
|
|
||||||
withCredentials: boolean | null;
|
|
||||||
constructor(opts?: RequestOptionsArgs);
|
|
||||||
merge(options?: RequestOptionsArgs): RequestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare interface RequestOptionsArgs {
|
|
||||||
body?: any;
|
|
||||||
headers?: Headers | null;
|
|
||||||
method?: string | RequestMethod | null;
|
|
||||||
params?: string | URLSearchParams | {
|
|
||||||
[key: string]: any | any[];
|
|
||||||
} | null;
|
|
||||||
responseType?: ResponseContentType | null;
|
|
||||||
/** @deprecated */ search?: string | URLSearchParams | {
|
|
||||||
[key: string]: any | any[];
|
|
||||||
} | null;
|
|
||||||
url?: string | null;
|
|
||||||
withCredentials?: boolean | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class Response extends ɵangular_packages_http_http_f {
|
|
||||||
bytesLoaded: number;
|
|
||||||
headers: Headers | null;
|
|
||||||
ok: boolean;
|
|
||||||
status: number;
|
|
||||||
statusText: string | null;
|
|
||||||
totalBytes: number;
|
|
||||||
type: ResponseType;
|
|
||||||
url: string;
|
|
||||||
constructor(responseOptions: ResponseOptions);
|
|
||||||
toString(): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare enum ResponseContentType {
|
|
||||||
Text = 0,
|
|
||||||
Json = 1,
|
|
||||||
ArrayBuffer = 2,
|
|
||||||
Blob = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class ResponseOptions {
|
|
||||||
body: string | Object | ArrayBuffer | Blob | null;
|
|
||||||
headers: Headers | null;
|
|
||||||
status: number | null;
|
|
||||||
url: string | null;
|
|
||||||
constructor(opts?: ResponseOptionsArgs);
|
|
||||||
merge(options?: ResponseOptionsArgs): ResponseOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare interface ResponseOptionsArgs {
|
|
||||||
body?: string | Object | FormData | ArrayBuffer | Blob | null;
|
|
||||||
headers?: Headers | null;
|
|
||||||
status?: number | null;
|
|
||||||
statusText?: string | null;
|
|
||||||
type?: ResponseType | null;
|
|
||||||
url?: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare enum ResponseType {
|
|
||||||
Basic = 0,
|
|
||||||
Cors = 1,
|
|
||||||
Default = 2,
|
|
||||||
Error = 3,
|
|
||||||
Opaque = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class URLSearchParams {
|
|
||||||
paramsMap: Map<string, string[]>;
|
|
||||||
rawParams: string;
|
|
||||||
constructor(rawParams?: string, queryEncoder?: QueryEncoder);
|
|
||||||
append(param: string, val: string): void;
|
|
||||||
appendAll(searchParams: URLSearchParams): void;
|
|
||||||
clone(): URLSearchParams;
|
|
||||||
delete(param: string): void;
|
|
||||||
get(param: string): string | null;
|
|
||||||
getAll(param: string): string[];
|
|
||||||
has(param: string): boolean;
|
|
||||||
replaceAll(searchParams: URLSearchParams): void;
|
|
||||||
set(param: string, val: string): void;
|
|
||||||
setAll(searchParams: URLSearchParams): void;
|
|
||||||
toString(): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare const VERSION: Version;
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class XHRBackend implements ConnectionBackend {
|
|
||||||
constructor(_browserXHR: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy);
|
|
||||||
createConnection(request: Request): XHRConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class XHRConnection implements Connection {
|
|
||||||
readyState: ReadyState;
|
|
||||||
request: Request;
|
|
||||||
response: Observable<Response>;
|
|
||||||
constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions);
|
|
||||||
setDetectedContentType(req: any /** TODO Request */, _xhr: any /** XMLHttpRequest */): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare abstract class XSRFStrategy {
|
|
||||||
abstract configureRequest(req: Request): void;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
/** @deprecated */
|
|
||||||
export declare class MockBackend implements ConnectionBackend {
|
|
||||||
connections: any;
|
|
||||||
connectionsArray: MockConnection[];
|
|
||||||
pendingConnections: any;
|
|
||||||
constructor();
|
|
||||||
createConnection(req: Request): MockConnection;
|
|
||||||
resolveAllConnections(): void;
|
|
||||||
verifyNoPendingRequests(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export declare class MockConnection implements Connection {
|
|
||||||
readyState: ReadyState;
|
|
||||||
request: Request;
|
|
||||||
response: ReplaySubject<Response>;
|
|
||||||
constructor(req: Request);
|
|
||||||
mockDownload(res: Response): void;
|
|
||||||
mockError(err?: Error): void;
|
|
||||||
mockRespond(res: Response): void;
|
|
||||||
}
|
|
|
@ -44,7 +44,6 @@ GENERATED_NPM_PACKAGES = [
|
||||||
"@angular/core",
|
"@angular/core",
|
||||||
"@angular/elements",
|
"@angular/elements",
|
||||||
"@angular/forms",
|
"@angular/forms",
|
||||||
"@angular/http",
|
|
||||||
"@angular/language-service",
|
"@angular/language-service",
|
||||||
"@angular/localize",
|
"@angular/localize",
|
||||||
"@angular/platform-browser",
|
"@angular/platform-browser",
|
||||||
|
|
|
@ -34,7 +34,6 @@ function benchmarksBootstrap() {
|
||||||
'/packages-dist/platform-browser/bundles/platform-browser.umd.js',
|
'/packages-dist/platform-browser/bundles/platform-browser.umd.js',
|
||||||
'@angular/platform-browser-dynamic':
|
'@angular/platform-browser-dynamic':
|
||||||
'/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
|
'/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
|
||||||
'@angular/http': '/packages-dist/http/bundles/http.umd.js',
|
|
||||||
'@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js',
|
'@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js',
|
||||||
'@angular/router': '/packages-dist/router/bundles/router.umd.js',
|
'@angular/router': '/packages-dist/router/bundles/router.umd.js',
|
||||||
'rxjs': '/all/benchmarks/vendor/rxjs',
|
'rxjs': '/all/benchmarks/vendor/rxjs',
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {Component} from '@angular/core';
|
||||||
<h1>people</h1>
|
<h1>people</h1>
|
||||||
<ul class="people">
|
<ul class="people">
|
||||||
<li *ngFor="let person of people">
|
<li *ngFor="let person of people">
|
||||||
hello, {{person['name']}}
|
hello, {{person.name}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
`
|
`
|
||||||
|
|
|
@ -110,8 +110,6 @@ WELL_KNOWN_GLOBALS = {p: _global_name(p) for p in [
|
||||||
"@angular/common/http/testing",
|
"@angular/common/http/testing",
|
||||||
"@angular/common/http",
|
"@angular/common/http",
|
||||||
"@angular/elements",
|
"@angular/elements",
|
||||||
"@angular/http/testing",
|
|
||||||
"@angular/http",
|
|
||||||
"@angular/platform-browser-dynamic/testing",
|
"@angular/platform-browser-dynamic/testing",
|
||||||
"@angular/platform-browser-dynamic",
|
"@angular/platform-browser-dynamic",
|
||||||
"@angular/compiler/testing",
|
"@angular/compiler/testing",
|
||||||
|
|
|
@ -56,7 +56,6 @@ nodejs_test(
|
||||||
"//packages/compiler-cli:npm_package",
|
"//packages/compiler-cli:npm_package",
|
||||||
"//packages/core:npm_package",
|
"//packages/core:npm_package",
|
||||||
"//packages/forms:npm_package",
|
"//packages/forms:npm_package",
|
||||||
"//packages/http:npm_package",
|
|
||||||
"//packages/platform-browser:npm_package",
|
"//packages/platform-browser:npm_package",
|
||||||
"//packages/platform-browser-dynamic:npm_package",
|
"//packages/platform-browser-dynamic:npm_package",
|
||||||
"//packages/platform-server:npm_package",
|
"//packages/platform-server:npm_package",
|
||||||
|
|
|
@ -28,7 +28,6 @@ const requiredNodeModules = {
|
||||||
'@angular/compiler-cli': resolveNpmTreeArtifact('angular/packages/compiler-cli/npm_package'),
|
'@angular/compiler-cli': resolveNpmTreeArtifact('angular/packages/compiler-cli/npm_package'),
|
||||||
'@angular/core': resolveNpmTreeArtifact('angular/packages/core/npm_package'),
|
'@angular/core': resolveNpmTreeArtifact('angular/packages/core/npm_package'),
|
||||||
'@angular/forms': resolveNpmTreeArtifact('angular/packages/forms/npm_package'),
|
'@angular/forms': resolveNpmTreeArtifact('angular/packages/forms/npm_package'),
|
||||||
'@angular/http': resolveNpmTreeArtifact('angular/packages/http/npm_package'),
|
|
||||||
'@angular/platform-browser':
|
'@angular/platform-browser':
|
||||||
resolveNpmTreeArtifact('angular/packages/platform-browser/npm_package'),
|
resolveNpmTreeArtifact('angular/packages/platform-browser/npm_package'),
|
||||||
'@angular/platform-browser-dynamic':
|
'@angular/platform-browser-dynamic':
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
load("//tools:defaults.bzl", "ng_module", "ng_package", "ts_api_guardian_test_npm_package")
|
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
|
||||||
|
|
||||||
ng_module(
|
|
||||||
name = "http",
|
|
||||||
srcs = glob(
|
|
||||||
[
|
|
||||||
"*.ts",
|
|
||||||
"src/**/*.ts",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
# Disable building with strict compatibility as the http package is no longer
|
|
||||||
# maintained and therefore not needed to be made compatible with --strict.
|
|
||||||
tsconfig = "//packages:tsconfig-build-no-strict",
|
|
||||||
deps = [
|
|
||||||
"//packages/core",
|
|
||||||
"//packages/platform-browser",
|
|
||||||
"@npm//rxjs",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
ng_package(
|
|
||||||
name = "npm_package",
|
|
||||||
srcs = [
|
|
||||||
"package.json",
|
|
||||||
"//packages/http/testing:package.json",
|
|
||||||
],
|
|
||||||
entry_point = ":index.ts",
|
|
||||||
tags = [
|
|
||||||
# Currently the plan for Angular v8 is to exclude @angular/http package from publishing
|
|
||||||
# "release-with-framework",
|
|
||||||
],
|
|
||||||
# Do not add more to this list.
|
|
||||||
# Dependencies on the full npm_package cause long re-builds.
|
|
||||||
visibility = [
|
|
||||||
"//integration:__pkg__",
|
|
||||||
"//packages/compiler-cli/integrationtest:__pkg__",
|
|
||||||
],
|
|
||||||
deps = [
|
|
||||||
":http",
|
|
||||||
"//packages/http/testing",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
ts_api_guardian_test_npm_package(
|
|
||||||
name = "http_api",
|
|
||||||
actualDir = "angular/packages/http/npm_package",
|
|
||||||
data = [
|
|
||||||
":npm_package",
|
|
||||||
"//goldens:public-api",
|
|
||||||
],
|
|
||||||
goldenDir = "angular/goldens/public-api/http",
|
|
||||||
)
|
|
|
@ -1 +0,0 @@
|
||||||
Deprecated in favor of `@angular/common/http`.
|
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This file is not used to build this module. It is only used during editing
|
|
||||||
// by the TypeScript language service and during build for verification. `ngc`
|
|
||||||
// replaces this file with production index.ts when it rewrites private symbol
|
|
||||||
// names.
|
|
||||||
|
|
||||||
export * from './public_api';
|
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@angular/http",
|
|
||||||
"version": "0.0.0-PLACEHOLDER",
|
|
||||||
"description": "Angular - the http service",
|
|
||||||
"main": "./bundles/http.umd.js",
|
|
||||||
"module": "./fesm5/http.js",
|
|
||||||
"es2015": "./fesm2015/http.js",
|
|
||||||
"esm5": "./esm5/http.js",
|
|
||||||
"esm2015": "./esm2015/http.js",
|
|
||||||
"fesm5": "./fesm5/http.js",
|
|
||||||
"fesm2015": "./fesm2015/http.js",
|
|
||||||
"typings": "./http.d.ts",
|
|
||||||
"author": "angular",
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"@angular/core": "0.0.0-PLACEHOLDER",
|
|
||||||
"@angular/platform-browser": "0.0.0-PLACEHOLDER",
|
|
||||||
"rxjs": "^6.5.3",
|
|
||||||
"tslib": "^1.10.0"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/angular/angular.git",
|
|
||||||
"repository": "packages/http"
|
|
||||||
},
|
|
||||||
"ng-update": {
|
|
||||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
|
||||||
},
|
|
||||||
"sideEffects": false,
|
|
||||||
"publishConfig":{
|
|
||||||
"registry":"https://wombat-dressing-room.appspot.com"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Entry point for all public APIs of this package.
|
|
||||||
*/
|
|
||||||
export * from './src/index';
|
|
||||||
|
|
||||||
// This file only reexports content of the `src` folder. Keep it that way.
|
|
|
@ -1,62 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
|
|
||||||
let _nextRequestId = 0;
|
|
||||||
export const JSONP_HOME = '__ng_jsonp__';
|
|
||||||
let _jsonpConnections: {[key: string]: any}|null = null;
|
|
||||||
|
|
||||||
function _getJsonpConnections(): {[key: string]: any} {
|
|
||||||
const w: {[key: string]: any} = typeof window == 'object' ? window : {};
|
|
||||||
if (_jsonpConnections === null) {
|
|
||||||
_jsonpConnections = w[JSONP_HOME] = {};
|
|
||||||
}
|
|
||||||
return _jsonpConnections;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure not to evaluate this in a non-browser environment!
|
|
||||||
@Injectable()
|
|
||||||
export class BrowserJsonp {
|
|
||||||
// Construct a <script> element with the specified URL
|
|
||||||
build(url: string): any {
|
|
||||||
const node = document.createElement('script');
|
|
||||||
node.src = url;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextRequestID(): string {
|
|
||||||
return `__req${_nextRequestId++}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestCallback(id: string): string {
|
|
||||||
return `${JSONP_HOME}.${id}.finished`;
|
|
||||||
}
|
|
||||||
|
|
||||||
exposeConnection(id: string, connection: any) {
|
|
||||||
const connections = _getJsonpConnections();
|
|
||||||
connections[id] = connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeConnection(id: string) {
|
|
||||||
const connections = _getJsonpConnections();
|
|
||||||
connections[id] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach the <script> element to the DOM
|
|
||||||
send(node: any) {
|
|
||||||
document.body.appendChild(<Node>(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove <script> element from the DOM
|
|
||||||
cleanup(node: any) {
|
|
||||||
if (node.parentNode) {
|
|
||||||
node.parentNode.removeChild(<Node>(node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class BrowserXhr {
|
|
||||||
constructor() {}
|
|
||||||
build(): any {
|
|
||||||
return <any>(new XMLHttpRequest());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {Observable, Observer} from 'rxjs';
|
|
||||||
|
|
||||||
import {ResponseOptions} from '../base_response_options';
|
|
||||||
import {ReadyState, RequestMethod, ResponseType} from '../enums';
|
|
||||||
import {Connection, ConnectionBackend} from '../interfaces';
|
|
||||||
import {Request} from '../static_request';
|
|
||||||
import {Response} from '../static_response';
|
|
||||||
|
|
||||||
import {BrowserJsonp} from './browser_jsonp';
|
|
||||||
|
|
||||||
const JSONP_ERR_NO_CALLBACK = 'JSONP injected script did not invoke callback.';
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
export class JSONPConnection implements Connection {
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
private _id!: string;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
private _script!: Element;
|
|
||||||
private _responseData: any;
|
|
||||||
private _finished: boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link ReadyState} of this request.
|
|
||||||
*/
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
readyState!: ReadyState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The outgoing HTTP request.
|
|
||||||
*/
|
|
||||||
request: Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An observable that completes with the response, when the request is finished.
|
|
||||||
*/
|
|
||||||
response: Observable<Response>;
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
constructor(
|
|
||||||
req: Request, private _dom: BrowserJsonp, private baseResponseOptions?: ResponseOptions) {
|
|
||||||
if (req.method !== RequestMethod.Get) {
|
|
||||||
throw new TypeError(JSONP_ERR_WRONG_METHOD);
|
|
||||||
}
|
|
||||||
this.request = req;
|
|
||||||
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
|
|
||||||
this.readyState = ReadyState.Loading;
|
|
||||||
const id = this._id = _dom.nextRequestID();
|
|
||||||
|
|
||||||
_dom.exposeConnection(id, this);
|
|
||||||
|
|
||||||
// Workaround Dart
|
|
||||||
// url = url.replace(/=JSONP_CALLBACK(&|$)/, `generated method`);
|
|
||||||
const callback = _dom.requestCallback(this._id);
|
|
||||||
let url: string = 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}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const script = this._script = _dom.build(url);
|
|
||||||
|
|
||||||
const onLoad = (event: Event) => {
|
|
||||||
if (this.readyState === ReadyState.Cancelled) return;
|
|
||||||
this.readyState = ReadyState.Done;
|
|
||||||
_dom.cleanup(script);
|
|
||||||
if (!this._finished) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let responseOptions = new ResponseOptions({body: this._responseData, url});
|
|
||||||
if (this.baseResponseOptions) {
|
|
||||||
responseOptions = this.baseResponseOptions.merge(responseOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
responseObserver.next(new Response(responseOptions));
|
|
||||||
responseObserver.complete();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onError = (error: Error) => {
|
|
||||||
if (this.readyState === ReadyState.Cancelled) return;
|
|
||||||
this.readyState = ReadyState.Done;
|
|
||||||
_dom.cleanup(script);
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
finished(data?: any) {
|
|
||||||
// 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
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class JSONPBackend extends ConnectionBackend {
|
|
||||||
/** @internal */
|
|
||||||
constructor(private _browserJSONP: BrowserJsonp, private _baseResponseOptions: ResponseOptions) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
createConnection(request: Request): JSONPConnection {
|
|
||||||
return new JSONPConnection(request, this._browserJSONP, this._baseResponseOptions);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,245 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {Observable, Observer} from 'rxjs';
|
|
||||||
import {ResponseOptions} from '../base_response_options';
|
|
||||||
import {ContentType, ReadyState, RequestMethod, ResponseContentType, ResponseType} from '../enums';
|
|
||||||
import {Headers} from '../headers';
|
|
||||||
import {getResponseURL, isSuccess} from '../http_utils';
|
|
||||||
import {Connection, ConnectionBackend, XSRFStrategy} from '../interfaces';
|
|
||||||
import {Request} from '../static_request';
|
|
||||||
import {Response} from '../static_response';
|
|
||||||
import {BrowserXhr} from './browser_xhr';
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
export class XHRConnection implements Connection {
|
|
||||||
request: Request;
|
|
||||||
/**
|
|
||||||
* Response {@link EventEmitter} which emits a single {@link Response} value on load event of
|
|
||||||
* `XMLHttpRequest`.
|
|
||||||
*/
|
|
||||||
response: Observable<Response>;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
readyState!: ReadyState;
|
|
||||||
constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) {
|
|
||||||
this.request = req;
|
|
||||||
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
|
|
||||||
const _xhr: XMLHttpRequest = browserXHR.build();
|
|
||||||
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
|
|
||||||
if (req.withCredentials != null) {
|
|
||||||
_xhr.withCredentials = req.withCredentials;
|
|
||||||
}
|
|
||||||
// load event handler
|
|
||||||
const onLoad = () => {
|
|
||||||
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
|
||||||
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
|
|
||||||
|
|
||||||
let body: any = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers: Headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
|
||||||
// IE 9 does not provide the way to get URL of response
|
|
||||||
const url = getResponseURL(_xhr) || req.url;
|
|
||||||
const statusText: string = _xhr.statusText || 'OK';
|
|
||||||
|
|
||||||
let responseOptions = new ResponseOptions({body, status, headers, statusText, url});
|
|
||||||
if (baseResponseOptions != null) {
|
|
||||||
responseOptions = baseResponseOptions.merge(responseOptions);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
const onError = (err: ErrorEvent) => {
|
|
||||||
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(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();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDetectedContentType(req: any /** TODO Request */, _xhr: any /** 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:
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
export class CookieXSRFStrategy implements XSRFStrategy {
|
|
||||||
constructor(
|
|
||||||
private _cookieName: string = 'XSRF-TOKEN', private _headerName: string = 'X-XSRF-TOKEN') {}
|
|
||||||
|
|
||||||
configureRequest(req: Request): void {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class XHRBackend implements ConnectionBackend {
|
|
||||||
constructor(
|
|
||||||
private _browserXHR: BrowserXhr, private _baseResponseOptions: ResponseOptions,
|
|
||||||
private _xsrfStrategy: XSRFStrategy) {}
|
|
||||||
|
|
||||||
createConnection(request: Request): XHRConnection {
|
|
||||||
this._xsrfStrategy.configureRequest(request);
|
|
||||||
return new XHRConnection(request, this._browserXHR, this._baseResponseOptions);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,216 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
|
|
||||||
import {RequestMethod, ResponseContentType} from './enums';
|
|
||||||
import {Headers} from './headers';
|
|
||||||
import {normalizeMethodName} from './http_utils';
|
|
||||||
import {RequestOptionsArgs} from './interfaces';
|
|
||||||
import {URLSearchParams} from './url_search_params';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
export class RequestOptions {
|
|
||||||
/**
|
|
||||||
* Http method with which to execute a {@link Request}.
|
|
||||||
* Acceptable methods are defined in the {@link RequestMethod} enum.
|
|
||||||
*/
|
|
||||||
method: RequestMethod|string|null;
|
|
||||||
/**
|
|
||||||
* {@link Headers} to be attached to a {@link Request}.
|
|
||||||
*/
|
|
||||||
headers: Headers|null;
|
|
||||||
/**
|
|
||||||
* Body to be used when creating a {@link Request}.
|
|
||||||
*/
|
|
||||||
body: any;
|
|
||||||
/**
|
|
||||||
* Url with which to perform a {@link Request}.
|
|
||||||
*/
|
|
||||||
url: string|null;
|
|
||||||
/**
|
|
||||||
* Search parameters to be included in a {@link Request}.
|
|
||||||
*/
|
|
||||||
params: URLSearchParams;
|
|
||||||
/**
|
|
||||||
* @deprecated from 4.0.0. Use params instead.
|
|
||||||
*/
|
|
||||||
get search(): URLSearchParams {
|
|
||||||
return this.params;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @deprecated from 4.0.0. Use params instead.
|
|
||||||
*/
|
|
||||||
set search(params: URLSearchParams) {
|
|
||||||
this.params = params;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Enable use credentials for a {@link Request}.
|
|
||||||
*/
|
|
||||||
withCredentials: boolean|null;
|
|
||||||
/*
|
|
||||||
* Select a buffer to store the response, such as ArrayBuffer, Blob, Json (or Document)
|
|
||||||
*/
|
|
||||||
responseType: ResponseContentType|null;
|
|
||||||
|
|
||||||
// TODO(Dzmitry): remove search when this.search is removed
|
|
||||||
constructor(opts: RequestOptionsArgs = {}) {
|
|
||||||
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
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
merge(options?: RequestOptionsArgs): RequestOptions {
|
|
||||||
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 _mergeSearchParams(params?: string|URLSearchParams|{[key: string]: any | any[]}|
|
|
||||||
null): URLSearchParams {
|
|
||||||
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 _parseParams(objParams: {[key: string]: any|any[]} = {}): URLSearchParams {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
Object.keys(objParams).forEach((key: string) => {
|
|
||||||
const value: any|any[] = objParams[key];
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
value.forEach((item: any) => this._appendParam(key, item, params));
|
|
||||||
} else {
|
|
||||||
this._appendParam(key, value, params);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _appendParam(key: string, value: any, params: URLSearchParams): void {
|
|
||||||
if (typeof value !== 'string') {
|
|
||||||
value = JSON.stringify(value);
|
|
||||||
}
|
|
||||||
params.append(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of {@link RequestOptions}, with default values.
|
|
||||||
*
|
|
||||||
* Default values:
|
|
||||||
* * method: {@link RequestMethod RequestMethod.Get}
|
|
||||||
* * headers: empty {@link Headers} object
|
|
||||||
*
|
|
||||||
* This class could be extended and bound to the {@link RequestOptions} class
|
|
||||||
* when configuring an {@link Injector}, in order to override the default options
|
|
||||||
* used by {@link Http} to create and send {@link Request Requests}.
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* import {BaseRequestOptions, RequestOptions} from '@angular/http';
|
|
||||||
*
|
|
||||||
* class MyOptions extends BaseRequestOptions {
|
|
||||||
* search: string = 'coreTeam=true';
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* {provide: RequestOptions, useClass: MyOptions};
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* The options could also be extended when manually creating a {@link Request}
|
|
||||||
* object.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* import {BaseRequestOptions, Request, RequestMethod} from '@angular/http';
|
|
||||||
*
|
|
||||||
* const options = new BaseRequestOptions();
|
|
||||||
* const req = new Request(options.merge({
|
|
||||||
* method: RequestMethod.Post,
|
|
||||||
* 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
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class BaseRequestOptions extends RequestOptions {
|
|
||||||
constructor() {
|
|
||||||
super({method: RequestMethod.Get, headers: new Headers()});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
|
|
||||||
import {ResponseType} from './enums';
|
|
||||||
import {Headers} from './headers';
|
|
||||||
import {ResponseOptionsArgs} from './interfaces';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
export class ResponseOptions {
|
|
||||||
// TODO: FormData | Blob
|
|
||||||
/**
|
|
||||||
* String, Object, ArrayBuffer or Blob representing the body of the {@link Response}.
|
|
||||||
*/
|
|
||||||
body: string|Object|ArrayBuffer|Blob|null;
|
|
||||||
/**
|
|
||||||
* Http {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html status code}
|
|
||||||
* associated with the response.
|
|
||||||
*/
|
|
||||||
status: number|null;
|
|
||||||
/**
|
|
||||||
* Response {@link Headers headers}
|
|
||||||
*/
|
|
||||||
headers: Headers|null;
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
statusText: string|null;
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
type: ResponseType|null;
|
|
||||||
url: string|null;
|
|
||||||
constructor(opts: ResponseOptionsArgs = {}) {
|
|
||||||
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
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
merge(options?: ResponseOptionsArgs): ResponseOptions {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class BaseResponseOptions extends ResponseOptions {
|
|
||||||
constructor() {
|
|
||||||
super({status: 200, statusText: 'Ok', type: ResponseType.Default, headers: new Headers()});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {stringToArrayBuffer} from './http_utils';
|
|
||||||
import {URLSearchParams} from './url_search_params';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP request body used by both {@link Request} and {@link Response}
|
|
||||||
* https://fetch.spec.whatwg.org/#body
|
|
||||||
*/
|
|
||||||
export abstract class Body {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
protected _body: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to return body as parsed `JSON` object, or raises an exception.
|
|
||||||
*/
|
|
||||||
json(): any {
|
|
||||||
if (typeof this._body === 'string') {
|
|
||||||
return JSON.parse(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).
|
|
||||||
*/
|
|
||||||
text(encodingHint: 'legacy'|'iso-8859' = 'legacy'): string {
|
|
||||||
if (this._body instanceof URLSearchParams) {
|
|
||||||
return this._body.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._body instanceof ArrayBuffer) {
|
|
||||||
switch (encodingHint) {
|
|
||||||
case 'legacy':
|
|
||||||
// TODO: Argument of type 'Uint16Array' is not assignable to parameter of type
|
|
||||||
// 'number[]'.
|
|
||||||
return String.fromCharCode.apply(null, new Uint16Array(this._body) as any);
|
|
||||||
case 'iso-8859':
|
|
||||||
// TODO: Argument of type 'Uint8Array' is not assignable to parameter of type
|
|
||||||
// 'number[]'.
|
|
||||||
return String.fromCharCode.apply(null, new Uint8Array(this._body) as any);
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
arrayBuffer(): ArrayBuffer {
|
|
||||||
if (this._body instanceof ArrayBuffer) {
|
|
||||||
return this._body;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringToArrayBuffer(this.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request's body as a Blob, assuming that body exists.
|
|
||||||
*/
|
|
||||||
blob(): Blob {
|
|
||||||
if (this._body instanceof Blob) {
|
|
||||||
return 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');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supported http methods.
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export enum RequestMethod {
|
|
||||||
Get,
|
|
||||||
Post,
|
|
||||||
Put,
|
|
||||||
Delete,
|
|
||||||
Options,
|
|
||||||
Head,
|
|
||||||
Patch
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All possible states in which a connection can be, based on
|
|
||||||
* [States](http://www.w3.org/TR/XMLHttpRequest/#states) from the `XMLHttpRequest` spec, but with an
|
|
||||||
* additional "CANCELLED" state.
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export enum ReadyState {
|
|
||||||
Unsent,
|
|
||||||
Open,
|
|
||||||
HeadersReceived,
|
|
||||||
Loading,
|
|
||||||
Done,
|
|
||||||
Cancelled
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acceptable response types to be associated with a {@link Response}, based on
|
|
||||||
* [ResponseType](https://fetch.spec.whatwg.org/#responsetype) from the Fetch spec.
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export enum ResponseType {
|
|
||||||
Basic,
|
|
||||||
Cors,
|
|
||||||
Default,
|
|
||||||
Error,
|
|
||||||
Opaque
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supported content type to be automatically associated with a {@link Request}.
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
*/
|
|
||||||
export enum ContentType {
|
|
||||||
NONE,
|
|
||||||
JSON,
|
|
||||||
FORM,
|
|
||||||
FORM_DATA,
|
|
||||||
TEXT,
|
|
||||||
BLOB,
|
|
||||||
ARRAY_BUFFER
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define which buffer to use to store the response
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export enum ResponseContentType {
|
|
||||||
Text,
|
|
||||||
Json,
|
|
||||||
ArrayBuffer,
|
|
||||||
Blob
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
export class Headers {
|
|
||||||
/** @internal header names are lower case */
|
|
||||||
_headers: Map<string, string[]> = new Map();
|
|
||||||
/** @internal map lower case names to actual names */
|
|
||||||
_normalizedNames: Map<string, string> = new Map();
|
|
||||||
|
|
||||||
// TODO(vicb): any -> string|string[]
|
|
||||||
constructor(headers?: Headers|{[name: string]: any}|null) {
|
|
||||||
if (!headers) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headers instanceof Headers) {
|
|
||||||
headers.forEach((values: string[], name: string) => {
|
|
||||||
values.forEach(value => this.append(name, value));
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(headers).forEach((name: string) => {
|
|
||||||
const values: string[] = 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
|
|
||||||
*/
|
|
||||||
static fromResponseHeaderString(headersString: string): Headers {
|
|
||||||
const headers = new Headers();
|
|
||||||
|
|
||||||
headersString.split('\n').forEach(line => {
|
|
||||||
const index = line.indexOf(':');
|
|
||||||
if (index > 0) {
|
|
||||||
const name = line.slice(0, index);
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
append(name: string, value: string): void {
|
|
||||||
const values = this.getAll(name);
|
|
||||||
|
|
||||||
if (values === null) {
|
|
||||||
this.set(name, value);
|
|
||||||
} else {
|
|
||||||
values.push(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes all header values for the given name.
|
|
||||||
*/
|
|
||||||
delete(name: string): void {
|
|
||||||
const lcName = name.toLowerCase();
|
|
||||||
this._normalizedNames.delete(lcName);
|
|
||||||
this._headers.delete(lcName);
|
|
||||||
}
|
|
||||||
|
|
||||||
forEach(fn: (values: string[], name: string|undefined, headers: Map<string, string[]>) => void):
|
|
||||||
void {
|
|
||||||
this._headers.forEach(
|
|
||||||
(values, lcName) => fn(values, this._normalizedNames.get(lcName), this._headers));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns first header that matches given name.
|
|
||||||
*/
|
|
||||||
get(name: string): string|null {
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
has(name: string): boolean {
|
|
||||||
return this._headers.has(name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the names of the headers
|
|
||||||
*/
|
|
||||||
keys(): string[] {
|
|
||||||
return Array.from(this._normalizedNames.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets or overrides header value for given name.
|
|
||||||
*/
|
|
||||||
set(name: string, value: string|string[]): void {
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
values(): string[][] {
|
|
||||||
return Array.from(this._headers.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns string of all headers.
|
|
||||||
*/
|
|
||||||
// TODO(vicb): returns {[name: string]: string[]}
|
|
||||||
toJSON(): {[name: string]: any} {
|
|
||||||
const serialized: {[name: string]: string[]} = {};
|
|
||||||
|
|
||||||
this._headers.forEach((values: string[], name: string) => {
|
|
||||||
const split: string[] = [];
|
|
||||||
values.forEach(v => split.push(...v.split(',')));
|
|
||||||
serialized[this._normalizedNames.get(name)!] = split;
|
|
||||||
});
|
|
||||||
|
|
||||||
return serialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns list of header values for a given name.
|
|
||||||
*/
|
|
||||||
getAll(name: string): string[]|null {
|
|
||||||
return this.has(name) ? this._headers.get(name.toLowerCase()) || null : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is not implemented.
|
|
||||||
*/
|
|
||||||
entries() {
|
|
||||||
throw new Error('"entries" method is not implemented on Headers class');
|
|
||||||
}
|
|
||||||
|
|
||||||
private mayBeSetNormalizedName(name: string): void {
|
|
||||||
const lcName = name.toLowerCase();
|
|
||||||
|
|
||||||
if (!this._normalizedNames.has(lcName)) {
|
|
||||||
this._normalizedNames.set(lcName, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,230 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {Observable} from 'rxjs';
|
|
||||||
|
|
||||||
import {BaseRequestOptions, RequestOptions} from './base_request_options';
|
|
||||||
import {RequestMethod} from './enums';
|
|
||||||
import {ConnectionBackend, RequestArgs, RequestOptionsArgs} from './interfaces';
|
|
||||||
import {Request} from './static_request';
|
|
||||||
import {Response} from './static_response';
|
|
||||||
|
|
||||||
function httpRequest(backend: ConnectionBackend, request: Request): Observable<Response> {
|
|
||||||
return backend.createConnection(request).response;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeOptions(
|
|
||||||
defaultOpts: BaseRequestOptions, providedOpts: RequestOptionsArgs|undefined,
|
|
||||||
method: RequestMethod, url: string): RequestArgs {
|
|
||||||
const newOptions = defaultOpts;
|
|
||||||
if (providedOpts) {
|
|
||||||
// Hack so Dart can used named parameters
|
|
||||||
return newOptions.merge(new RequestOptions({
|
|
||||||
method: providedOpts.method || method,
|
|
||||||
url: providedOpts.url || url,
|
|
||||||
search: providedOpts.search,
|
|
||||||
params: providedOpts.params,
|
|
||||||
headers: providedOpts.headers,
|
|
||||||
body: providedOpts.body,
|
|
||||||
withCredentials: providedOpts.withCredentials,
|
|
||||||
responseType: providedOpts.responseType
|
|
||||||
})) as RequestArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newOptions.merge(new RequestOptions({method, url})) as RequestArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs http requests using `XMLHttpRequest` as the default backend.
|
|
||||||
*
|
|
||||||
* `Http` is available as an injectable class, with methods to perform http requests. Calling
|
|
||||||
* `request` returns an `Observable` which will emit a single {@link Response} when a
|
|
||||||
* response is received.
|
|
||||||
*
|
|
||||||
* @usageNotes
|
|
||||||
* ### Example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* import {Http, HTTP_PROVIDERS} from '@angular/http';
|
|
||||||
* import {map} from 'rxjs/operators';
|
|
||||||
*
|
|
||||||
* @Component({
|
|
||||||
* selector: 'http-app',
|
|
||||||
* viewProviders: [HTTP_PROVIDERS],
|
|
||||||
* templateUrl: 'people.html'
|
|
||||||
* })
|
|
||||||
* class PeopleComponent {
|
|
||||||
* constructor(http: Http) {
|
|
||||||
* http.get('people.json')
|
|
||||||
* // Call map on the response observable to get the parsed people object
|
|
||||||
* .pipe(map(res => res.json()))
|
|
||||||
* // Subscribe to the observable to get the parsed people object and attach it to the
|
|
||||||
* // component
|
|
||||||
* .subscribe(people => this.people = people);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* http.get('people.json').subscribe((res:Response) => this.people = res.json());
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* The default construct used to perform requests, `XMLHttpRequest`, is abstracted as a "Backend" (
|
|
||||||
* {@link XHRBackend} in this case), which could be mocked with dependency injection by replacing
|
|
||||||
* the {@link XHRBackend} provider, as in the following example:
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* import {BaseRequestOptions, Http} from '@angular/http';
|
|
||||||
* import {MockBackend} from '@angular/http/testing';
|
|
||||||
* var injector = Injector.resolveAndCreate([
|
|
||||||
* BaseRequestOptions,
|
|
||||||
* MockBackend,
|
|
||||||
* {provide: Http, useFactory:
|
|
||||||
* function(backend, defaultOptions) {
|
|
||||||
* return new Http(backend, defaultOptions);
|
|
||||||
* },
|
|
||||||
* deps: [MockBackend, BaseRequestOptions]}
|
|
||||||
* ]);
|
|
||||||
* var http = injector.get(Http);
|
|
||||||
* http.get('request-from-mock-backend.json').subscribe((res:Response) => doSomething(res));
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class Http {
|
|
||||||
constructor(protected _backend: ConnectionBackend, protected _defaultOptions: RequestOptions) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs any type of http request. First argument is required, and can either be a url or
|
|
||||||
* a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}
|
|
||||||
* object can be provided as the 2nd argument. The options object will be merged with the values
|
|
||||||
* of {@link BaseRequestOptions} before performing the request.
|
|
||||||
*/
|
|
||||||
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
let responseObservable: any;
|
|
||||||
if (typeof url === 'string') {
|
|
||||||
responseObservable = httpRequest(
|
|
||||||
this._backend,
|
|
||||||
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, url)));
|
|
||||||
} else if (url instanceof Request) {
|
|
||||||
responseObservable = httpRequest(this._backend, url);
|
|
||||||
} else {
|
|
||||||
throw new Error('First argument must be a url string or Request instance.');
|
|
||||||
}
|
|
||||||
return responseObservable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `get` http method.
|
|
||||||
*/
|
|
||||||
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(
|
|
||||||
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `post` http method.
|
|
||||||
*/
|
|
||||||
post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(new Request(mergeOptions(
|
|
||||||
this._defaultOptions.merge(new RequestOptions({body: body})), options, RequestMethod.Post,
|
|
||||||
url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `put` http method.
|
|
||||||
*/
|
|
||||||
put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(new Request(mergeOptions(
|
|
||||||
this._defaultOptions.merge(new RequestOptions({body: body})), options, RequestMethod.Put,
|
|
||||||
url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `delete` http method.
|
|
||||||
*/
|
|
||||||
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(
|
|
||||||
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Delete, url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `patch` http method.
|
|
||||||
*/
|
|
||||||
patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(new Request(mergeOptions(
|
|
||||||
this._defaultOptions.merge(new RequestOptions({body: body})), options, RequestMethod.Patch,
|
|
||||||
url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `head` http method.
|
|
||||||
*/
|
|
||||||
head(url: string, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(
|
|
||||||
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Head, url)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a request with `options` http method.
|
|
||||||
*/
|
|
||||||
options(url: string, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
return this.request(
|
|
||||||
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Options, url)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class Jsonp extends Http {
|
|
||||||
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
|
|
||||||
super(backend, defaultOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs any type of http request. First argument is required, and can either be a url or
|
|
||||||
* a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}
|
|
||||||
* object can be provided as the 2nd argument. The options object will be merged with the values
|
|
||||||
* of {@link BaseRequestOptions} before performing the request.
|
|
||||||
*
|
|
||||||
* @security Regular XHR is the safest alternative to JSONP for most applications, and is
|
|
||||||
* supported by all current browsers. Because JSONP creates a `<script>` element with
|
|
||||||
* contents retrieved from a remote source, attacker-controlled data introduced by an untrusted
|
|
||||||
* source could expose your application to XSS risks. Data exposed by JSONP may also be
|
|
||||||
* readable by malicious third-party websites. In addition, JSONP introduces potential risk for
|
|
||||||
* future security issues (e.g. content sniffing). For more detail, see the
|
|
||||||
* [Security Guide](http://g.co/ng/security).
|
|
||||||
*/
|
|
||||||
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
let responseObservable: any;
|
|
||||||
if (typeof url === 'string') {
|
|
||||||
url = new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, url));
|
|
||||||
}
|
|
||||||
if (url instanceof Request) {
|
|
||||||
if (url.method !== RequestMethod.Get) {
|
|
||||||
throw new Error('JSONP requests must use GET request method.');
|
|
||||||
}
|
|
||||||
responseObservable = httpRequest(this._backend, url);
|
|
||||||
} else {
|
|
||||||
throw new Error('First argument must be a url string or Request instance.');
|
|
||||||
}
|
|
||||||
return responseObservable;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* The http module provides services to perform http requests. To get started, see the {@link Http}
|
|
||||||
* class.
|
|
||||||
*/
|
|
||||||
import {NgModule} from '@angular/core';
|
|
||||||
|
|
||||||
import {BrowserJsonp} from './backends/browser_jsonp';
|
|
||||||
import {BrowserXhr} from './backends/browser_xhr';
|
|
||||||
import {JSONPBackend} from './backends/jsonp_backend';
|
|
||||||
import {CookieXSRFStrategy, XHRBackend} from './backends/xhr_backend';
|
|
||||||
import {BaseRequestOptions, RequestOptions} from './base_request_options';
|
|
||||||
import {BaseResponseOptions, ResponseOptions} from './base_response_options';
|
|
||||||
import {Http, Jsonp} from './http';
|
|
||||||
import {XSRFStrategy} from './interfaces';
|
|
||||||
|
|
||||||
|
|
||||||
export function _createDefaultCookieXSRFStrategy() {
|
|
||||||
return new CookieXSRFStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function httpFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions): Http {
|
|
||||||
return new Http(xhrBackend, requestOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function jsonpFactory(jsonpBackend: JSONPBackend, requestOptions: RequestOptions): Jsonp {
|
|
||||||
return new Jsonp(jsonpBackend, requestOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The module that includes http's providers
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@NgModule({
|
|
||||||
providers: [
|
|
||||||
// TODO(pascal): use factory type annotations once supported in DI
|
|
||||||
// issue: https://github.com/angular/angular/issues/3183
|
|
||||||
{provide: Http, useFactory: httpFactory, deps: [XHRBackend, RequestOptions]},
|
|
||||||
BrowserXhr,
|
|
||||||
{provide: RequestOptions, useClass: BaseRequestOptions},
|
|
||||||
{provide: ResponseOptions, useClass: BaseResponseOptions},
|
|
||||||
XHRBackend,
|
|
||||||
{provide: XSRFStrategy, useFactory: _createDefaultCookieXSRFStrategy},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class HttpModule {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The module that includes jsonp's providers
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/api/common/http/HttpClient#jsonp
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@NgModule({
|
|
||||||
providers: [
|
|
||||||
// TODO(pascal): use factory type annotations once supported in DI
|
|
||||||
// issue: https://github.com/angular/angular/issues/3183
|
|
||||||
{provide: Jsonp, useFactory: jsonpFactory, deps: [JSONPBackend, RequestOptions]},
|
|
||||||
BrowserJsonp,
|
|
||||||
{provide: RequestOptions, useClass: BaseRequestOptions},
|
|
||||||
{provide: ResponseOptions, useClass: BaseResponseOptions},
|
|
||||||
JSONPBackend,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class JsonpModule {
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {RequestMethod} from './enums';
|
|
||||||
|
|
||||||
export function normalizeMethodName(method: string|RequestMethod): RequestMethod {
|
|
||||||
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.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);
|
|
||||||
|
|
||||||
export function getResponseURL(xhr: any): string|null {
|
|
||||||
if ('responseURL' in xhr) {
|
|
||||||
return xhr.responseURL;
|
|
||||||
}
|
|
||||||
if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
|
|
||||||
return xhr.getResponseHeader('X-Request-URL');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function stringToArrayBuffer8(input: String): ArrayBuffer {
|
|
||||||
const view = new Uint8Array(input.length);
|
|
||||||
for (let i = 0, strLen = input.length; i < strLen; i++) {
|
|
||||||
view[i] = input.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return view.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function stringToArrayBuffer(input: String): ArrayBuffer {
|
|
||||||
const view = new Uint16Array(input.length);
|
|
||||||
for (let i = 0, strLen = input.length; i < strLen; i++) {
|
|
||||||
view[i] = input.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return view.buffer;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
export {BrowserXhr} from './backends/browser_xhr';
|
|
||||||
export {JSONPBackend, JSONPConnection} from './backends/jsonp_backend';
|
|
||||||
export {CookieXSRFStrategy, XHRBackend, XHRConnection} from './backends/xhr_backend';
|
|
||||||
export {BaseRequestOptions, RequestOptions} from './base_request_options';
|
|
||||||
export {BaseResponseOptions, ResponseOptions} from './base_response_options';
|
|
||||||
export {ReadyState, RequestMethod, ResponseContentType, ResponseType} from './enums';
|
|
||||||
export {Headers} from './headers';
|
|
||||||
export {Http, Jsonp} from './http';
|
|
||||||
export {HttpModule, JsonpModule} from './http_module';
|
|
||||||
export {Connection, ConnectionBackend, RequestOptionsArgs, ResponseOptionsArgs, XSRFStrategy} from './interfaces';
|
|
||||||
export {Request} from './static_request';
|
|
||||||
export {Response} from './static_response';
|
|
||||||
export {QueryEncoder, URLSearchParams} from './url_search_params';
|
|
||||||
export {VERSION} from './version';
|
|
|
@ -1,91 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ReadyState, RequestMethod, ResponseContentType, ResponseType} from './enums';
|
|
||||||
import {Headers} from './headers';
|
|
||||||
import {Request} from './static_request';
|
|
||||||
import {URLSearchParams} from './url_search_params';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
export abstract class ConnectionBackend {
|
|
||||||
abstract createConnection(request: any): Connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class from which real connections are derived.
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export abstract class Connection {
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
readyState!: ReadyState;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
request!: Request;
|
|
||||||
response: any; // TODO: generic of <Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An XSRFStrategy configures XSRF protection (e.g. via headers) on an HTTP request.
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export abstract class XSRFStrategy {
|
|
||||||
abstract configureRequest(req: Request): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for options to construct a RequestOptions, based on
|
|
||||||
* [RequestInit](https://fetch.spec.whatwg.org/#requestinit) from the Fetch spec.
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export interface RequestOptionsArgs {
|
|
||||||
url?: string|null;
|
|
||||||
method?: string|RequestMethod|null;
|
|
||||||
/** @deprecated from 4.0.0. Use params instead. */
|
|
||||||
search?: string|URLSearchParams|{[key: string]: any | any[]}|null;
|
|
||||||
params?: string|URLSearchParams|{[key: string]: any | any[]}|null;
|
|
||||||
headers?: Headers|null;
|
|
||||||
body?: any;
|
|
||||||
withCredentials?: boolean|null;
|
|
||||||
responseType?: ResponseContentType|null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required structure when constructing new Request();
|
|
||||||
*/
|
|
||||||
export interface RequestArgs extends RequestOptionsArgs {
|
|
||||||
url: string|null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for options to construct a Response, based on
|
|
||||||
* [ResponseInit](https://fetch.spec.whatwg.org/#responseinit) from the Fetch spec.
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export interface ResponseOptionsArgs {
|
|
||||||
body?: string|Object|FormData|ArrayBuffer|Blob|null;
|
|
||||||
status?: number|null;
|
|
||||||
statusText?: string|null;
|
|
||||||
headers?: Headers|null;
|
|
||||||
type?: ResponseType|null;
|
|
||||||
url?: string|null;
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Body} from './body';
|
|
||||||
import {ContentType, RequestMethod, ResponseContentType} from './enums';
|
|
||||||
import {Headers} from './headers';
|
|
||||||
import {normalizeMethodName} from './http_utils';
|
|
||||||
import {RequestArgs} from './interfaces';
|
|
||||||
import {URLSearchParams} from './url_search_params';
|
|
||||||
|
|
||||||
|
|
||||||
// TODO(jeffbcross): properly implement body accessors
|
|
||||||
/**
|
|
||||||
* Creates `Request` instances from provided values.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* `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.
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* import {Injectable, Injector} from '@angular/core';
|
|
||||||
* import {HTTP_PROVIDERS, Http, Request, RequestMethod} from '@angular/http';
|
|
||||||
*
|
|
||||||
* @Injectable()
|
|
||||||
* class AutoAuthenticator {
|
|
||||||
* constructor(public http:Http) {}
|
|
||||||
* request(url:string) {
|
|
||||||
* return this.http.request(new Request({
|
|
||||||
* method: RequestMethod.Get,
|
|
||||||
* url: url,
|
|
||||||
* search: 'password=123'
|
|
||||||
* }));
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, AutoAuthenticator]);
|
|
||||||
* var authenticator = injector.get(AutoAuthenticator);
|
|
||||||
* authenticator.request('people.json').subscribe(res => {
|
|
||||||
* //URL should have included '?password=123'
|
|
||||||
* console.log('people', res.json());
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export class Request extends Body {
|
|
||||||
/**
|
|
||||||
* Http method with which to perform the request.
|
|
||||||
*/
|
|
||||||
method: RequestMethod;
|
|
||||||
/**
|
|
||||||
* {@link Headers} instance
|
|
||||||
*/
|
|
||||||
headers: Headers;
|
|
||||||
/** Url of the remote resource */
|
|
||||||
url: string;
|
|
||||||
/** Type of the request body **/
|
|
||||||
private contentType: ContentType;
|
|
||||||
/** Enable use credentials */
|
|
||||||
withCredentials: boolean;
|
|
||||||
/** Buffer to store the response */
|
|
||||||
responseType: ResponseContentType;
|
|
||||||
constructor(requestOptions: RequestArgs) {
|
|
||||||
super();
|
|
||||||
// TODO: assert that url is present
|
|
||||||
const url = requestOptions.url;
|
|
||||||
this.url = requestOptions.url!;
|
|
||||||
const paramsArg = requestOptions.params || requestOptions.search;
|
|
||||||
if (paramsArg) {
|
|
||||||
let params: string;
|
|
||||||
if (typeof paramsArg === 'object' && !(paramsArg instanceof URLSearchParams)) {
|
|
||||||
params = urlEncodeParams(paramsArg).toString();
|
|
||||||
} else {
|
|
||||||
params = paramsArg.toString();
|
|
||||||
}
|
|
||||||
if (params.length > 0) {
|
|
||||||
let prefix = '?';
|
|
||||||
if (this.url.indexOf('?') != -1) {
|
|
||||||
prefix = (this.url[this.url.length - 1] == '&') ? '' : '&';
|
|
||||||
}
|
|
||||||
// TODO: just delete search-query-looking string in url?
|
|
||||||
this.url = url + prefix + params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._body = requestOptions.body;
|
|
||||||
this.method = normalizeMethodName(requestOptions.method!);
|
|
||||||
// TODO(jeffbcross): implement behavior
|
|
||||||
// Defaults to 'omit', consistent with browser
|
|
||||||
this.headers = new Headers(requestOptions.headers);
|
|
||||||
this.contentType = this.detectContentType();
|
|
||||||
this.withCredentials = requestOptions.withCredentials!;
|
|
||||||
this.responseType = requestOptions.responseType!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 this._body instanceof ArrayBuffer ? ContentType.ARRAY_BUFFER : ContentType.BLOB;
|
|
||||||
default:
|
|
||||||
return this.detectContentTypeFromBody();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the content type of request's body based on its type.
|
|
||||||
*/
|
|
||||||
detectContentTypeFromBody(): ContentType {
|
|
||||||
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:
|
|
||||||
return this.text();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function urlEncodeParams(params: {[key: string]: any}): URLSearchParams {
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
Object.keys(params).forEach(key => {
|
|
||||||
const value = params[key];
|
|
||||||
if (value && Array.isArray(value)) {
|
|
||||||
value.forEach(element => searchParams.append(key, element.toString()));
|
|
||||||
} else {
|
|
||||||
searchParams.append(key, value.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return searchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
const noop = function() {};
|
|
||||||
const w = typeof window == 'object' ? window : noop;
|
|
||||||
const FormData = (() => (w as any /** TODO #9100 */)['FormData'] || noop)();
|
|
||||||
const Blob = (() => (w as any /** TODO #9100 */)['Blob'] || noop)();
|
|
||||||
export const ArrayBuffer: ArrayBufferConstructor =
|
|
||||||
(() => (w as any /** TODO #9100 */)['ArrayBuffer'] || noop)();
|
|
|
@ -1,104 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import {ResponseOptions} from './base_response_options';
|
|
||||||
import {Body} from './body';
|
|
||||||
import {ResponseType} from './enums';
|
|
||||||
import {Headers} from './headers';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
export class Response extends Body {
|
|
||||||
/**
|
|
||||||
* One of "basic", "cors", "default", "error", or "opaque".
|
|
||||||
*
|
|
||||||
* Defaults to "default".
|
|
||||||
*/
|
|
||||||
type: ResponseType;
|
|
||||||
/**
|
|
||||||
* True if the response's status is within 200-299
|
|
||||||
*/
|
|
||||||
ok: boolean;
|
|
||||||
/**
|
|
||||||
* URL of response.
|
|
||||||
*
|
|
||||||
* Defaults to empty string.
|
|
||||||
*/
|
|
||||||
url: string;
|
|
||||||
/**
|
|
||||||
* Status code returned by server.
|
|
||||||
*
|
|
||||||
* Defaults to 200.
|
|
||||||
*/
|
|
||||||
status: number;
|
|
||||||
/**
|
|
||||||
* Text representing the corresponding reason phrase to the `status`, as defined in [ietf rfc 2616
|
|
||||||
* section 6.1.1](https://tools.ietf.org/html/rfc2616#section-6.1.1)
|
|
||||||
*
|
|
||||||
* Defaults to "OK"
|
|
||||||
*/
|
|
||||||
statusText: string|null;
|
|
||||||
/**
|
|
||||||
* Non-standard property
|
|
||||||
*
|
|
||||||
* Denotes how many of the response body's bytes have been loaded, for example if the response is
|
|
||||||
* the result of a progress event.
|
|
||||||
*/
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
bytesLoaded!: number;
|
|
||||||
/**
|
|
||||||
* Non-standard property
|
|
||||||
*
|
|
||||||
* Denotes how many bytes are expected in the final response body.
|
|
||||||
*/
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
totalBytes!: number;
|
|
||||||
/**
|
|
||||||
* Headers object based on the `Headers` class in the [Fetch
|
|
||||||
* Spec](https://fetch.spec.whatwg.org/#headers-class).
|
|
||||||
*/
|
|
||||||
headers: Headers|null;
|
|
||||||
|
|
||||||
constructor(responseOptions: ResponseOptions) {
|
|
||||||
super();
|
|
||||||
this._body = responseOptions.body;
|
|
||||||
this.status = responseOptions.status!;
|
|
||||||
this.ok = (this.status >= 200 && this.status <= 299);
|
|
||||||
this.statusText = responseOptions.statusText;
|
|
||||||
this.headers = responseOptions.headers;
|
|
||||||
this.type = responseOptions.type!;
|
|
||||||
this.url = responseOptions.url!;
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
return `Response with status: ${this.status} ${this.statusText} for URL: ${this.url}`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
function paramParser(rawParams: string = ''): Map<string, string[]> {
|
|
||||||
const map = new Map<string, string[]>();
|
|
||||||
if (rawParams.length > 0) {
|
|
||||||
const params: string[] = rawParams.split('&');
|
|
||||||
params.forEach((param: string) => {
|
|
||||||
const eqIdx = param.indexOf('=');
|
|
||||||
const [key, val]: string[] =
|
|
||||||
eqIdx == -1 ? [param, ''] : [param.slice(0, eqIdx), param.slice(eqIdx + 1)];
|
|
||||||
const list = map.get(key) || [];
|
|
||||||
list.push(val);
|
|
||||||
map.set(key, list);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
**/
|
|
||||||
export class QueryEncoder {
|
|
||||||
encodeKey(key: string): string {
|
|
||||||
return standardEncoding(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
encodeValue(value: string): string {
|
|
||||||
return standardEncoding(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function standardEncoding(v: string): string {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
export class URLSearchParams {
|
|
||||||
paramsMap: Map<string, string[]>;
|
|
||||||
constructor(
|
|
||||||
public rawParams: string = '', private queryEncoder: QueryEncoder = new QueryEncoder()) {
|
|
||||||
this.paramsMap = paramParser(rawParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
clone(): URLSearchParams {
|
|
||||||
const clone = new URLSearchParams('', this.queryEncoder);
|
|
||||||
clone.appendAll(this);
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
has(param: string): boolean {
|
|
||||||
return this.paramsMap.has(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(param: string): string|null {
|
|
||||||
const storedParam = this.paramsMap.get(param);
|
|
||||||
|
|
||||||
return Array.isArray(storedParam) ? storedParam[0] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAll(param: string): string[] {
|
|
||||||
return this.paramsMap.get(param) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(param: string, val: string) {
|
|
||||||
if (val === void 0 || val === null) {
|
|
||||||
this.delete(param);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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
|
|
||||||
setAll(searchParams: URLSearchParams) {
|
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
|
||||||
const list = this.paramsMap.get(param) || [];
|
|
||||||
list.length = 0;
|
|
||||||
list.push(value[0]);
|
|
||||||
this.paramsMap.set(param, list);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
append(param: string, val: string): void {
|
|
||||||
if (val === void 0 || val === null) return;
|
|
||||||
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
|
|
||||||
appendAll(searchParams: URLSearchParams) {
|
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
|
||||||
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
|
|
||||||
replaceAll(searchParams: URLSearchParams) {
|
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
const paramsList: string[] = [];
|
|
||||||
this.paramsMap.forEach((values, k) => {
|
|
||||||
values.forEach(
|
|
||||||
v => paramsList.push(
|
|
||||||
this.queryEncoder.encodeKey(k) + '=' + this.queryEncoder.encodeValue(v)));
|
|
||||||
});
|
|
||||||
return paramsList.join('&');
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(param: string): void {
|
|
||||||
this.paramsMap.delete(param);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Entry point for all public APIs of the common package.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Version} from '@angular/core';
|
|
||||||
/**
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export const VERSION = new Version('0.0.0-PLACEHOLDER');
|
|
|
@ -1,34 +0,0 @@
|
||||||
load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library")
|
|
||||||
|
|
||||||
ts_library(
|
|
||||||
name = "test_lib",
|
|
||||||
testonly = True,
|
|
||||||
srcs = glob(["**/*.ts"]),
|
|
||||||
# Visible to //:saucelabs_unit_tests_poc target
|
|
||||||
visibility = ["//:__pkg__"],
|
|
||||||
deps = [
|
|
||||||
"//packages/common",
|
|
||||||
"//packages/core",
|
|
||||||
"//packages/core/testing",
|
|
||||||
"//packages/http",
|
|
||||||
"//packages/http/testing",
|
|
||||||
"//packages/platform-browser",
|
|
||||||
"//packages/platform-browser/testing",
|
|
||||||
"@npm//rxjs",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
jasmine_node_test(
|
|
||||||
name = "test",
|
|
||||||
bootstrap = ["//tools/testing:node_es5"],
|
|
||||||
deps = [
|
|
||||||
":test_lib",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
karma_web_test_suite(
|
|
||||||
name = "test_web",
|
|
||||||
deps = [
|
|
||||||
":test_lib",
|
|
||||||
],
|
|
||||||
)
|
|
|
@ -1,174 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injector} from '@angular/core';
|
|
||||||
import {afterEach, AsyncTestCompleter, beforeEach, describe, inject, it, SpyObject} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {BrowserJsonp} from '@angular/http/src/backends/browser_jsonp';
|
|
||||||
import {JSONPBackend, JSONPConnection} from '@angular/http/src/backends/jsonp_backend';
|
|
||||||
import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options';
|
|
||||||
import {BaseResponseOptions, ResponseOptions} from '@angular/http/src/base_response_options';
|
|
||||||
import {ReadyState, RequestMethod, ResponseType} from '@angular/http/src/enums';
|
|
||||||
import {Request} from '@angular/http/src/static_request';
|
|
||||||
import {Response} from '@angular/http/src/static_response';
|
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
|
||||||
|
|
||||||
let existingScripts: MockBrowserJsonp[] = [];
|
|
||||||
|
|
||||||
class MockBrowserJsonp extends BrowserJsonp {
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
src!: string;
|
|
||||||
callbacks = new Map<string, (data: any) => any>();
|
|
||||||
|
|
||||||
addEventListener(type: string, cb: (data: any) => any) {
|
|
||||||
this.callbacks.set(type, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeEventListener(type: string, cb: Function) {
|
|
||||||
this.callbacks.delete(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(type: string, argument: any = {}) {
|
|
||||||
const cb = this.callbacks.get(type);
|
|
||||||
if (cb) {
|
|
||||||
cb(argument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
build(url: string) {
|
|
||||||
const script = new MockBrowserJsonp();
|
|
||||||
script.src = url;
|
|
||||||
existingScripts.push(script);
|
|
||||||
return script;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(node: any) { /* noop */
|
|
||||||
}
|
|
||||||
cleanup(node: any) { /* noop */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('JSONPBackend', () => {
|
|
||||||
let backend: JSONPBackend;
|
|
||||||
let sampleRequest: Request;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
const injector = Injector.create([
|
|
||||||
{provide: ResponseOptions, useClass: BaseResponseOptions, deps: []},
|
|
||||||
{provide: BrowserJsonp, useClass: MockBrowserJsonp, deps: []},
|
|
||||||
{provide: JSONPBackend, useClass: JSONPBackend, deps: [BrowserJsonp, ResponseOptions]}
|
|
||||||
]);
|
|
||||||
backend = injector.get(JSONPBackend);
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
sampleRequest =
|
|
||||||
new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
existingScripts = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a connection', () => {
|
|
||||||
let instance: JSONPConnection = undefined!;
|
|
||||||
expect(() => instance = backend.createConnection(sampleRequest)).not.toThrow();
|
|
||||||
expect(instance).toBeAnInstanceOf(JSONPConnection);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('JSONPConnection', () => {
|
|
||||||
it('should use the injected BaseResponseOptions to create the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new (JSONPConnection as any)(
|
|
||||||
sampleRequest, new MockBrowserJsonp(),
|
|
||||||
new ResponseOptions({type: ResponseType.Error}));
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.type).toBe(ResponseType.Error);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection.finished();
|
|
||||||
existingScripts[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should ignore load/callback when disposed',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
|
|
||||||
const spy = new SpyObject();
|
|
||||||
const loadSpy = spy.spy('load');
|
|
||||||
const errorSpy = spy.spy('error');
|
|
||||||
const returnSpy = spy.spy('cancelled');
|
|
||||||
|
|
||||||
const request = connection.response.subscribe(loadSpy, errorSpy, returnSpy);
|
|
||||||
request.unsubscribe();
|
|
||||||
|
|
||||||
connection.finished('Fake data');
|
|
||||||
existingScripts[0].dispatchEvent('load');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(connection.readyState).toBe(ReadyState.Cancelled);
|
|
||||||
expect(loadSpy).not.toHaveBeenCalled();
|
|
||||||
expect(errorSpy).not.toHaveBeenCalled();
|
|
||||||
expect(returnSpy).not.toHaveBeenCalled();
|
|
||||||
async.done();
|
|
||||||
}, 10);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should report error if loaded without invoking callback',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
|
|
||||||
connection.response.subscribe(
|
|
||||||
() => async.fail('Response listener should not be called'), (err: Response) => {
|
|
||||||
expect(err.text()).toBe('JSONP injected script did not invoke callback.');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingScripts[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should report error if script contains error',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
|
|
||||||
|
|
||||||
connection.response.subscribe(
|
|
||||||
() => async.fail('Response listener should not be called'), (err: Response) => {
|
|
||||||
expect(err.text()).toBe('Oops!');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingScripts[0].dispatchEvent('error', ({message: 'Oops!'}));
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw if request method is not GET', () => {
|
|
||||||
[RequestMethod.Post, RequestMethod.Put, RequestMethod.Delete, RequestMethod.Options,
|
|
||||||
RequestMethod.Head, RequestMethod.Patch]
|
|
||||||
.forEach(method => {
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const req = new Request(
|
|
||||||
base.merge(new RequestOptions({url: 'https://google.com', method: method})) as
|
|
||||||
any);
|
|
||||||
expect(
|
|
||||||
() => new (JSONPConnection as any)(req, new MockBrowserJsonp())
|
|
||||||
.response.subscribe())
|
|
||||||
.toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should respond with data passed to callback',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.json()).toEqual(({fake_payload: true, blob_id: 12345}));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
connection.finished(({fake_payload: true, blob_id: 12345}));
|
|
||||||
existingScripts[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injector} from '@angular/core';
|
|
||||||
import {AsyncTestCompleter, beforeEach, describe, inject, it, xit} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options';
|
|
||||||
import {BaseResponseOptions, ResponseOptions} from '@angular/http/src/base_response_options';
|
|
||||||
import {Request} from '@angular/http/src/static_request';
|
|
||||||
import {Response} from '@angular/http/src/static_response';
|
|
||||||
import {MockBackend, MockConnection} from '@angular/http/testing/src/mock_backend';
|
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
|
||||||
import {ReplaySubject} from 'rxjs';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('MockBackend', () => {
|
|
||||||
let backend: MockBackend;
|
|
||||||
let sampleRequest1: Request;
|
|
||||||
let sampleResponse1: Response;
|
|
||||||
let sampleRequest2: Request;
|
|
||||||
let sampleResponse2: Response;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
const injector = Injector.create([
|
|
||||||
{provide: ResponseOptions, useClass: BaseResponseOptions, deps: []},
|
|
||||||
{provide: MockBackend, deps: []}
|
|
||||||
]);
|
|
||||||
backend = injector.get(MockBackend);
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
sampleRequest1 =
|
|
||||||
new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any);
|
|
||||||
sampleResponse1 = new Response(new ResponseOptions({body: 'response1'}));
|
|
||||||
sampleRequest2 =
|
|
||||||
new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any);
|
|
||||||
sampleResponse2 = new Response(new ResponseOptions({body: 'response2'}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a new MockBackend', () => {
|
|
||||||
expect(backend).toBeAnInstanceOf(MockBackend);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a new MockConnection', () => {
|
|
||||||
expect(backend.createConnection(sampleRequest1)).toBeAnInstanceOf(MockConnection);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a new connection and allow subscription', () => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.response.subscribe(() => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow responding after subscription',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.response.subscribe(() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection.mockRespond(sampleResponse1);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should allow subscribing after responding',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.mockRespond(sampleResponse1);
|
|
||||||
connection.response.subscribe(() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should allow responding after subscription with an error',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.response.subscribe(null!, () => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection.mockError(new Error('nope'));
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not throw when there are no unresolved requests',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.response.subscribe(() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection.mockRespond(sampleResponse1);
|
|
||||||
backend.verifyNoPendingRequests();
|
|
||||||
}));
|
|
||||||
|
|
||||||
xit('should throw when there are unresolved requests',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection.response.subscribe(() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
backend.verifyNoPendingRequests();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should work when requests are resolved out of order',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection1: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
const connection2: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection1.response.subscribe(() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection2.response.subscribe(() => {});
|
|
||||||
connection2.mockRespond(sampleResponse1);
|
|
||||||
connection1.mockRespond(sampleResponse1);
|
|
||||||
backend.verifyNoPendingRequests();
|
|
||||||
}));
|
|
||||||
|
|
||||||
xit('should allow double subscribing',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const responses: Response[] = [sampleResponse1, sampleResponse2];
|
|
||||||
backend.connections.subscribe((c: MockConnection) => c.mockRespond(responses.shift()!));
|
|
||||||
const responseObservable: ReplaySubject<Response> =
|
|
||||||
backend.createConnection(sampleRequest1).response;
|
|
||||||
responseObservable.subscribe(res => expect(res.text()).toBe('response1'));
|
|
||||||
responseObservable.subscribe(
|
|
||||||
res => expect(res.text()).toBe('response2'), null!, async.done);
|
|
||||||
}));
|
|
||||||
|
|
||||||
// TODO(robwormald): readyStates are leaving?
|
|
||||||
it('should allow resolution of requests manually', () => {
|
|
||||||
const connection1: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
const connection2: MockConnection = backend.createConnection(sampleRequest1);
|
|
||||||
connection1.response.subscribe(() => {});
|
|
||||||
connection2.response.subscribe(() => {});
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
backend.verifyNoPendingRequests();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,808 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {afterEach, AsyncTestCompleter, beforeEach, beforeEachProviders, describe, expect, inject, it, SpyObject} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {BrowserXhr} from '@angular/http/src/backends/browser_xhr';
|
|
||||||
import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '@angular/http/src/backends/xhr_backend';
|
|
||||||
import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options';
|
|
||||||
import {BaseResponseOptions, ResponseOptions} from '@angular/http/src/base_response_options';
|
|
||||||
import {ResponseContentType, ResponseType} from '@angular/http/src/enums';
|
|
||||||
import {Headers} from '@angular/http/src/headers';
|
|
||||||
import {XSRFStrategy} from '@angular/http/src/interfaces';
|
|
||||||
import {Request} from '@angular/http/src/static_request';
|
|
||||||
import {Response} from '@angular/http/src/static_response';
|
|
||||||
import {URLSearchParams} from '@angular/http/src/url_search_params';
|
|
||||||
import {setCookie} from '@angular/platform-browser/testing/src/browser_util';
|
|
||||||
|
|
||||||
let abortSpy: any;
|
|
||||||
let sendSpy: any;
|
|
||||||
let openSpy: any;
|
|
||||||
let setRequestHeaderSpy: any;
|
|
||||||
let existingXHRs: MockBrowserXHR[] = [];
|
|
||||||
|
|
||||||
class MockBrowserXHR extends BrowserXhr {
|
|
||||||
abort: any;
|
|
||||||
send: any;
|
|
||||||
open: any;
|
|
||||||
response: any;
|
|
||||||
responseType: string;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
responseText!: string;
|
|
||||||
setRequestHeader: any;
|
|
||||||
callbacks = new Map<string, Function>();
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
status!: number;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
responseHeaders!: string;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
responseURL!: string;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
statusText!: string;
|
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
withCredentials!: boolean;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const spy = new SpyObject();
|
|
||||||
this.abort = abortSpy = spy.spy('abort');
|
|
||||||
this.send = sendSpy = spy.spy('send');
|
|
||||||
this.open = openSpy = spy.spy('open');
|
|
||||||
this.setRequestHeader = setRequestHeaderSpy = spy.spy('setRequestHeader');
|
|
||||||
// If responseType is supported by the browser, then it should be set to an empty string.
|
|
||||||
// (https://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute)
|
|
||||||
this.responseType = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatusCode(status: number) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatusText(statusText: string) {
|
|
||||||
this.statusText = statusText;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResponse(value: string) {
|
|
||||||
this.response = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResponseText(value: string) {
|
|
||||||
this.responseText = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResponseURL(value: string) {
|
|
||||||
this.responseURL = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResponseHeaders(value: string) {
|
|
||||||
this.responseHeaders = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllResponseHeaders() {
|
|
||||||
return this.responseHeaders || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
getResponseHeader(key: string) {
|
|
||||||
return Headers.fromResponseHeaderString(this.responseHeaders).get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
addEventListener(type: string, cb: Function) {
|
|
||||||
this.callbacks.set(type, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeEventListener(type: string, cb: Function) {
|
|
||||||
this.callbacks.delete(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(type: string) {
|
|
||||||
this.callbacks.get(type)!({});
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
const xhr = new MockBrowserXHR();
|
|
||||||
existingXHRs.push(xhr);
|
|
||||||
return xhr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('XHRBackend', () => {
|
|
||||||
let backend: XHRBackend;
|
|
||||||
let sampleRequest: Request;
|
|
||||||
|
|
||||||
beforeEachProviders(
|
|
||||||
() =>
|
|
||||||
[{provide: ResponseOptions, useClass: BaseResponseOptions},
|
|
||||||
{provide: BrowserXhr, useClass: MockBrowserXHR},
|
|
||||||
XHRBackend,
|
|
||||||
{provide: XSRFStrategy, useValue: new CookieXSRFStrategy()},
|
|
||||||
]);
|
|
||||||
|
|
||||||
beforeEach(inject([XHRBackend], (be: XHRBackend) => {
|
|
||||||
backend = be;
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
sampleRequest =
|
|
||||||
new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any);
|
|
||||||
}));
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
existingXHRs = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('creating a connection', () => {
|
|
||||||
@Injectable()
|
|
||||||
class NoopXsrfStrategy implements XSRFStrategy {
|
|
||||||
configureRequest(req: Request) {}
|
|
||||||
}
|
|
||||||
beforeEachProviders(() => [{provide: XSRFStrategy, useClass: NoopXsrfStrategy}]);
|
|
||||||
|
|
||||||
it('succeeds', () => {
|
|
||||||
expect(() => backend.createConnection(sampleRequest)).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (getDOM().supportsCookies()) {
|
|
||||||
describe('XSRF support', () => {
|
|
||||||
it('sets an XSRF header by default', () => {
|
|
||||||
setCookie('XSRF-TOKEN', 'magic XSRF value');
|
|
||||||
backend.createConnection(sampleRequest);
|
|
||||||
expect(sampleRequest.headers.get('X-XSRF-TOKEN')).toBe('magic XSRF value');
|
|
||||||
});
|
|
||||||
it('should allow overwriting of existing headers', () => {
|
|
||||||
setCookie('XSRF-TOKEN', 'magic XSRF value');
|
|
||||||
sampleRequest.headers.set('X-XSRF-TOKEN', 'already set');
|
|
||||||
backend.createConnection(sampleRequest);
|
|
||||||
expect(sampleRequest.headers.get('X-XSRF-TOKEN')).toBe('magic XSRF value');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('configuration', () => {
|
|
||||||
beforeEachProviders(() => [{
|
|
||||||
provide: XSRFStrategy,
|
|
||||||
useValue: new CookieXSRFStrategy('my cookie', 'X-MY-HEADER')
|
|
||||||
}]);
|
|
||||||
|
|
||||||
it('uses the configured names', () => {
|
|
||||||
setCookie('my cookie', 'XSRF value');
|
|
||||||
backend.createConnection(sampleRequest);
|
|
||||||
expect(sampleRequest.headers.get('X-MY-HEADER')).toBe('XSRF value');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('XHRConnection', () => {
|
|
||||||
it('should use the injected BaseResponseOptions to create the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(),
|
|
||||||
new ResponseOptions({type: ResponseType.Error}));
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.type).toBe(ResponseType.Error);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should complete a request', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(),
|
|
||||||
new ResponseOptions({type: ResponseType.Error}));
|
|
||||||
connection.response.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
expect(res.type).toBe(ResponseType.Error);
|
|
||||||
},
|
|
||||||
null!,
|
|
||||||
() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should call abort when disposed', () => {
|
|
||||||
const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
||||||
const request = connection.response.subscribe();
|
|
||||||
request.unsubscribe();
|
|
||||||
expect(abortSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an error Response on error',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(),
|
|
||||||
new ResponseOptions({type: ResponseType.Error}));
|
|
||||||
connection.response.subscribe(null!, (res: Response) => {
|
|
||||||
expect(res.type).toBe(ResponseType.Error);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].dispatchEvent('error');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set the status text and status code on error',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(),
|
|
||||||
new ResponseOptions({type: ResponseType.Error}));
|
|
||||||
connection.response.subscribe(null!, (res: Response) => {
|
|
||||||
expect(res.type).toBe(ResponseType.Error);
|
|
||||||
expect(res.status).toEqual(0);
|
|
||||||
expect(res.statusText).toEqual('');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
const xhr = existingXHRs[0];
|
|
||||||
// status=0 with a text='' is common for CORS errors
|
|
||||||
xhr.setStatusCode(0);
|
|
||||||
xhr.setStatusText('');
|
|
||||||
xhr.dispatchEvent('error');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should call open with method and url when subscribed to', () => {
|
|
||||||
const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
||||||
expect(openSpy).not.toHaveBeenCalled();
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call send on the backend with request body when subscribed to', () => {
|
|
||||||
const body = 'Some body to love';
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
|
|
||||||
expect(sendSpy).not.toHaveBeenCalled();
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should attach headers to the request', () => {
|
|
||||||
const headers =
|
|
||||||
new Headers({'Content-Type': 'text/xml', 'Breaking-Bad': '<3', 'X-Multi': ['a', 'b']});
|
|
||||||
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({headers: headers})) as any),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/xml');
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Breaking-Bad', '<3');
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('X-Multi', 'a,b');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should attach default Accept header', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({headers})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(setRequestHeaderSpy)
|
|
||||||
.toHaveBeenCalledWith('Accept', 'application/json, text/plain, */*');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not override user provided Accept header', () => {
|
|
||||||
const headers = new Headers({'Accept': 'text/xml'});
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({headers})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Accept', 'text/xml');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip content type detection if custom content type header is set', () => {
|
|
||||||
const headers = new Headers({'Content-Type': 'text/plain'});
|
|
||||||
const body = {test: 'val'};
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body, headers: headers})) as any),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/plain');
|
|
||||||
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith('Content-Type', 'application/json');
|
|
||||||
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith('content-type', 'application/json');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use object body and detect content type header to the request', () => {
|
|
||||||
const body = {test: 'val'};
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(JSON.stringify(body, null, 2));
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'application/json');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use number body and detect content type header to the request', () => {
|
|
||||||
const body = 23;
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith('23');
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use string body and detect content type header to the request', () => {
|
|
||||||
const body = 'some string';
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use URLSearchParams body and detect content type header to the request', () => {
|
|
||||||
const body = new URLSearchParams();
|
|
||||||
body.set('test1', 'val1');
|
|
||||||
body.set('test2', 'val2');
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith('test1=val1&test2=val2');
|
|
||||||
expect(setRequestHeaderSpy)
|
|
||||||
.toHaveBeenCalledWith(
|
|
||||||
'content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
|
||||||
});
|
|
||||||
|
|
||||||
if ((global as any /** TODO #9100 */)['Blob']) {
|
|
||||||
// `new Blob(...)` throws an 'Illegal constructor' exception in Android browser <= 4.3,
|
|
||||||
// but a BlobBuilder can be used instead
|
|
||||||
const createBlob = (data: Array<string>, datatype: string) => {
|
|
||||||
let newBlob: Blob;
|
|
||||||
try {
|
|
||||||
newBlob = new Blob(data || [], datatype ? {type: datatype} : {});
|
|
||||||
} catch {
|
|
||||||
const BlobBuilder = (<any>global).BlobBuilder || (<any>global).WebKitBlobBuilder ||
|
|
||||||
(<any>global).MozBlobBuilder || (<any>global).MSBlobBuilder;
|
|
||||||
const builder = new BlobBuilder();
|
|
||||||
builder.append(data);
|
|
||||||
newBlob = builder.getBlob(datatype);
|
|
||||||
}
|
|
||||||
return newBlob;
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should use FormData body and detect content type header to the request', () => {
|
|
||||||
const body = new FormData();
|
|
||||||
body.append('test1', 'val1');
|
|
||||||
body.append('test2', '123456');
|
|
||||||
const blob = createBlob(['body { color: red; }'], 'text/css');
|
|
||||||
body.append('userfile', blob);
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use blob body and detect content type header to the request', () => {
|
|
||||||
const body = createBlob(['body { color: red; }'], 'text/css');
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body})) as any),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/css');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use blob body without type to the request', () => {
|
|
||||||
const body = createBlob(['body { color: red; }'], null!);
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use blob body without type with custom content type header to the request',
|
|
||||||
() => {
|
|
||||||
const headers = new Headers({'Content-Type': 'text/css'});
|
|
||||||
const body = createBlob(['body { color: red; }'], null!);
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/css');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use array buffer body to the request', () => {
|
|
||||||
const body = new ArrayBuffer(512);
|
|
||||||
const longInt8View = new Uint8Array(body);
|
|
||||||
for (let i = 0; i < longInt8View.length; i++) {
|
|
||||||
longInt8View[i] = i % 255;
|
|
||||||
}
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use array buffer body without type with custom content type header to the request',
|
|
||||||
() => {
|
|
||||||
const headers = new Headers({'Content-Type': 'text/css'});
|
|
||||||
const body = new ArrayBuffer(512);
|
|
||||||
const longInt8View = new Uint8Array(body);
|
|
||||||
for (let i = 0; i < longInt8View.length; i++) {
|
|
||||||
longInt8View[i] = i % 255;
|
|
||||||
}
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
connection.response.subscribe();
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
||||||
expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/css');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should return the correct status code',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 418;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
|
|
||||||
},
|
|
||||||
(errRes: Response) => {
|
|
||||||
expect(errRes.status).toBe(statusCode);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should call next and complete on 200 codes',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
let nextCalled = false;
|
|
||||||
let errorCalled = false;
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
nextCalled = true;
|
|
||||||
expect(res.status).toBe(statusCode);
|
|
||||||
},
|
|
||||||
(errRes: Response) => {
|
|
||||||
errorCalled = true;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
expect(nextCalled).toBe(true);
|
|
||||||
expect(errorCalled).toBe(false);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set ok to true on 200 return',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.ok).toBe(true);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set ok to false on 300 return',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 300;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
throw 'should not be called';
|
|
||||||
},
|
|
||||||
(errRes: Response) => {
|
|
||||||
expect(errRes.ok).toBe(false);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should call error and not complete on 300+ codes',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
let nextCalled = false;
|
|
||||||
const errorCalled = false;
|
|
||||||
const statusCode = 301;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
nextCalled = true;
|
|
||||||
},
|
|
||||||
(errRes: Response) => {
|
|
||||||
expect(errRes.status).toBe(statusCode);
|
|
||||||
expect(nextCalled).toBe(false);
|
|
||||||
async.done();
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
throw 'should not be called';
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should normalize IE\'s 1223 status code into 204',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 1223;
|
|
||||||
const normalizedCode = 204;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.status).toBe(normalizedCode);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should ignore response body for 204 status code',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 204;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].setResponseText('Doge');
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should normalize responseText and response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const responseBody = 'Doge';
|
|
||||||
|
|
||||||
const connection1 =
|
|
||||||
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
||||||
|
|
||||||
const connection2 =
|
|
||||||
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
||||||
|
|
||||||
connection1.response.subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe(responseBody);
|
|
||||||
|
|
||||||
connection2.response.subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe(responseBody);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[1].setStatusCode(200);
|
|
||||||
existingXHRs[1].setResponse(responseBody);
|
|
||||||
existingXHRs[1].dispatchEvent('load');
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].setResponseText(responseBody);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const conn =
|
|
||||||
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
||||||
conn.response.subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('{json: "object"}');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].setResponseText(')]}\'\n{json: "object"}');
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const conn =
|
|
||||||
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
||||||
conn.response.subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('{json: "object"}');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].setResponseText(')]}\',\n{json: "object"}');
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should strip XSSI prefix from errors',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const conn =
|
|
||||||
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
||||||
conn.response.subscribe(null!, (res: Response) => {
|
|
||||||
expect(res.text()).toBe('{json: "object"}');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
existingXHRs[0].setStatusCode(404);
|
|
||||||
existingXHRs[0].setResponseText(')]}\'\n{json: "object"}');
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should parse response headers and add them to the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
const responseHeaderString = `Date: Fri, 20 Nov 2015 01:45:26 GMT
|
|
||||||
Content-Type: application/json; charset=utf-8
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
Connection: keep-alive`;
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.headers!.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
|
|
||||||
expect(res.headers!.get('Content-Type')).toEqual('application/json; charset=utf-8');
|
|
||||||
expect(res.headers!.get('Transfer-Encoding')).toEqual('chunked');
|
|
||||||
expect(res.headers!.get('Connection')).toEqual('keep-alive');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setResponseHeaders(responseHeaderString);
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add the responseURL to the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
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: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
const responseHeaders = `X-Request-URL: http://somedomain.com
|
|
||||||
Foo: Bar`;
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.url).toEqual('http://somedomain.com');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setResponseHeaders(responseHeaders);
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should return request url if it cannot be retrieved from response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.url).toEqual('https://google.com');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set the status text property from the XMLHttpRequest instance if present',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusText = 'test';
|
|
||||||
const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.statusText).toBe(statusText);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusText(statusText);
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set status text to "OK" if it is not present in XMLHttpRequest instance',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.statusText).toBe('OK');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(200);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set withCredentials to true when defined in request options for CORS situations',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
sampleRequest.withCredentials = true;
|
|
||||||
const mockXhr = new MockBrowserXHR();
|
|
||||||
const connection =
|
|
||||||
new XHRConnection(sampleRequest, mockXhr, new ResponseOptions({status: statusCode}));
|
|
||||||
const responseHeaders = `X-Request-URL: http://somedomain.com
|
|
||||||
Foo: Bar`;
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.url).toEqual('http://somedomain.com');
|
|
||||||
expect(existingXHRs[0].withCredentials).toBeTruthy();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setResponseHeaders(responseHeaders);
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set the responseType attribute to blob when the corresponding response content type is present',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const statusCode = 200;
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(
|
|
||||||
base.merge(new RequestOptions({responseType: ResponseContentType.Blob}))),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(existingXHRs[0].responseType).toBe('blob');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not throw invalidStateError if response without body and responseType not equal to text',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const base = new BaseRequestOptions();
|
|
||||||
const connection = new XHRConnection(
|
|
||||||
new Request(
|
|
||||||
base.merge(new RequestOptions({responseType: ResponseContentType.Json}))),
|
|
||||||
new MockBrowserXHR());
|
|
||||||
|
|
||||||
connection.response.subscribe((res: Response) => {
|
|
||||||
expect(res.json()).toBe(null);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
existingXHRs[0].setStatusCode(204);
|
|
||||||
existingXHRs[0].dispatchEvent('load');
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options';
|
|
||||||
import {RequestMethod} from '@angular/http/src/enums';
|
|
||||||
import {Headers} from '@angular/http/src/headers';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('BaseRequestOptions', () => {
|
|
||||||
it('should create a new object when calling merge', () => {
|
|
||||||
const options1 = new BaseRequestOptions();
|
|
||||||
const options2 = options1.merge(new RequestOptions({method: RequestMethod.Delete}));
|
|
||||||
expect(options2).not.toBe(options1);
|
|
||||||
expect(options2.method).toBe(RequestMethod.Delete);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should retain previously merged values when merging again', () => {
|
|
||||||
const options1 = new BaseRequestOptions();
|
|
||||||
const options2 = options1.merge(new RequestOptions({method: RequestMethod.Delete}));
|
|
||||||
expect(options2.method).toBe(RequestMethod.Delete);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should accept search params as object', () => {
|
|
||||||
const params = {a: 1, b: 'text', c: [1, 2, '3']};
|
|
||||||
const options = new RequestOptions({params});
|
|
||||||
|
|
||||||
expect(options.params.paramsMap.size).toBe(3);
|
|
||||||
expect(options.params.paramsMap.get('a')).toEqual(['1']);
|
|
||||||
expect(options.params.paramsMap.get('b')).toEqual(['text']);
|
|
||||||
expect(options.params.paramsMap.get('c')).toEqual(['1', '2', '3']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should merge search params as object', () => {
|
|
||||||
const options1 = new BaseRequestOptions();
|
|
||||||
const params = {a: 1, b: 'text', c: [1, 2, '3']};
|
|
||||||
const options2 = options1.merge(new RequestOptions({params}));
|
|
||||||
|
|
||||||
expect(options2.params.paramsMap.size).toBe(3);
|
|
||||||
expect(options2.params.paramsMap.get('a')).toEqual(['1']);
|
|
||||||
expect(options2.params.paramsMap.get('b')).toEqual(['text']);
|
|
||||||
expect(options2.params.paramsMap.get('c')).toEqual(['1', '2', '3']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a new headers object when calling merge', () => {
|
|
||||||
const options1 = new RequestOptions({headers: new Headers()});
|
|
||||||
const options2 = options1.merge();
|
|
||||||
expect(options2.headers).not.toBe(options1.headers);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,192 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Headers} from '@angular/http/src/headers';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('Headers', () => {
|
|
||||||
describe('initialization', () => {
|
|
||||||
it('should conform to spec', () => {
|
|
||||||
const httpHeaders = {
|
|
||||||
'Content-Type': 'image/jpeg',
|
|
||||||
'Accept-Charset': 'utf-8',
|
|
||||||
'X-My-Custom-Header': 'Zeke are cool',
|
|
||||||
};
|
|
||||||
const secondHeaders = new Headers(httpHeaders);
|
|
||||||
const secondHeadersObj = new Headers(secondHeaders);
|
|
||||||
expect(secondHeadersObj.get('Content-Type')).toEqual('image/jpeg');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should merge values in provided dictionary', () => {
|
|
||||||
const headers = new Headers({'foo': 'bar'});
|
|
||||||
expect(headers.get('foo')).toEqual('bar');
|
|
||||||
expect(headers.getAll('foo')).toEqual(['bar']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not alter the values of a provided header template', () => {
|
|
||||||
// Spec at https://fetch.spec.whatwg.org/#concept-headers-fill
|
|
||||||
// test for https://github.com/angular/angular/issues/6845
|
|
||||||
const firstHeaders = new Headers();
|
|
||||||
const secondHeaders = new Headers(firstHeaders);
|
|
||||||
secondHeaders.append('Content-Type', 'image/jpeg');
|
|
||||||
expect(firstHeaders.has('Content-Type')).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should preserve the list of values', () => {
|
|
||||||
const src = new Headers();
|
|
||||||
src.append('foo', 'a');
|
|
||||||
src.append('foo', 'b');
|
|
||||||
src.append('foo', 'c');
|
|
||||||
const dst = new Headers(src);
|
|
||||||
expect(dst.getAll('foo')).toEqual(src.getAll('foo'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should keep the last value when initialized from an object', () => {
|
|
||||||
const headers = new Headers({
|
|
||||||
'foo': 'first',
|
|
||||||
'fOo': 'second',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(headers.getAll('foo')).toEqual(['second']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.set()', () => {
|
|
||||||
it('should clear all values and re-set for the provided key', () => {
|
|
||||||
const headers = new Headers({'foo': 'bar'});
|
|
||||||
expect(headers.get('foo')).toEqual('bar');
|
|
||||||
|
|
||||||
headers.set('foo', 'baz');
|
|
||||||
expect(headers.get('foo')).toEqual('baz');
|
|
||||||
|
|
||||||
headers.set('fOO', 'bat');
|
|
||||||
expect(headers.get('foo')).toEqual('bat');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should preserve the case of the first call', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set('fOo', 'baz');
|
|
||||||
headers.set('foo', 'bat');
|
|
||||||
expect(JSON.stringify(headers)).toEqual('{"fOo":["bat"]}');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should preserve cases after cloning', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set('fOo', 'baz');
|
|
||||||
headers.set('foo', 'bat');
|
|
||||||
expect(JSON.stringify(new Headers(headers))).toEqual('{"fOo":["bat"]}');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert input array to string', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set('foo', ['bar', 'baz']);
|
|
||||||
expect(headers.get('foo')).toEqual('bar,baz');
|
|
||||||
expect(headers.getAll('foo')).toEqual(['bar,baz']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.get()', () => {
|
|
||||||
it('should be case insensitive', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set('foo', 'baz');
|
|
||||||
expect(headers.get('foo')).toEqual('baz');
|
|
||||||
expect(headers.get('FOO')).toEqual('baz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null if the header is not present', () => {
|
|
||||||
const headers = new Headers({bar: []});
|
|
||||||
expect(headers.get('bar')).toEqual(null);
|
|
||||||
expect(headers.get('foo')).toEqual(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.getAll()', () => {
|
|
||||||
it('should be case insensitive', () => {
|
|
||||||
const headers = new Headers({foo: ['bar', 'baz']});
|
|
||||||
expect(headers.getAll('foo')).toEqual(['bar', 'baz']);
|
|
||||||
expect(headers.getAll('FOO')).toEqual(['bar', 'baz']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null if the header is not present', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
expect(headers.getAll('foo')).toEqual(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.delete', () => {
|
|
||||||
it('should be case insensitive', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
|
|
||||||
headers.set('foo', 'baz');
|
|
||||||
expect(headers.has('foo')).toEqual(true);
|
|
||||||
headers.delete('foo');
|
|
||||||
expect(headers.has('foo')).toEqual(false);
|
|
||||||
|
|
||||||
headers.set('foo', 'baz');
|
|
||||||
expect(headers.has('foo')).toEqual(true);
|
|
||||||
headers.delete('FOO');
|
|
||||||
expect(headers.has('foo')).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.append', () => {
|
|
||||||
it('should append a value to the list', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.append('foo', 'bar');
|
|
||||||
headers.append('foo', 'baz');
|
|
||||||
expect(headers.get('foo')).toEqual('bar');
|
|
||||||
expect(headers.getAll('foo')).toEqual(['bar', 'baz']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should preserve the case of the first call', () => {
|
|
||||||
const headers = new Headers();
|
|
||||||
|
|
||||||
headers.append('FOO', 'bar');
|
|
||||||
headers.append('foo', 'baz');
|
|
||||||
expect(JSON.stringify(headers)).toEqual('{"FOO":["bar","baz"]}');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.toJSON()', () => {
|
|
||||||
let headers: Headers;
|
|
||||||
let values: string[];
|
|
||||||
let ref: {[name: string]: string[]};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
values = ['application/jeisen', 'application/jason', 'application/patrickjs'];
|
|
||||||
headers = new Headers();
|
|
||||||
headers.set('Accept', values);
|
|
||||||
ref = {'Accept': values};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be serializable with toJSON', () => {
|
|
||||||
expect(JSON.stringify(headers)).toEqual(JSON.stringify(ref));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to recreate serializedHeaders', () => {
|
|
||||||
const parsedHeaders = JSON.parse(JSON.stringify(headers));
|
|
||||||
const recreatedHeaders = new Headers(parsedHeaders);
|
|
||||||
expect(JSON.stringify(parsedHeaders)).toEqual(JSON.stringify(recreatedHeaders));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.fromResponseHeaderString()', () => {
|
|
||||||
it('should parse a response header string', () => {
|
|
||||||
const response = `Date: Fri, 20 Nov 2015 01:45:26 GMT\n` +
|
|
||||||
`Content-Type: application/json; charset=utf-8\n` +
|
|
||||||
`Transfer-Encoding: chunked\n` +
|
|
||||||
`Connection: keep-alive`;
|
|
||||||
const headers = Headers.fromResponseHeaderString(response);
|
|
||||||
expect(headers.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
|
|
||||||
expect(headers.get('Content-Type')).toEqual('application/json; charset=utf-8');
|
|
||||||
expect(headers.get('Transfer-Encoding')).toEqual('chunked');
|
|
||||||
expect(headers.get('Connection')).toEqual('keep-alive');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,548 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injector} from '@angular/core';
|
|
||||||
import {getTestBed, TestBed} from '@angular/core/testing';
|
|
||||||
import {afterEach, AsyncTestCompleter, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {stringToArrayBuffer} from '@angular/http/src/http_utils';
|
|
||||||
import {MockBackend, MockConnection} from '@angular/http/testing/src/mock_backend';
|
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
|
||||||
import {Observable, zip} from 'rxjs';
|
|
||||||
|
|
||||||
import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, Jsonp, JSONPBackend, JsonpModule, Request, RequestMethod, RequestOptions, Response, ResponseContentType, ResponseOptions, URLSearchParams, XHRBackend} from '../index';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('injectables', () => {
|
|
||||||
const url = 'http://foo.bar';
|
|
||||||
let http: Http;
|
|
||||||
let injector: Injector;
|
|
||||||
let jsonpBackend: MockBackend;
|
|
||||||
let xhrBackend: MockBackend;
|
|
||||||
let jsonp: Jsonp;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [HttpModule, JsonpModule],
|
|
||||||
providers: [
|
|
||||||
{provide: XHRBackend, useClass: MockBackend},
|
|
||||||
{provide: JSONPBackend, useClass: MockBackend}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
injector = getTestBed();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow using jsonpInjectables and httpInjectables in same injector',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
http = injector.get(Http);
|
|
||||||
jsonp = injector.get(Jsonp);
|
|
||||||
jsonpBackend = injector.get(JSONPBackend) as any as MockBackend;
|
|
||||||
xhrBackend = injector.get(XHRBackend) as any as MockBackend;
|
|
||||||
|
|
||||||
let xhrCreatedConnections = 0;
|
|
||||||
let jsonpCreatedConnections = 0;
|
|
||||||
|
|
||||||
xhrBackend.connections.subscribe(() => {
|
|
||||||
xhrCreatedConnections++;
|
|
||||||
expect(xhrCreatedConnections).toEqual(1);
|
|
||||||
if (jsonpCreatedConnections) {
|
|
||||||
async.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
http.get(url).subscribe(() => {});
|
|
||||||
|
|
||||||
jsonpBackend.connections.subscribe(() => {
|
|
||||||
jsonpCreatedConnections++;
|
|
||||||
expect(jsonpCreatedConnections).toEqual(1);
|
|
||||||
if (xhrCreatedConnections) {
|
|
||||||
async.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonp.request(url).subscribe(() => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('http', () => {
|
|
||||||
const url = 'http://foo.bar';
|
|
||||||
let http: Http;
|
|
||||||
let injector: Injector;
|
|
||||||
let backend: MockBackend;
|
|
||||||
let baseResponse: Response;
|
|
||||||
let jsonp: Jsonp;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
injector = Injector.create([
|
|
||||||
{provide: BaseRequestOptions, deps: []}, {provide: MockBackend, deps: []}, {
|
|
||||||
provide: Http,
|
|
||||||
useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
|
|
||||||
return new Http(backend, defaultOptions);
|
|
||||||
},
|
|
||||||
deps: [MockBackend, BaseRequestOptions]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: Jsonp,
|
|
||||||
useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
|
|
||||||
return new Jsonp(backend, defaultOptions);
|
|
||||||
},
|
|
||||||
deps: [MockBackend, BaseRequestOptions]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
http = injector.get(Http);
|
|
||||||
jsonp = injector.get(Jsonp);
|
|
||||||
backend = injector.get(MockBackend);
|
|
||||||
baseResponse = new Response(new ResponseOptions({body: 'base response'}));
|
|
||||||
spyOn(Http.prototype, 'request').and.callThrough();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => backend.verifyNoPendingRequests());
|
|
||||||
|
|
||||||
describe('Http', () => {
|
|
||||||
describe('.request()', () => {
|
|
||||||
it('should return an Observable', () => {
|
|
||||||
expect(http.request(url)).toBeAnInstanceOf(Observable);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should accept a fully-qualified request as its only parameter',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toBe('https://google.com');
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.request(new Request(new RequestOptions({url: 'https://google.com'})))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should accept a fully-qualified request as its only parameter',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toBe('https://google.com');
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Post);
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.request(new Request(new RequestOptions(
|
|
||||||
{url: 'https://google.com', method: RequestMethod.Post})))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should perform a get request for given url if only passed a string',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
|
|
||||||
http.request('http://basic.connection').subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should perform a post request for given url if options include a method',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toEqual(RequestMethod.Post);
|
|
||||||
c.mockRespond(baseResponse);
|
|
||||||
});
|
|
||||||
const requestOptions = new RequestOptions({method: RequestMethod.Post});
|
|
||||||
http.request('http://basic.connection', requestOptions).subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should perform a post request for given url if options include a method',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toEqual(RequestMethod.Post);
|
|
||||||
c.mockRespond(baseResponse);
|
|
||||||
});
|
|
||||||
const requestOptions = {method: RequestMethod.Post};
|
|
||||||
http.request('http://basic.connection', requestOptions).subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should perform a get request and complete the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
|
|
||||||
http.request('http://basic.connection')
|
|
||||||
.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
},
|
|
||||||
null!,
|
|
||||||
() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should perform multiple get requests and complete the responses',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
|
|
||||||
|
|
||||||
http.request('http://basic.connection').subscribe((res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
});
|
|
||||||
http.request('http://basic.connection')
|
|
||||||
.subscribe(
|
|
||||||
(res: Response) => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
},
|
|
||||||
null!,
|
|
||||||
() => {
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw if url is not a string or Request', () => {
|
|
||||||
const req = <Request>{};
|
|
||||||
expect(() => http.request(req))
|
|
||||||
.toThrowError('First argument must be a url string or Request instance.');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.get()', () => {
|
|
||||||
it('should perform a get request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Get);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.get(url).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.post()', () => {
|
|
||||||
it('should perform a post request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Post);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.post(url, 'post me').subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should attach the provided body to the request',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const body = 'this is my post body';
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.text()).toBe(body);
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.post(url, body).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.put()', () => {
|
|
||||||
it('should perform a put request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Put);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.put(url, 'put me').subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should attach the provided body to the request',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const body = 'this is my put body';
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.text()).toBe(body);
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.put(url, body).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.delete()', () => {
|
|
||||||
it('should perform a delete request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Delete);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.delete(url).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.patch()', () => {
|
|
||||||
it('should perform a patch request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Patch);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.patch(url, 'this is my patch body').subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should attach the provided body to the request',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const body = 'this is my patch body';
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.text()).toBe(body);
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.patch(url, body).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.head()', () => {
|
|
||||||
it('should perform a head request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Head);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.head(url).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('.options()', () => {
|
|
||||||
it('should perform an options request for given url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Options);
|
|
||||||
expect(http.request).toHaveBeenCalled();
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
expect(http.request).not.toHaveBeenCalled();
|
|
||||||
http.options(url).subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('searchParams', () => {
|
|
||||||
it('should append search params to url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
params.append('q', 'puppies');
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toEqual('https://www.google.com?q=puppies');
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.get('https://www.google.com', new RequestOptions({search: params}))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should append string search params to url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toEqual('https://www.google.com?q=piggies');
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.get('https://www.google.com', new RequestOptions({search: 'q=piggies'}))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should produce valid url when url already contains a query',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toEqual('https://www.google.com?q=angular&as_eq=1.x');
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.get('https://www.google.com?q=angular', new RequestOptions({search: 'as_eq=1.x'}))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('params', () => {
|
|
||||||
it('should append params to url',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.url).toEqual('https://www.google.com?q=puppies');
|
|
||||||
backend.resolveAllConnections();
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.get('https://www.google.com', {params: {q: 'puppies'}})
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('string method names', () => {
|
|
||||||
it('should allow case insensitive strings for method names', () => {
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.method).toBe(RequestMethod.Post);
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.request(
|
|
||||||
new Request(new RequestOptions({url: 'https://google.com', method: 'PosT'})))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw when invalid string parameter is passed for method name', () => {
|
|
||||||
expect(() => {
|
|
||||||
http.request(
|
|
||||||
new Request(new RequestOptions({url: 'https://google.com', method: 'Invalid'})));
|
|
||||||
}).toThrowError('Invalid request method. The method "Invalid" is not supported.');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Jsonp', () => {
|
|
||||||
describe('.request()', () => {
|
|
||||||
it('should throw if url is not a string or Request', () => {
|
|
||||||
const req = <Request>{};
|
|
||||||
expect(() => jsonp.request(req))
|
|
||||||
.toThrowError('First argument must be a url string or Request instance.');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('response buffer', () => {
|
|
||||||
it('should attach the provided buffer to the response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
expect(c.request.responseType).toBe(ResponseContentType.ArrayBuffer);
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: new ArrayBuffer(32)})));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
http.get(
|
|
||||||
'https://www.google.com',
|
|
||||||
new RequestOptions({responseType: ResponseContentType.ArrayBuffer}))
|
|
||||||
.subscribe((res: Response) => {});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should be able to consume a buffer containing a String as any response type',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
|
|
||||||
http.get('https://www.google.com').subscribe((res: Response) => {
|
|
||||||
expect(res.arrayBuffer()).toBeAnInstanceOf(ArrayBuffer);
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should be able to consume a buffer containing an ArrayBuffer as any response type',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const arrayBuffer = stringToArrayBuffer('{"response": "ok"}');
|
|
||||||
backend.connections.subscribe(
|
|
||||||
(c: MockConnection) =>
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: arrayBuffer}))));
|
|
||||||
http.get('https://www.google.com').subscribe((res: Response) => {
|
|
||||||
expect(res.arrayBuffer()).toBe(arrayBuffer);
|
|
||||||
expect(res.text()).toEqual('{"response": "ok"}');
|
|
||||||
expect(res.json()).toEqual({response: 'ok'});
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should be able to consume a buffer containing an Object as any response type',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const simpleObject = {'content': 'ok'};
|
|
||||||
backend.connections.subscribe(
|
|
||||||
(c: MockConnection) =>
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: simpleObject}))));
|
|
||||||
http.get('https://www.google.com').subscribe((res: Response) => {
|
|
||||||
expect(res.arrayBuffer()).toBeAnInstanceOf(ArrayBuffer);
|
|
||||||
expect(res.text()).toEqual(JSON.stringify(simpleObject, null, 2));
|
|
||||||
expect(res.json()).toBe(simpleObject);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should preserve encoding of ArrayBuffer response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const message = 'é@θЂ';
|
|
||||||
const arrayBuffer = stringToArrayBuffer(message);
|
|
||||||
backend.connections.subscribe(
|
|
||||||
(c: MockConnection) =>
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: arrayBuffer}))));
|
|
||||||
http.get('https://www.google.com').subscribe((res: Response) => {
|
|
||||||
expect(res.arrayBuffer()).toBeAnInstanceOf(ArrayBuffer);
|
|
||||||
expect(res.text()).toEqual(message);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should preserve encoding of String response',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const message = 'é@θЂ';
|
|
||||||
backend.connections.subscribe(
|
|
||||||
(c: MockConnection) =>
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: message}))));
|
|
||||||
http.get('https://www.google.com').subscribe((res: Response) => {
|
|
||||||
expect(res.arrayBuffer()).toEqual(stringToArrayBuffer(message));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should have an equivalent response independently of the buffer used',
|
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
||||||
const message = {'param': 'content'};
|
|
||||||
|
|
||||||
backend.connections.subscribe((c: MockConnection) => {
|
|
||||||
const body = (): any => {
|
|
||||||
switch (c.request.responseType) {
|
|
||||||
case ResponseContentType.Text:
|
|
||||||
return JSON.stringify(message, null, 2);
|
|
||||||
case ResponseContentType.Json:
|
|
||||||
return message;
|
|
||||||
case ResponseContentType.ArrayBuffer:
|
|
||||||
return stringToArrayBuffer(JSON.stringify(message, null, 2));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
c.mockRespond(new Response(new ResponseOptions({body: body()})));
|
|
||||||
});
|
|
||||||
|
|
||||||
zip(http.get(
|
|
||||||
'https://www.google.com',
|
|
||||||
new RequestOptions({responseType: ResponseContentType.Text})),
|
|
||||||
http.get(
|
|
||||||
'https://www.google.com',
|
|
||||||
new RequestOptions({responseType: ResponseContentType.Json})),
|
|
||||||
http.get(
|
|
||||||
'https://www.google.com',
|
|
||||||
new RequestOptions({responseType: ResponseContentType.ArrayBuffer})))
|
|
||||||
.subscribe((res: Array<any>) => {
|
|
||||||
expect(res[0].text()).toEqual(res[1].text());
|
|
||||||
expect(res[1].text()).toEqual(res[2].text());
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
|
||||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {RequestOptions} from '@angular/http/src/base_request_options';
|
|
||||||
import {ContentType} from '@angular/http/src/enums';
|
|
||||||
import {Headers} from '@angular/http/src/headers';
|
|
||||||
import {stringToArrayBuffer, stringToArrayBuffer8} from '@angular/http/src/http_utils';
|
|
||||||
import {ArrayBuffer, Request} from '@angular/http/src/static_request';
|
|
||||||
import {supportsWebAnimation} from '@angular/platform-browser/testing/src/browser_util';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('Request', () => {
|
|
||||||
describe('detectContentType', () => {
|
|
||||||
it('should return ContentType.NONE', () => {
|
|
||||||
const req =
|
|
||||||
new Request(new RequestOptions({url: 'test', method: 'GET', body: null}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.NONE);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return ContentType.JSON', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'application/json'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.JSON);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return ContentType.FORM', () => {
|
|
||||||
const req = new Request(
|
|
||||||
new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'application/x-www-form-urlencoded'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.FORM);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return ContentType.FORM_DATA', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'multipart/form-data'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.FORM_DATA);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return ContentType.TEXT', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'text/plain'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.TEXT);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return ContentType.BLOB', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'application/octet-stream'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.BLOB);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not create a blob out of ArrayBuffer', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: new ArrayBuffer(1),
|
|
||||||
headers: new Headers({'content-type': 'application/octet-stream'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.ARRAY_BUFFER);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return empty string if no body is present', () => {
|
|
||||||
const req = new Request(new RequestOptions({
|
|
||||||
url: 'test',
|
|
||||||
method: 'GET',
|
|
||||||
body: null,
|
|
||||||
headers: new Headers({'content-type': 'application/json'})
|
|
||||||
}) as any);
|
|
||||||
|
|
||||||
expect(req.text()).toEqual('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return empty string if body is undefined', () => {
|
|
||||||
const reqOptions = new RequestOptions(
|
|
||||||
{url: 'test', method: 'GET', headers: new Headers({'content-type': 'application/json'})});
|
|
||||||
delete reqOptions.body;
|
|
||||||
const req = new Request(reqOptions as any);
|
|
||||||
|
|
||||||
expect(req.text()).toEqual('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use object params', () => {
|
|
||||||
const req = new Request({url: 'http://test.com', params: {'a': 3, 'b': ['x', 'y']}});
|
|
||||||
expect(req.url).toBe('http://test.com?a=3&b=x&b=y');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use search if present', () => {
|
|
||||||
const req = new Request({url: 'http://test.com', search: 'a=1&b=2'});
|
|
||||||
expect(req.url).toBe('http://test.com?a=1&b=2');
|
|
||||||
});
|
|
||||||
|
|
||||||
if (supportsWebAnimation()) {
|
|
||||||
it('should serialize an ArrayBuffer to string via legacy encoding', () => {
|
|
||||||
const str = '\u89d2\u5ea6';
|
|
||||||
expect(new Request({body: stringToArrayBuffer(str), url: '/'}).text()).toEqual(str);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize an ArrayBuffer to string via iso-8859 encoding', () => {
|
|
||||||
const str = 'abcd';
|
|
||||||
expect(new Request({body: stringToArrayBuffer8(str), url: '/'}).text('iso-8859'))
|
|
||||||
.toEqual(str);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
|
||||||
|
|
||||||
import {ResponseOptions} from '@angular/http/src/base_response_options';
|
|
||||||
import {Response} from '@angular/http/src/static_response';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('Response', () => {
|
|
||||||
it('should be ok for 200 statuses', () => {
|
|
||||||
expect(new Response(new ResponseOptions({status: 200})).ok).toEqual(true);
|
|
||||||
expect(new Response(new ResponseOptions({status: 299})).ok).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not be ok for non 200 statuses', () => {
|
|
||||||
expect(new Response(new ResponseOptions({status: 199})).ok).toEqual(false);
|
|
||||||
expect(new Response(new ResponseOptions({status: 300})).ok).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,179 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
|
||||||
import {URLSearchParams} from '@angular/http/src/url_search_params';
|
|
||||||
|
|
||||||
{
|
|
||||||
describe('URLSearchParams', () => {
|
|
||||||
it('should conform to spec', () => {
|
|
||||||
const paramsString = 'q=URLUtils.searchParams&topic=api';
|
|
||||||
const searchParams = new URLSearchParams(paramsString);
|
|
||||||
|
|
||||||
// Tests borrowed from example at
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
|
|
||||||
// Compliant with spec described at https://url.spec.whatwg.org/#urlsearchparams
|
|
||||||
expect(searchParams.has('topic')).toBe(true);
|
|
||||||
expect(searchParams.has('foo')).toBe(false);
|
|
||||||
expect(searchParams.get('topic')).toEqual('api');
|
|
||||||
expect(searchParams.getAll('topic')).toEqual(['api']);
|
|
||||||
expect(searchParams.get('foo')).toBe(null);
|
|
||||||
searchParams.append('topic', 'webdev');
|
|
||||||
expect(searchParams.getAll('topic')).toEqual(['api', 'webdev']);
|
|
||||||
expect(searchParams.toString()).toEqual('q=URLUtils.searchParams&topic=api&topic=webdev');
|
|
||||||
searchParams.delete('topic');
|
|
||||||
expect(searchParams.toString()).toEqual('q=URLUtils.searchParams');
|
|
||||||
|
|
||||||
// Test default constructor
|
|
||||||
expect(new URLSearchParams().toString()).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should optionally accept a custom parser', () => {
|
|
||||||
const fooEveryThingParser = {
|
|
||||||
encodeKey() {
|
|
||||||
return 'I AM KEY';
|
|
||||||
},
|
|
||||||
encodeValue() {
|
|
||||||
return 'I AM VALUE';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const params = new URLSearchParams('', fooEveryThingParser);
|
|
||||||
params.set('myKey', 'myValue');
|
|
||||||
expect(params.toString()).toBe('I AM KEY=I AM VALUE');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should encode special characters in params', () => {
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
searchParams.append('a', '1+1');
|
|
||||||
searchParams.append('b c', '2');
|
|
||||||
searchParams.append('d%', '3$');
|
|
||||||
expect(searchParams.toString()).toEqual('a=1+1&b%20c=2&d%25=3$');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should not encode allowed characters', () => {
|
|
||||||
/*
|
|
||||||
* https://tools.ietf.org/html/rfc3986#section-3.4
|
|
||||||
* Allowed: ( pchar / "/" / "?" )
|
|
||||||
* pchar: unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
||||||
* unreserved: ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
||||||
* pct-encoded: "%" HEXDIG HEXDIG
|
|
||||||
* sub-delims: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
|
||||||
*
|
|
||||||
* & and = are excluded and should be encoded inside keys and values
|
|
||||||
* because URLSearchParams is responsible for inserting this.
|
|
||||||
**/
|
|
||||||
|
|
||||||
let params = new URLSearchParams();
|
|
||||||
'! $ \' ( ) * + , ; A 9 - . _ ~ ? / ='.split(' ').forEach((char, idx) => {
|
|
||||||
params.set(`a${idx}`, char);
|
|
||||||
});
|
|
||||||
expect(params.toString())
|
|
||||||
.toBe(
|
|
||||||
`a0=!&a1=$&a2=\'&a3=(&a4=)&a5=*&a6=+&a7=,&a8=;&a9=A&a10=9&a11=-&a12=.&a13=_&a14=~&a15=?&a16=/&a17==`
|
|
||||||
.replace(/\s/g, ''));
|
|
||||||
|
|
||||||
|
|
||||||
// Original example from https://github.com/angular/angular/issues/9348 for posterity
|
|
||||||
params = new URLSearchParams();
|
|
||||||
params.set('q', 'repo:janbaer/howcani+type:issue');
|
|
||||||
params.set('sort', 'created');
|
|
||||||
params.set('order', 'desc');
|
|
||||||
params.set('page', '1');
|
|
||||||
expect(params.toString())
|
|
||||||
.toBe('q=repo:janbaer/howcani+type:issue&sort=created&order=desc&page=1');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should support map-like merging operation via setAll()', () => {
|
|
||||||
const mapA = new URLSearchParams('a=1&a=2&a=3&c=8');
|
|
||||||
const mapB = new URLSearchParams('a=4&a=5&a=6&b=7');
|
|
||||||
mapA.setAll(mapB);
|
|
||||||
expect(mapA.has('a')).toBe(true);
|
|
||||||
expect(mapA.has('b')).toBe(true);
|
|
||||||
expect(mapA.has('c')).toBe(true);
|
|
||||||
expect(mapA.getAll('a')).toEqual(['4']);
|
|
||||||
expect(mapA.getAll('b')).toEqual(['7']);
|
|
||||||
expect(mapA.getAll('c')).toEqual(['8']);
|
|
||||||
expect(mapA.toString()).toEqual('a=4&c=8&b=7');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should support multimap-like merging operation via appendAll()', () => {
|
|
||||||
const mapA = new URLSearchParams('a=1&a=2&a=3&c=8');
|
|
||||||
const mapB = new URLSearchParams('a=4&a=5&a=6&b=7');
|
|
||||||
mapA.appendAll(mapB);
|
|
||||||
expect(mapA.has('a')).toBe(true);
|
|
||||||
expect(mapA.has('b')).toBe(true);
|
|
||||||
expect(mapA.has('c')).toBe(true);
|
|
||||||
expect(mapA.getAll('a')).toEqual(['1', '2', '3', '4', '5', '6']);
|
|
||||||
expect(mapA.getAll('b')).toEqual(['7']);
|
|
||||||
expect(mapA.getAll('c')).toEqual(['8']);
|
|
||||||
expect(mapA.toString()).toEqual('a=1&a=2&a=3&a=4&a=5&a=6&c=8&b=7');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should support multimap-like merging operation via replaceAll()', () => {
|
|
||||||
const mapA = new URLSearchParams('a=1&a=2&a=3&c=8');
|
|
||||||
const mapB = new URLSearchParams('a=4&a=5&a=6&b=7');
|
|
||||||
mapA.replaceAll(mapB);
|
|
||||||
expect(mapA.has('a')).toBe(true);
|
|
||||||
expect(mapA.has('b')).toBe(true);
|
|
||||||
expect(mapA.has('c')).toBe(true);
|
|
||||||
expect(mapA.getAll('a')).toEqual(['4', '5', '6']);
|
|
||||||
expect(mapA.getAll('b')).toEqual(['7']);
|
|
||||||
expect(mapA.getAll('c')).toEqual(['8']);
|
|
||||||
expect(mapA.toString()).toEqual('a=4&a=5&a=6&c=8&b=7');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support a clone operation via clone()', () => {
|
|
||||||
const fooQueryEncoder = {
|
|
||||||
encodeKey(k: string) {
|
|
||||||
return encodeURIComponent(k);
|
|
||||||
},
|
|
||||||
encodeValue(v: string) {
|
|
||||||
return encodeURIComponent(v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const paramsA = new URLSearchParams('', fooQueryEncoder);
|
|
||||||
paramsA.set('a', '2');
|
|
||||||
paramsA.set('q', '4+');
|
|
||||||
paramsA.set('c', '8');
|
|
||||||
const paramsB = new URLSearchParams();
|
|
||||||
paramsB.set('a', '2');
|
|
||||||
paramsB.set('q', '4+');
|
|
||||||
paramsB.set('c', '8');
|
|
||||||
expect(paramsB.toString()).toEqual('a=2&q=4+&c=8');
|
|
||||||
const paramsC = paramsA.clone();
|
|
||||||
expect(paramsC.has('a')).toBe(true);
|
|
||||||
expect(paramsC.has('b')).toBe(false);
|
|
||||||
expect(paramsC.has('c')).toBe(true);
|
|
||||||
expect(paramsC.toString()).toEqual('a=2&q=4%2B&c=8');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove the parameter when set to undefined or null', () => {
|
|
||||||
const params = new URLSearchParams('q=Q');
|
|
||||||
params.set('q', undefined!);
|
|
||||||
expect(params.has('q')).toBe(false);
|
|
||||||
expect(params.toString()).toEqual('');
|
|
||||||
params.set('q', null!);
|
|
||||||
expect(params.has('q')).toBe(false);
|
|
||||||
expect(params.toString()).toEqual('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should ignore the value when append undefined or null', () => {
|
|
||||||
const params = new URLSearchParams('q=Q');
|
|
||||||
params.append('q', undefined!);
|
|
||||||
expect(params.toString()).toEqual('q=Q');
|
|
||||||
params.append('q', null!);
|
|
||||||
expect(params.toString()).toEqual('q=Q');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
load("//tools:defaults.bzl", "ng_module")
|
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
|
||||||
|
|
||||||
exports_files(["package.json"])
|
|
||||||
|
|
||||||
ng_module(
|
|
||||||
name = "testing",
|
|
||||||
srcs = glob(["**/*.ts"]),
|
|
||||||
deps = [
|
|
||||||
"//packages/core",
|
|
||||||
"//packages/http",
|
|
||||||
"@npm//rxjs",
|
|
||||||
],
|
|
||||||
)
|
|
|
@ -1,15 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Entry point for all public APIs of the http/testing package.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from './public_api';
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@angular/http/testing",
|
|
||||||
"typings": "./testing.d.ts",
|
|
||||||
"main": "../bundles/http-testing.umd.js",
|
|
||||||
"module": "../fesm5/testing.js",
|
|
||||||
"es2015": "../fesm2015/testing.js",
|
|
||||||
"esm5": "../esm5/testing/testing.js",
|
|
||||||
"esm2015": "../esm2015/testing/testing.js",
|
|
||||||
"fesm5": "../fesm5/testing.js",
|
|
||||||
"fesm2015": "../fesm2015/testing.js"
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Entry point for all public APIs of this package.
|
|
||||||
*/
|
|
||||||
export * from './src/testing';
|
|
|
@ -1,266 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {Connection, ConnectionBackend, ReadyState, Request, Response} from '@angular/http';
|
|
||||||
import {ReplaySubject, Subject} from 'rxjs';
|
|
||||||
import {take} from 'rxjs/operators';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Mock Connection to represent a {@link Connection} for tests.
|
|
||||||
*
|
|
||||||
* @usageNotes
|
|
||||||
* ### Example of `mockRespond()`
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* var connection;
|
|
||||||
* backend.connections.subscribe(c => connection = c);
|
|
||||||
* http.request('data.json').subscribe(res => console.log(res.text()));
|
|
||||||
* connection.mockRespond(new Response(new ResponseOptions({ body: 'fake response' }))); //logs
|
|
||||||
* 'fake response'
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* ### Example of `mockError()`
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* var connection;
|
|
||||||
* backend.connections.subscribe(c => connection = c);
|
|
||||||
* http.request('data.json').subscribe(res => res, err => console.log(err)));
|
|
||||||
* connection.mockError(new Error('error'));
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export class MockConnection implements Connection {
|
|
||||||
// TODO: Name `readyState` should change to be more generic, and states could be made to be more
|
|
||||||
// descriptive than ResourceLoader states.
|
|
||||||
/**
|
|
||||||
* Describes the state of the connection, based on `XMLHttpRequest.readyState`, but with
|
|
||||||
* additional states. For example, state 5 indicates an aborted connection.
|
|
||||||
*/
|
|
||||||
readyState: ReadyState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Request} instance used to create the connection.
|
|
||||||
*/
|
|
||||||
request: Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link EventEmitter} of {@link Response}. Can be subscribed to in order to be notified when a
|
|
||||||
* response is available.
|
|
||||||
*/
|
|
||||||
response: ReplaySubject<Response>;
|
|
||||||
|
|
||||||
constructor(req: Request) {
|
|
||||||
this.response = <any>new ReplaySubject(1).pipe(take(1));
|
|
||||||
this.readyState = ReadyState.Open;
|
|
||||||
this.request = req;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a mock response to the connection. This response is the value that is emitted to the
|
|
||||||
* {@link EventEmitter} returned by {@link Http}.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mockRespond(res: Response) {
|
|
||||||
if (this.readyState === ReadyState.Done || this.readyState === ReadyState.Cancelled) {
|
|
||||||
throw new Error('Connection has already been resolved');
|
|
||||||
}
|
|
||||||
this.readyState = ReadyState.Done;
|
|
||||||
this.response.next(res);
|
|
||||||
this.response.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not yet implemented!
|
|
||||||
*
|
|
||||||
* Sends the provided {@link Response} to the `downloadObserver` of the `Request`
|
|
||||||
* associated with this connection.
|
|
||||||
*/
|
|
||||||
mockDownload(res: Response) {
|
|
||||||
// this.request.downloadObserver.onNext(res);
|
|
||||||
// if (res.bytesLoaded === res.totalBytes) {
|
|
||||||
// this.request.downloadObserver.onCompleted();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(jeffbcross): consider using Response type
|
|
||||||
/**
|
|
||||||
* Emits the provided error object as an error to the {@link Response} {@link EventEmitter}
|
|
||||||
* returned
|
|
||||||
* from {@link Http}.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mockError(err?: Error) {
|
|
||||||
// Matches ResourceLoader semantics
|
|
||||||
this.readyState = ReadyState.Done;
|
|
||||||
this.response.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock backend for testing the {@link Http} service.
|
|
||||||
*
|
|
||||||
* This class can be injected in tests, and should be used to override providers
|
|
||||||
* to other backends, such as {@link XHRBackend}.
|
|
||||||
*
|
|
||||||
* @usageNotes
|
|
||||||
* ### Example
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* import {Injectable, Injector} from '@angular/core';
|
|
||||||
* import {async, fakeAsync, tick} from '@angular/core/testing';
|
|
||||||
* import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions} from '@angular/http';
|
|
||||||
* import {Response, ResponseOptions} from '@angular/http';
|
|
||||||
* import {MockBackend, MockConnection} from '@angular/http/testing';
|
|
||||||
*
|
|
||||||
* const HERO_ONE = 'HeroNrOne';
|
|
||||||
* const HERO_TWO = 'WillBeAlwaysTheSecond';
|
|
||||||
*
|
|
||||||
* @Injectable()
|
|
||||||
* class HeroService {
|
|
||||||
* constructor(private http: Http) {}
|
|
||||||
*
|
|
||||||
* getHeroes(): Promise<String[]> {
|
|
||||||
* return this.http.get('myservices.de/api/heroes')
|
|
||||||
* .toPromise()
|
|
||||||
* .then(response => response.json().data)
|
|
||||||
* .catch(e => this.handleError(e));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* private handleError(error: any): Promise<any> {
|
|
||||||
* console.error('An error occurred', error);
|
|
||||||
* return Promise.reject(error.message || error);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* describe('MockBackend HeroService Example', () => {
|
|
||||||
* beforeEach(() => {
|
|
||||||
* this.injector = Injector.create([
|
|
||||||
* {provide: ConnectionBackend, useClass: MockBackend},
|
|
||||||
* {provide: RequestOptions, useClass: BaseRequestOptions},
|
|
||||||
* Http,
|
|
||||||
* HeroService,
|
|
||||||
* ]);
|
|
||||||
* this.heroService = this.injector.get(HeroService);
|
|
||||||
* this.backend = this.injector.get(ConnectionBackend) as MockBackend;
|
|
||||||
* this.backend.connections.subscribe((connection: any) => this.lastConnection = connection);
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* it('getHeroes() should query current service url', () => {
|
|
||||||
* this.heroService.getHeroes();
|
|
||||||
* expect(this.lastConnection).toBeDefined('no http service connection at all?');
|
|
||||||
* expect(this.lastConnection.request.url).toMatch(/api\/heroes$/, 'url invalid');
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* it('getHeroes() should return some heroes', fakeAsync(() => {
|
|
||||||
* let result: String[];
|
|
||||||
* this.heroService.getHeroes().then((heroes: String[]) => result = heroes);
|
|
||||||
* this.lastConnection.mockRespond(new Response(new ResponseOptions({
|
|
||||||
* body: JSON.stringify({data: [HERO_ONE, HERO_TWO]}),
|
|
||||||
* })));
|
|
||||||
* tick();
|
|
||||||
* expect(result.length).toEqual(2, 'should contain given amount of heroes');
|
|
||||||
* expect(result[0]).toEqual(HERO_ONE, ' HERO_ONE should be the first hero');
|
|
||||||
* expect(result[1]).toEqual(HERO_TWO, ' HERO_TWO should be the second hero');
|
|
||||||
* }));
|
|
||||||
*
|
|
||||||
* it('getHeroes() while server is down', fakeAsync(() => {
|
|
||||||
* let result: String[];
|
|
||||||
* let catchedError: any;
|
|
||||||
* this.heroService.getHeroes()
|
|
||||||
* .then((heroes: String[]) => result = heroes)
|
|
||||||
* .catch((error: any) => catchedError = error);
|
|
||||||
* this.lastConnection.mockError(new Response(new ResponseOptions({
|
|
||||||
* status: 404,
|
|
||||||
* statusText: 'URL not Found',
|
|
||||||
* })));
|
|
||||||
* tick();
|
|
||||||
* expect(result).toBeUndefined();
|
|
||||||
* expect(catchedError).toBeDefined();
|
|
||||||
* }));
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @deprecated see https://angular.io/guide/http
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class MockBackend implements ConnectionBackend {
|
|
||||||
/**
|
|
||||||
* {@link EventEmitter}
|
|
||||||
* of {@link MockConnection} instances that have been created by this backend. Can be subscribed
|
|
||||||
* to in order to respond to connections.
|
|
||||||
*
|
|
||||||
* This property only exists in the mock implementation, not in real Backends.
|
|
||||||
*/
|
|
||||||
connections: any; //<MockConnection>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array representation of `connections`. This array will be updated with each connection that
|
|
||||||
* is created by this backend.
|
|
||||||
*
|
|
||||||
* This property only exists in the mock implementation, not in real Backends.
|
|
||||||
*/
|
|
||||||
connectionsArray: MockConnection[];
|
|
||||||
/**
|
|
||||||
* {@link EventEmitter} of {@link MockConnection} instances that haven't yet been resolved (i.e.
|
|
||||||
* with a `readyState`
|
|
||||||
* less than 4). Used internally to verify that no connections are pending via the
|
|
||||||
* `verifyNoPendingRequests` method.
|
|
||||||
*
|
|
||||||
* This property only exists in the mock implementation, not in real Backends.
|
|
||||||
*/
|
|
||||||
pendingConnections: any; // Subject<MockConnection>
|
|
||||||
constructor() {
|
|
||||||
this.connectionsArray = [];
|
|
||||||
this.connections = new Subject();
|
|
||||||
this.connections.subscribe(
|
|
||||||
(connection: MockConnection) => this.connectionsArray.push(connection));
|
|
||||||
this.pendingConnections = new Subject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks all connections, and raises an exception if any connection has not received a response.
|
|
||||||
*
|
|
||||||
* This method only exists in the mock implementation, not in real Backends.
|
|
||||||
*/
|
|
||||||
verifyNoPendingRequests() {
|
|
||||||
let pending = 0;
|
|
||||||
this.pendingConnections.subscribe((c: MockConnection) => pending++);
|
|
||||||
if (pending > 0) throw new Error(`${pending} pending connections to be resolved`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be used in conjunction with `verifyNoPendingRequests` to resolve any not-yet-resolve
|
|
||||||
* connections, if it's expected that there are connections that have not yet received a response.
|
|
||||||
*
|
|
||||||
* This method only exists in the mock implementation, not in real Backends.
|
|
||||||
*/
|
|
||||||
resolveAllConnections() {
|
|
||||||
this.connections.subscribe((c: MockConnection) => c.readyState = 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link MockConnection}. This is equivalent to calling `new
|
|
||||||
* MockConnection()`, except that it also will emit the new `Connection` to the `connections`
|
|
||||||
* emitter of this `MockBackend` instance. This method will usually only be used by tests
|
|
||||||
* against the framework itself, not by end-users.
|
|
||||||
*/
|
|
||||||
createConnection(req: Request): MockConnection {
|
|
||||||
if (!req || !(req instanceof Request)) {
|
|
||||||
throw new Error(`createConnection requires an instance of Request, got ${req}`);
|
|
||||||
}
|
|
||||||
const connection = new MockConnection(req);
|
|
||||||
this.connections.next(connection);
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Entry point for all public APIs of the platform-server/testing package.
|
|
||||||
*/
|
|
||||||
export * from './mock_backend';
|
|
|
@ -49,8 +49,6 @@ System.config({
|
||||||
'@angular/facade': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/facade': {main: 'index.js', defaultExtension: 'js'},
|
||||||
'@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
|
||||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||||
'@angular/http/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
||||||
'@angular/http': {main: 'index.js', defaultExtension: 'js'},
|
|
||||||
'@angular/localize/src/utils': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/localize/src/utils': {main: 'index.js', defaultExtension: 'js'},
|
||||||
'@angular/localize/src/localize': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/localize/src/localize': {main: 'index.js', defaultExtension: 'js'},
|
||||||
'@angular/localize/init': {main: 'index.js', defaultExtension: 'js'},
|
'@angular/localize/init': {main: 'index.js', defaultExtension: 'js'},
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
"packages/core/src/",
|
"packages/core/src/",
|
||||||
"packages/elements/src/",
|
"packages/elements/src/",
|
||||||
"packages/forms/src/",
|
"packages/forms/src/",
|
||||||
"packages/http/src/",
|
|
||||||
"packages/platform-browser/src/",
|
"packages/platform-browser/src/",
|
||||||
"packages/router/src/"
|
"packages/router/src/"
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue