UNPKG

93.3 kBJavaScriptView Raw
1/**
2 * @license Angular v14.0.4
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import * as i1 from '@angular/common';
8import { DOCUMENT, ɵparseCookieValue, XhrFactory as XhrFactory$1 } from '@angular/common';
9import * as i0 from '@angular/core';
10import { Injectable, InjectionToken, Inject, PLATFORM_ID, NgModule } from '@angular/core';
11import { of, Observable } from 'rxjs';
12import { concatMap, filter, map } from 'rxjs/operators';
13
14/**
15 * @license
16 * Copyright Google LLC All Rights Reserved.
17 *
18 * Use of this source code is governed by an MIT-style license that can be
19 * found in the LICENSE file at https://angular.io/license
20 */
21/**
22 * Transforms an `HttpRequest` into a stream of `HttpEvent`s, one of which will likely be a
23 * `HttpResponse`.
24 *
25 * `HttpHandler` is injectable. When injected, the handler instance dispatches requests to the
26 * first interceptor in the chain, which dispatches to the second, etc, eventually reaching the
27 * `HttpBackend`.
28 *
29 * In an `HttpInterceptor`, the `HttpHandler` parameter is the next interceptor in the chain.
30 *
31 * @publicApi
32 */
33class HttpHandler {
34}
35/**
36 * A final `HttpHandler` which will dispatch the request via browser HTTP APIs to a backend.
37 *
38 * Interceptors sit between the `HttpClient` interface and the `HttpBackend`.
39 *
40 * When injected, `HttpBackend` dispatches requests directly to the backend, without going
41 * through the interceptor chain.
42 *
43 * @publicApi
44 */
45class HttpBackend {
46}
47
48/**
49 * @license
50 * Copyright Google LLC All Rights Reserved.
51 *
52 * Use of this source code is governed by an MIT-style license that can be
53 * found in the LICENSE file at https://angular.io/license
54 */
55/**
56 * Represents the header configuration options for an HTTP request.
57 * Instances are immutable. Modifying methods return a cloned
58 * instance with the change. The original object is never changed.
59 *
60 * @publicApi
61 */
62class HttpHeaders {
63 /** Constructs a new HTTP header object with the given values.*/
64 constructor(headers) {
65 /**
66 * Internal map of lowercased header names to the normalized
67 * form of the name (the form seen first).
68 */
69 this.normalizedNames = new Map();
70 /**
71 * Queued updates to be materialized the next initialization.
72 */
73 this.lazyUpdate = null;
74 if (!headers) {
75 this.headers = new Map();
76 }
77 else if (typeof headers === 'string') {
78 this.lazyInit = () => {
79 this.headers = new Map();
80 headers.split('\n').forEach(line => {
81 const index = line.indexOf(':');
82 if (index > 0) {
83 const name = line.slice(0, index);
84 const key = name.toLowerCase();
85 const value = line.slice(index + 1).trim();
86 this.maybeSetNormalizedName(name, key);
87 if (this.headers.has(key)) {
88 this.headers.get(key).push(value);
89 }
90 else {
91 this.headers.set(key, [value]);
92 }
93 }
94 });
95 };
96 }
97 else {
98 this.lazyInit = () => {
99 this.headers = new Map();
100 Object.keys(headers).forEach(name => {
101 let values = headers[name];
102 const key = name.toLowerCase();
103 if (typeof values === 'string') {
104 values = [values];
105 }
106 if (values.length > 0) {
107 this.headers.set(key, values);
108 this.maybeSetNormalizedName(name, key);
109 }
110 });
111 };
112 }
113 }
114 /**
115 * Checks for existence of a given header.
116 *
117 * @param name The header name to check for existence.
118 *
119 * @returns True if the header exists, false otherwise.
120 */
121 has(name) {
122 this.init();
123 return this.headers.has(name.toLowerCase());
124 }
125 /**
126 * Retrieves the first value of a given header.
127 *
128 * @param name The header name.
129 *
130 * @returns The value string if the header exists, null otherwise
131 */
132 get(name) {
133 this.init();
134 const values = this.headers.get(name.toLowerCase());
135 return values && values.length > 0 ? values[0] : null;
136 }
137 /**
138 * Retrieves the names of the headers.
139 *
140 * @returns A list of header names.
141 */
142 keys() {
143 this.init();
144 return Array.from(this.normalizedNames.values());
145 }
146 /**
147 * Retrieves a list of values for a given header.
148 *
149 * @param name The header name from which to retrieve values.
150 *
151 * @returns A string of values if the header exists, null otherwise.
152 */
153 getAll(name) {
154 this.init();
155 return this.headers.get(name.toLowerCase()) || null;
156 }
157 /**
158 * Appends a new value to the existing set of values for a header
159 * and returns them in a clone of the original instance.
160 *
161 * @param name The header name for which to append the values.
162 * @param value The value to append.
163 *
164 * @returns A clone of the HTTP headers object with the value appended to the given header.
165 */
166 append(name, value) {
167 return this.clone({ name, value, op: 'a' });
168 }
169 /**
170 * Sets or modifies a value for a given header in a clone of the original instance.
171 * If the header already exists, its value is replaced with the given value
172 * in the returned object.
173 *
174 * @param name The header name.
175 * @param value The value or values to set or overide for the given header.
176 *
177 * @returns A clone of the HTTP headers object with the newly set header value.
178 */
179 set(name, value) {
180 return this.clone({ name, value, op: 's' });
181 }
182 /**
183 * Deletes values for a given header in a clone of the original instance.
184 *
185 * @param name The header name.
186 * @param value The value or values to delete for the given header.
187 *
188 * @returns A clone of the HTTP headers object with the given value deleted.
189 */
190 delete(name, value) {
191 return this.clone({ name, value, op: 'd' });
192 }
193 maybeSetNormalizedName(name, lcName) {
194 if (!this.normalizedNames.has(lcName)) {
195 this.normalizedNames.set(lcName, name);
196 }
197 }
198 init() {
199 if (!!this.lazyInit) {
200 if (this.lazyInit instanceof HttpHeaders) {
201 this.copyFrom(this.lazyInit);
202 }
203 else {
204 this.lazyInit();
205 }
206 this.lazyInit = null;
207 if (!!this.lazyUpdate) {
208 this.lazyUpdate.forEach(update => this.applyUpdate(update));
209 this.lazyUpdate = null;
210 }
211 }
212 }
213 copyFrom(other) {
214 other.init();
215 Array.from(other.headers.keys()).forEach(key => {
216 this.headers.set(key, other.headers.get(key));
217 this.normalizedNames.set(key, other.normalizedNames.get(key));
218 });
219 }
220 clone(update) {
221 const clone = new HttpHeaders();
222 clone.lazyInit =
223 (!!this.lazyInit && this.lazyInit instanceof HttpHeaders) ? this.lazyInit : this;
224 clone.lazyUpdate = (this.lazyUpdate || []).concat([update]);
225 return clone;
226 }
227 applyUpdate(update) {
228 const key = update.name.toLowerCase();
229 switch (update.op) {
230 case 'a':
231 case 's':
232 let value = update.value;
233 if (typeof value === 'string') {
234 value = [value];
235 }
236 if (value.length === 0) {
237 return;
238 }
239 this.maybeSetNormalizedName(update.name, key);
240 const base = (update.op === 'a' ? this.headers.get(key) : undefined) || [];
241 base.push(...value);
242 this.headers.set(key, base);
243 break;
244 case 'd':
245 const toDelete = update.value;
246 if (!toDelete) {
247 this.headers.delete(key);
248 this.normalizedNames.delete(key);
249 }
250 else {
251 let existing = this.headers.get(key);
252 if (!existing) {
253 return;
254 }
255 existing = existing.filter(value => toDelete.indexOf(value) === -1);
256 if (existing.length === 0) {
257 this.headers.delete(key);
258 this.normalizedNames.delete(key);
259 }
260 else {
261 this.headers.set(key, existing);
262 }
263 }
264 break;
265 }
266 }
267 /**
268 * @internal
269 */
270 forEach(fn) {
271 this.init();
272 Array.from(this.normalizedNames.keys())
273 .forEach(key => fn(this.normalizedNames.get(key), this.headers.get(key)));
274 }
275}
276
277/**
278 * @license
279 * Copyright Google LLC All Rights Reserved.
280 *
281 * Use of this source code is governed by an MIT-style license that can be
282 * found in the LICENSE file at https://angular.io/license
283 */
284/**
285 * Provides encoding and decoding of URL parameter and query-string values.
286 *
287 * Serializes and parses URL parameter keys and values to encode and decode them.
288 * If you pass URL query parameters without encoding,
289 * the query parameters can be misinterpreted at the receiving end.
290 *
291 *
292 * @publicApi
293 */
294class HttpUrlEncodingCodec {
295 /**
296 * Encodes a key name for a URL parameter or query-string.
297 * @param key The key name.
298 * @returns The encoded key name.
299 */
300 encodeKey(key) {
301 return standardEncoding(key);
302 }
303 /**
304 * Encodes the value of a URL parameter or query-string.
305 * @param value The value.
306 * @returns The encoded value.
307 */
308 encodeValue(value) {
309 return standardEncoding(value);
310 }
311 /**
312 * Decodes an encoded URL parameter or query-string key.
313 * @param key The encoded key name.
314 * @returns The decoded key name.
315 */
316 decodeKey(key) {
317 return decodeURIComponent(key);
318 }
319 /**
320 * Decodes an encoded URL parameter or query-string value.
321 * @param value The encoded value.
322 * @returns The decoded value.
323 */
324 decodeValue(value) {
325 return decodeURIComponent(value);
326 }
327}
328function paramParser(rawParams, codec) {
329 const map = new Map();
330 if (rawParams.length > 0) {
331 // The `window.location.search` can be used while creating an instance of the `HttpParams` class
332 // (e.g. `new HttpParams({ fromString: window.location.search })`). The `window.location.search`
333 // may start with the `?` char, so we strip it if it's present.
334 const params = rawParams.replace(/^\?/, '').split('&');
335 params.forEach((param) => {
336 const eqIdx = param.indexOf('=');
337 const [key, val] = eqIdx == -1 ?
338 [codec.decodeKey(param), ''] :
339 [codec.decodeKey(param.slice(0, eqIdx)), codec.decodeValue(param.slice(eqIdx + 1))];
340 const list = map.get(key) || [];
341 list.push(val);
342 map.set(key, list);
343 });
344 }
345 return map;
346}
347/**
348 * Encode input string with standard encodeURIComponent and then un-encode specific characters.
349 */
350const STANDARD_ENCODING_REGEX = /%(\d[a-f0-9])/gi;
351const STANDARD_ENCODING_REPLACEMENTS = {
352 '40': '@',
353 '3A': ':',
354 '24': '$',
355 '2C': ',',
356 '3B': ';',
357 '3D': '=',
358 '3F': '?',
359 '2F': '/',
360};
361function standardEncoding(v) {
362 return encodeURIComponent(v).replace(STANDARD_ENCODING_REGEX, (s, t) => STANDARD_ENCODING_REPLACEMENTS[t] ?? s);
363}
364function valueToString(value) {
365 return `${value}`;
366}
367/**
368 * An HTTP request/response body that represents serialized parameters,
369 * per the MIME type `application/x-www-form-urlencoded`.
370 *
371 * This class is immutable; all mutation operations return a new instance.
372 *
373 * @publicApi
374 */
375class HttpParams {
376 constructor(options = {}) {
377 this.updates = null;
378 this.cloneFrom = null;
379 this.encoder = options.encoder || new HttpUrlEncodingCodec();
380 if (!!options.fromString) {
381 if (!!options.fromObject) {
382 throw new Error(`Cannot specify both fromString and fromObject.`);
383 }
384 this.map = paramParser(options.fromString, this.encoder);
385 }
386 else if (!!options.fromObject) {
387 this.map = new Map();
388 Object.keys(options.fromObject).forEach(key => {
389 const value = options.fromObject[key];
390 // convert the values to strings
391 const values = Array.isArray(value) ? value.map(valueToString) : [valueToString(value)];
392 this.map.set(key, values);
393 });
394 }
395 else {
396 this.map = null;
397 }
398 }
399 /**
400 * Reports whether the body includes one or more values for a given parameter.
401 * @param param The parameter name.
402 * @returns True if the parameter has one or more values,
403 * false if it has no value or is not present.
404 */
405 has(param) {
406 this.init();
407 return this.map.has(param);
408 }
409 /**
410 * Retrieves the first value for a parameter.
411 * @param param The parameter name.
412 * @returns The first value of the given parameter,
413 * or `null` if the parameter is not present.
414 */
415 get(param) {
416 this.init();
417 const res = this.map.get(param);
418 return !!res ? res[0] : null;
419 }
420 /**
421 * Retrieves all values for a parameter.
422 * @param param The parameter name.
423 * @returns All values in a string array,
424 * or `null` if the parameter not present.
425 */
426 getAll(param) {
427 this.init();
428 return this.map.get(param) || null;
429 }
430 /**
431 * Retrieves all the parameters for this body.
432 * @returns The parameter names in a string array.
433 */
434 keys() {
435 this.init();
436 return Array.from(this.map.keys());
437 }
438 /**
439 * Appends a new value to existing values for a parameter.
440 * @param param The parameter name.
441 * @param value The new value to add.
442 * @return A new body with the appended value.
443 */
444 append(param, value) {
445 return this.clone({ param, value, op: 'a' });
446 }
447 /**
448 * Constructs a new body with appended values for the given parameter name.
449 * @param params parameters and values
450 * @return A new body with the new value.
451 */
452 appendAll(params) {
453 const updates = [];
454 Object.keys(params).forEach(param => {
455 const value = params[param];
456 if (Array.isArray(value)) {
457 value.forEach(_value => {
458 updates.push({ param, value: _value, op: 'a' });
459 });
460 }
461 else {
462 updates.push({ param, value: value, op: 'a' });
463 }
464 });
465 return this.clone(updates);
466 }
467 /**
468 * Replaces the value for a parameter.
469 * @param param The parameter name.
470 * @param value The new value.
471 * @return A new body with the new value.
472 */
473 set(param, value) {
474 return this.clone({ param, value, op: 's' });
475 }
476 /**
477 * Removes a given value or all values from a parameter.
478 * @param param The parameter name.
479 * @param value The value to remove, if provided.
480 * @return A new body with the given value removed, or with all values
481 * removed if no value is specified.
482 */
483 delete(param, value) {
484 return this.clone({ param, value, op: 'd' });
485 }
486 /**
487 * Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
488 * separated by `&`s.
489 */
490 toString() {
491 this.init();
492 return this.keys()
493 .map(key => {
494 const eKey = this.encoder.encodeKey(key);
495 // `a: ['1']` produces `'a=1'`
496 // `b: []` produces `''`
497 // `c: ['1', '2']` produces `'c=1&c=2'`
498 return this.map.get(key).map(value => eKey + '=' + this.encoder.encodeValue(value))
499 .join('&');
500 })
501 // filter out empty values because `b: []` produces `''`
502 // which results in `a=1&&c=1&c=2` instead of `a=1&c=1&c=2` if we don't
503 .filter(param => param !== '')
504 .join('&');
505 }
506 clone(update) {
507 const clone = new HttpParams({ encoder: this.encoder });
508 clone.cloneFrom = this.cloneFrom || this;
509 clone.updates = (this.updates || []).concat(update);
510 return clone;
511 }
512 init() {
513 if (this.map === null) {
514 this.map = new Map();
515 }
516 if (this.cloneFrom !== null) {
517 this.cloneFrom.init();
518 this.cloneFrom.keys().forEach(key => this.map.set(key, this.cloneFrom.map.get(key)));
519 this.updates.forEach(update => {
520 switch (update.op) {
521 case 'a':
522 case 's':
523 const base = (update.op === 'a' ? this.map.get(update.param) : undefined) || [];
524 base.push(valueToString(update.value));
525 this.map.set(update.param, base);
526 break;
527 case 'd':
528 if (update.value !== undefined) {
529 let base = this.map.get(update.param) || [];
530 const idx = base.indexOf(valueToString(update.value));
531 if (idx !== -1) {
532 base.splice(idx, 1);
533 }
534 if (base.length > 0) {
535 this.map.set(update.param, base);
536 }
537 else {
538 this.map.delete(update.param);
539 }
540 }
541 else {
542 this.map.delete(update.param);
543 break;
544 }
545 }
546 });
547 this.cloneFrom = this.updates = null;
548 }
549 }
550}
551
552/**
553 * @license
554 * Copyright Google LLC All Rights Reserved.
555 *
556 * Use of this source code is governed by an MIT-style license that can be
557 * found in the LICENSE file at https://angular.io/license
558 */
559/**
560 * A token used to manipulate and access values stored in `HttpContext`.
561 *
562 * @publicApi
563 */
564class HttpContextToken {
565 constructor(defaultValue) {
566 this.defaultValue = defaultValue;
567 }
568}
569/**
570 * Http context stores arbitrary user defined values and ensures type safety without
571 * actually knowing the types. It is backed by a `Map` and guarantees that keys do not clash.
572 *
573 * This context is mutable and is shared between cloned requests unless explicitly specified.
574 *
575 * @usageNotes
576 *
577 * ### Usage Example
578 *
579 * ```typescript
580 * // inside cache.interceptors.ts
581 * export const IS_CACHE_ENABLED = new HttpContextToken<boolean>(() => false);
582 *
583 * export class CacheInterceptor implements HttpInterceptor {
584 *
585 * intercept(req: HttpRequest<any>, delegate: HttpHandler): Observable<HttpEvent<any>> {
586 * if (req.context.get(IS_CACHE_ENABLED) === true) {
587 * return ...;
588 * }
589 * return delegate.handle(req);
590 * }
591 * }
592 *
593 * // inside a service
594 *
595 * this.httpClient.get('/api/weather', {
596 * context: new HttpContext().set(IS_CACHE_ENABLED, true)
597 * }).subscribe(...);
598 * ```
599 *
600 * @publicApi
601 */
602class HttpContext {
603 constructor() {
604 this.map = new Map();
605 }
606 /**
607 * Store a value in the context. If a value is already present it will be overwritten.
608 *
609 * @param token The reference to an instance of `HttpContextToken`.
610 * @param value The value to store.
611 *
612 * @returns A reference to itself for easy chaining.
613 */
614 set(token, value) {
615 this.map.set(token, value);
616 return this;
617 }
618 /**
619 * Retrieve the value associated with the given token.
620 *
621 * @param token The reference to an instance of `HttpContextToken`.
622 *
623 * @returns The stored value or default if one is defined.
624 */
625 get(token) {
626 if (!this.map.has(token)) {
627 this.map.set(token, token.defaultValue());
628 }
629 return this.map.get(token);
630 }
631 /**
632 * Delete the value associated with the given token.
633 *
634 * @param token The reference to an instance of `HttpContextToken`.
635 *
636 * @returns A reference to itself for easy chaining.
637 */
638 delete(token) {
639 this.map.delete(token);
640 return this;
641 }
642 /**
643 * Checks for existence of a given token.
644 *
645 * @param token The reference to an instance of `HttpContextToken`.
646 *
647 * @returns True if the token exists, false otherwise.
648 */
649 has(token) {
650 return this.map.has(token);
651 }
652 /**
653 * @returns a list of tokens currently stored in the context.
654 */
655 keys() {
656 return this.map.keys();
657 }
658}
659
660/**
661 * @license
662 * Copyright Google LLC All Rights Reserved.
663 *
664 * Use of this source code is governed by an MIT-style license that can be
665 * found in the LICENSE file at https://angular.io/license
666 */
667/**
668 * Determine whether the given HTTP method may include a body.
669 */
670function mightHaveBody(method) {
671 switch (method) {
672 case 'DELETE':
673 case 'GET':
674 case 'HEAD':
675 case 'OPTIONS':
676 case 'JSONP':
677 return false;
678 default:
679 return true;
680 }
681}
682/**
683 * Safely assert whether the given value is an ArrayBuffer.
684 *
685 * In some execution environments ArrayBuffer is not defined.
686 */
687function isArrayBuffer(value) {
688 return typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer;
689}
690/**
691 * Safely assert whether the given value is a Blob.
692 *
693 * In some execution environments Blob is not defined.
694 */
695function isBlob(value) {
696 return typeof Blob !== 'undefined' && value instanceof Blob;
697}
698/**
699 * Safely assert whether the given value is a FormData instance.
700 *
701 * In some execution environments FormData is not defined.
702 */
703function isFormData(value) {
704 return typeof FormData !== 'undefined' && value instanceof FormData;
705}
706/**
707 * Safely assert whether the given value is a URLSearchParams instance.
708 *
709 * In some execution environments URLSearchParams is not defined.
710 */
711function isUrlSearchParams(value) {
712 return typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams;
713}
714/**
715 * An outgoing HTTP request with an optional typed body.
716 *
717 * `HttpRequest` represents an outgoing request, including URL, method,
718 * headers, body, and other request configuration options. Instances should be
719 * assumed to be immutable. To modify a `HttpRequest`, the `clone`
720 * method should be used.
721 *
722 * @publicApi
723 */
724class HttpRequest {
725 constructor(method, url, third, fourth) {
726 this.url = url;
727 /**
728 * The request body, or `null` if one isn't set.
729 *
730 * Bodies are not enforced to be immutable, as they can include a reference to any
731 * user-defined data type. However, interceptors should take care to preserve
732 * idempotence by treating them as such.
733 */
734 this.body = null;
735 /**
736 * Whether this request should be made in a way that exposes progress events.
737 *
738 * Progress events are expensive (change detection runs on each event) and so
739 * they should only be requested if the consumer intends to monitor them.
740 */
741 this.reportProgress = false;
742 /**
743 * Whether this request should be sent with outgoing credentials (cookies).
744 */
745 this.withCredentials = false;
746 /**
747 * The expected response type of the server.
748 *
749 * This is used to parse the response appropriately before returning it to
750 * the requestee.
751 */
752 this.responseType = 'json';
753 this.method = method.toUpperCase();
754 // Next, need to figure out which argument holds the HttpRequestInit
755 // options, if any.
756 let options;
757 // Check whether a body argument is expected. The only valid way to omit
758 // the body argument is to use a known no-body method like GET.
759 if (mightHaveBody(this.method) || !!fourth) {
760 // Body is the third argument, options are the fourth.
761 this.body = (third !== undefined) ? third : null;
762 options = fourth;
763 }
764 else {
765 // No body required, options are the third argument. The body stays null.
766 options = third;
767 }
768 // If options have been passed, interpret them.
769 if (options) {
770 // Normalize reportProgress and withCredentials.
771 this.reportProgress = !!options.reportProgress;
772 this.withCredentials = !!options.withCredentials;
773 // Override default response type of 'json' if one is provided.
774 if (!!options.responseType) {
775 this.responseType = options.responseType;
776 }
777 // Override headers if they're provided.
778 if (!!options.headers) {
779 this.headers = options.headers;
780 }
781 if (!!options.context) {
782 this.context = options.context;
783 }
784 if (!!options.params) {
785 this.params = options.params;
786 }
787 }
788 // If no headers have been passed in, construct a new HttpHeaders instance.
789 if (!this.headers) {
790 this.headers = new HttpHeaders();
791 }
792 // If no context have been passed in, construct a new HttpContext instance.
793 if (!this.context) {
794 this.context = new HttpContext();
795 }
796 // If no parameters have been passed in, construct a new HttpUrlEncodedParams instance.
797 if (!this.params) {
798 this.params = new HttpParams();
799 this.urlWithParams = url;
800 }
801 else {
802 // Encode the parameters to a string in preparation for inclusion in the URL.
803 const params = this.params.toString();
804 if (params.length === 0) {
805 // No parameters, the visible URL is just the URL given at creation time.
806 this.urlWithParams = url;
807 }
808 else {
809 // Does the URL already have query parameters? Look for '?'.
810 const qIdx = url.indexOf('?');
811 // There are 3 cases to handle:
812 // 1) No existing parameters -> append '?' followed by params.
813 // 2) '?' exists and is followed by existing query string ->
814 // append '&' followed by params.
815 // 3) '?' exists at the end of the url -> append params directly.
816 // This basically amounts to determining the character, if any, with
817 // which to join the URL and parameters.
818 const sep = qIdx === -1 ? '?' : (qIdx < url.length - 1 ? '&' : '');
819 this.urlWithParams = url + sep + params;
820 }
821 }
822 }
823 /**
824 * Transform the free-form body into a serialized format suitable for
825 * transmission to the server.
826 */
827 serializeBody() {
828 // If no body is present, no need to serialize it.
829 if (this.body === null) {
830 return null;
831 }
832 // Check whether the body is already in a serialized form. If so,
833 // it can just be returned directly.
834 if (isArrayBuffer(this.body) || isBlob(this.body) || isFormData(this.body) ||
835 isUrlSearchParams(this.body) || typeof this.body === 'string') {
836 return this.body;
837 }
838 // Check whether the body is an instance of HttpUrlEncodedParams.
839 if (this.body instanceof HttpParams) {
840 return this.body.toString();
841 }
842 // Check whether the body is an object or array, and serialize with JSON if so.
843 if (typeof this.body === 'object' || typeof this.body === 'boolean' ||
844 Array.isArray(this.body)) {
845 return JSON.stringify(this.body);
846 }
847 // Fall back on toString() for everything else.
848 return this.body.toString();
849 }
850 /**
851 * Examine the body and attempt to infer an appropriate MIME type
852 * for it.
853 *
854 * If no such type can be inferred, this method will return `null`.
855 */
856 detectContentTypeHeader() {
857 // An empty body has no content type.
858 if (this.body === null) {
859 return null;
860 }
861 // FormData bodies rely on the browser's content type assignment.
862 if (isFormData(this.body)) {
863 return null;
864 }
865 // Blobs usually have their own content type. If it doesn't, then
866 // no type can be inferred.
867 if (isBlob(this.body)) {
868 return this.body.type || null;
869 }
870 // Array buffers have unknown contents and thus no type can be inferred.
871 if (isArrayBuffer(this.body)) {
872 return null;
873 }
874 // Technically, strings could be a form of JSON data, but it's safe enough
875 // to assume they're plain strings.
876 if (typeof this.body === 'string') {
877 return 'text/plain';
878 }
879 // `HttpUrlEncodedParams` has its own content-type.
880 if (this.body instanceof HttpParams) {
881 return 'application/x-www-form-urlencoded;charset=UTF-8';
882 }
883 // Arrays, objects, boolean and numbers will be encoded as JSON.
884 if (typeof this.body === 'object' || typeof this.body === 'number' ||
885 typeof this.body === 'boolean') {
886 return 'application/json';
887 }
888 // No type could be inferred.
889 return null;
890 }
891 clone(update = {}) {
892 // For method, url, and responseType, take the current value unless
893 // it is overridden in the update hash.
894 const method = update.method || this.method;
895 const url = update.url || this.url;
896 const responseType = update.responseType || this.responseType;
897 // The body is somewhat special - a `null` value in update.body means
898 // whatever current body is present is being overridden with an empty
899 // body, whereas an `undefined` value in update.body implies no
900 // override.
901 const body = (update.body !== undefined) ? update.body : this.body;
902 // Carefully handle the boolean options to differentiate between
903 // `false` and `undefined` in the update args.
904 const withCredentials = (update.withCredentials !== undefined) ? update.withCredentials : this.withCredentials;
905 const reportProgress = (update.reportProgress !== undefined) ? update.reportProgress : this.reportProgress;
906 // Headers and params may be appended to if `setHeaders` or
907 // `setParams` are used.
908 let headers = update.headers || this.headers;
909 let params = update.params || this.params;
910 // Pass on context if needed
911 const context = update.context ?? this.context;
912 // Check whether the caller has asked to add headers.
913 if (update.setHeaders !== undefined) {
914 // Set every requested header.
915 headers =
916 Object.keys(update.setHeaders)
917 .reduce((headers, name) => headers.set(name, update.setHeaders[name]), headers);
918 }
919 // Check whether the caller has asked to set params.
920 if (update.setParams) {
921 // Set every requested param.
922 params = Object.keys(update.setParams)
923 .reduce((params, param) => params.set(param, update.setParams[param]), params);
924 }
925 // Finally, construct the new HttpRequest using the pieces from above.
926 return new HttpRequest(method, url, body, {
927 params,
928 headers,
929 context,
930 reportProgress,
931 responseType,
932 withCredentials,
933 });
934 }
935}
936
937/**
938 * @license
939 * Copyright Google LLC All Rights Reserved.
940 *
941 * Use of this source code is governed by an MIT-style license that can be
942 * found in the LICENSE file at https://angular.io/license
943 */
944/**
945 * Type enumeration for the different kinds of `HttpEvent`.
946 *
947 * @publicApi
948 */
949var HttpEventType;
950(function (HttpEventType) {
951 /**
952 * The request was sent out over the wire.
953 */
954 HttpEventType[HttpEventType["Sent"] = 0] = "Sent";
955 /**
956 * An upload progress event was received.
957 */
958 HttpEventType[HttpEventType["UploadProgress"] = 1] = "UploadProgress";
959 /**
960 * The response status code and headers were received.
961 */
962 HttpEventType[HttpEventType["ResponseHeader"] = 2] = "ResponseHeader";
963 /**
964 * A download progress event was received.
965 */
966 HttpEventType[HttpEventType["DownloadProgress"] = 3] = "DownloadProgress";
967 /**
968 * The full response including the body was received.
969 */
970 HttpEventType[HttpEventType["Response"] = 4] = "Response";
971 /**
972 * A custom event from an interceptor or a backend.
973 */
974 HttpEventType[HttpEventType["User"] = 5] = "User";
975})(HttpEventType || (HttpEventType = {}));
976/**
977 * Base class for both `HttpResponse` and `HttpHeaderResponse`.
978 *
979 * @publicApi
980 */
981class HttpResponseBase {
982 /**
983 * Super-constructor for all responses.
984 *
985 * The single parameter accepted is an initialization hash. Any properties
986 * of the response passed there will override the default values.
987 */
988 constructor(init, defaultStatus = 200 /* HttpStatusCode.Ok */, defaultStatusText = 'OK') {
989 // If the hash has values passed, use them to initialize the response.
990 // Otherwise use the default values.
991 this.headers = init.headers || new HttpHeaders();
992 this.status = init.status !== undefined ? init.status : defaultStatus;
993 this.statusText = init.statusText || defaultStatusText;
994 this.url = init.url || null;
995 // Cache the ok value to avoid defining a getter.
996 this.ok = this.status >= 200 && this.status < 300;
997 }
998}
999/**
1000 * A partial HTTP response which only includes the status and header data,
1001 * but no response body.
1002 *
1003 * `HttpHeaderResponse` is a `HttpEvent` available on the response
1004 * event stream, only when progress events are requested.
1005 *
1006 * @publicApi
1007 */
1008class HttpHeaderResponse extends HttpResponseBase {
1009 /**
1010 * Create a new `HttpHeaderResponse` with the given parameters.
1011 */
1012 constructor(init = {}) {
1013 super(init);
1014 this.type = HttpEventType.ResponseHeader;
1015 }
1016 /**
1017 * Copy this `HttpHeaderResponse`, overriding its contents with the
1018 * given parameter hash.
1019 */
1020 clone(update = {}) {
1021 // Perform a straightforward initialization of the new HttpHeaderResponse,
1022 // overriding the current parameters with new ones if given.
1023 return new HttpHeaderResponse({
1024 headers: update.headers || this.headers,
1025 status: update.status !== undefined ? update.status : this.status,
1026 statusText: update.statusText || this.statusText,
1027 url: update.url || this.url || undefined,
1028 });
1029 }
1030}
1031/**
1032 * A full HTTP response, including a typed response body (which may be `null`
1033 * if one was not returned).
1034 *
1035 * `HttpResponse` is a `HttpEvent` available on the response event
1036 * stream.
1037 *
1038 * @publicApi
1039 */
1040class HttpResponse extends HttpResponseBase {
1041 /**
1042 * Construct a new `HttpResponse`.
1043 */
1044 constructor(init = {}) {
1045 super(init);
1046 this.type = HttpEventType.Response;
1047 this.body = init.body !== undefined ? init.body : null;
1048 }
1049 clone(update = {}) {
1050 return new HttpResponse({
1051 body: (update.body !== undefined) ? update.body : this.body,
1052 headers: update.headers || this.headers,
1053 status: (update.status !== undefined) ? update.status : this.status,
1054 statusText: update.statusText || this.statusText,
1055 url: update.url || this.url || undefined,
1056 });
1057 }
1058}
1059/**
1060 * A response that represents an error or failure, either from a
1061 * non-successful HTTP status, an error while executing the request,
1062 * or some other failure which occurred during the parsing of the response.
1063 *
1064 * Any error returned on the `Observable` response stream will be
1065 * wrapped in an `HttpErrorResponse` to provide additional context about
1066 * the state of the HTTP layer when the error occurred. The error property
1067 * will contain either a wrapped Error object or the error response returned
1068 * from the server.
1069 *
1070 * @publicApi
1071 */
1072class HttpErrorResponse extends HttpResponseBase {
1073 constructor(init) {
1074 // Initialize with a default status of 0 / Unknown Error.
1075 super(init, 0, 'Unknown Error');
1076 this.name = 'HttpErrorResponse';
1077 /**
1078 * Errors are never okay, even when the status code is in the 2xx success range.
1079 */
1080 this.ok = false;
1081 // If the response was successful, then this was a parse error. Otherwise, it was
1082 // a protocol-level failure of some sort. Either the request failed in transit
1083 // or the server returned an unsuccessful status code.
1084 if (this.status >= 200 && this.status < 300) {
1085 this.message = `Http failure during parsing for ${init.url || '(unknown url)'}`;
1086 }
1087 else {
1088 this.message = `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${init.statusText}`;
1089 }
1090 this.error = init.error || null;
1091 }
1092}
1093
1094/**
1095 * @license
1096 * Copyright Google LLC All Rights Reserved.
1097 *
1098 * Use of this source code is governed by an MIT-style license that can be
1099 * found in the LICENSE file at https://angular.io/license
1100 */
1101/**
1102 * Constructs an instance of `HttpRequestOptions<T>` from a source `HttpMethodOptions` and
1103 * the given `body`. This function clones the object and adds the body.
1104 *
1105 * Note that the `responseType` *options* value is a String that identifies the
1106 * single data type of the response.
1107 * A single overload version of the method handles each response type.
1108 * The value of `responseType` cannot be a union, as the combined signature could imply.
1109 *
1110 */
1111function addBody(options, body) {
1112 return {
1113 body,
1114 headers: options.headers,
1115 context: options.context,
1116 observe: options.observe,
1117 params: options.params,
1118 reportProgress: options.reportProgress,
1119 responseType: options.responseType,
1120 withCredentials: options.withCredentials,
1121 };
1122}
1123/**
1124 * Performs HTTP requests.
1125 * This service is available as an injectable class, with methods to perform HTTP requests.
1126 * Each request method has multiple signatures, and the return type varies based on
1127 * the signature that is called (mainly the values of `observe` and `responseType`).
1128 *
1129 * Note that the `responseType` *options* value is a String that identifies the
1130 * single data type of the response.
1131 * A single overload version of the method handles each response type.
1132 * The value of `responseType` cannot be a union, as the combined signature could imply.
1133
1134 *
1135 * @usageNotes
1136 * Sample HTTP requests for the [Tour of Heroes](/tutorial/toh-pt0) application.
1137 *
1138 * ### HTTP Request Example
1139 *
1140 * ```
1141 * // GET heroes whose name contains search term
1142 * searchHeroes(term: string): observable<Hero[]>{
1143 *
1144 * const params = new HttpParams({fromString: 'name=term'});
1145 * return this.httpClient.request('GET', this.heroesUrl, {responseType:'json', params});
1146 * }
1147 * ```
1148 *
1149 * Alternatively, the parameter string can be used without invoking HttpParams
1150 * by directly joining to the URL.
1151 * ```
1152 * this.httpClient.request('GET', this.heroesUrl + '?' + 'name=term', {responseType:'json'});
1153 * ```
1154 *
1155 *
1156 * ### JSONP Example
1157 * ```
1158 * requestJsonp(url, callback = 'callback') {
1159 * return this.httpClient.jsonp(this.heroesURL, callback);
1160 * }
1161 * ```
1162 *
1163 * ### PATCH Example
1164 * ```
1165 * // PATCH one of the heroes' name
1166 * patchHero (id: number, heroName: string): Observable<{}> {
1167 * const url = `${this.heroesUrl}/${id}`; // PATCH api/heroes/42
1168 * return this.httpClient.patch(url, {name: heroName}, httpOptions)
1169 * .pipe(catchError(this.handleError('patchHero')));
1170 * }
1171 * ```
1172 *
1173 * @see [HTTP Guide](guide/http)
1174 * @see [HTTP Request](api/common/http/HttpRequest)
1175 *
1176 * @publicApi
1177 */
1178class HttpClient {
1179 constructor(handler) {
1180 this.handler = handler;
1181 }
1182 /**
1183 * Constructs an observable for a generic HTTP request that, when subscribed,
1184 * fires the request through the chain of registered interceptors and on to the
1185 * server.
1186 *
1187 * You can pass an `HttpRequest` directly as the only parameter. In this case,
1188 * the call returns an observable of the raw `HttpEvent` stream.
1189 *
1190 * Alternatively you can pass an HTTP method as the first parameter,
1191 * a URL string as the second, and an options hash containing the request body as the third.
1192 * See `addBody()`. In this case, the specified `responseType` and `observe` options determine the
1193 * type of returned observable.
1194 * * The `responseType` value determines how a successful response body is parsed.
1195 * * If `responseType` is the default `json`, you can pass a type interface for the resulting
1196 * object as a type parameter to the call.
1197 *
1198 * The `observe` value determines the return type, according to what you are interested in
1199 * observing.
1200 * * An `observe` value of events returns an observable of the raw `HttpEvent` stream, including
1201 * progress events by default.
1202 * * An `observe` value of response returns an observable of `HttpResponse<T>`,
1203 * where the `T` parameter depends on the `responseType` and any optionally provided type
1204 * parameter.
1205 * * An `observe` value of body returns an observable of `<T>` with the same `T` body type.
1206 *
1207 */
1208 request(first, url, options = {}) {
1209 let req;
1210 // First, check whether the primary argument is an instance of `HttpRequest`.
1211 if (first instanceof HttpRequest) {
1212 // It is. The other arguments must be undefined (per the signatures) and can be
1213 // ignored.
1214 req = first;
1215 }
1216 else {
1217 // It's a string, so it represents a URL. Construct a request based on it,
1218 // and incorporate the remaining arguments (assuming `GET` unless a method is
1219 // provided.
1220 // Figure out the headers.
1221 let headers = undefined;
1222 if (options.headers instanceof HttpHeaders) {
1223 headers = options.headers;
1224 }
1225 else {
1226 headers = new HttpHeaders(options.headers);
1227 }
1228 // Sort out parameters.
1229 let params = undefined;
1230 if (!!options.params) {
1231 if (options.params instanceof HttpParams) {
1232 params = options.params;
1233 }
1234 else {
1235 params = new HttpParams({ fromObject: options.params });
1236 }
1237 }
1238 // Construct the request.
1239 req = new HttpRequest(first, url, (options.body !== undefined ? options.body : null), {
1240 headers,
1241 context: options.context,
1242 params,
1243 reportProgress: options.reportProgress,
1244 // By default, JSON is assumed to be returned for all calls.
1245 responseType: options.responseType || 'json',
1246 withCredentials: options.withCredentials,
1247 });
1248 }
1249 // Start with an Observable.of() the initial request, and run the handler (which
1250 // includes all interceptors) inside a concatMap(). This way, the handler runs
1251 // inside an Observable chain, which causes interceptors to be re-run on every
1252 // subscription (this also makes retries re-run the handler, including interceptors).
1253 const events$ = of(req).pipe(concatMap((req) => this.handler.handle(req)));
1254 // If coming via the API signature which accepts a previously constructed HttpRequest,
1255 // the only option is to get the event stream. Otherwise, return the event stream if
1256 // that is what was requested.
1257 if (first instanceof HttpRequest || options.observe === 'events') {
1258 return events$;
1259 }
1260 // The requested stream contains either the full response or the body. In either
1261 // case, the first step is to filter the event stream to extract a stream of
1262 // responses(s).
1263 const res$ = events$.pipe(filter((event) => event instanceof HttpResponse));
1264 // Decide which stream to return.
1265 switch (options.observe || 'body') {
1266 case 'body':
1267 // The requested stream is the body. Map the response stream to the response
1268 // body. This could be done more simply, but a misbehaving interceptor might
1269 // transform the response body into a different format and ignore the requested
1270 // responseType. Guard against this by validating that the response is of the
1271 // requested type.
1272 switch (req.responseType) {
1273 case 'arraybuffer':
1274 return res$.pipe(map((res) => {
1275 // Validate that the body is an ArrayBuffer.
1276 if (res.body !== null && !(res.body instanceof ArrayBuffer)) {
1277 throw new Error('Response is not an ArrayBuffer.');
1278 }
1279 return res.body;
1280 }));
1281 case 'blob':
1282 return res$.pipe(map((res) => {
1283 // Validate that the body is a Blob.
1284 if (res.body !== null && !(res.body instanceof Blob)) {
1285 throw new Error('Response is not a Blob.');
1286 }
1287 return res.body;
1288 }));
1289 case 'text':
1290 return res$.pipe(map((res) => {
1291 // Validate that the body is a string.
1292 if (res.body !== null && typeof res.body !== 'string') {
1293 throw new Error('Response is not a string.');
1294 }
1295 return res.body;
1296 }));
1297 case 'json':
1298 default:
1299 // No validation needed for JSON responses, as they can be of any type.
1300 return res$.pipe(map((res) => res.body));
1301 }
1302 case 'response':
1303 // The response stream was requested directly, so return it.
1304 return res$;
1305 default:
1306 // Guard against new future observe types being added.
1307 throw new Error(`Unreachable: unhandled observe type ${options.observe}}`);
1308 }
1309 }
1310 /**
1311 * Constructs an observable that, when subscribed, causes the configured
1312 * `DELETE` request to execute on the server. See the individual overloads for
1313 * details on the return type.
1314 *
1315 * @param url The endpoint URL.
1316 * @param options The HTTP options to send with the request.
1317 *
1318 */
1319 delete(url, options = {}) {
1320 return this.request('DELETE', url, options);
1321 }
1322 /**
1323 * Constructs an observable that, when subscribed, causes the configured
1324 * `GET` request to execute on the server. See the individual overloads for
1325 * details on the return type.
1326 */
1327 get(url, options = {}) {
1328 return this.request('GET', url, options);
1329 }
1330 /**
1331 * Constructs an observable that, when subscribed, causes the configured
1332 * `HEAD` request to execute on the server. The `HEAD` method returns
1333 * meta information about the resource without transferring the
1334 * resource itself. See the individual overloads for
1335 * details on the return type.
1336 */
1337 head(url, options = {}) {
1338 return this.request('HEAD', url, options);
1339 }
1340 /**
1341 * Constructs an `Observable` that, when subscribed, causes a request with the special method
1342 * `JSONP` to be dispatched via the interceptor pipeline.
1343 * The [JSONP pattern](https://en.wikipedia.org/wiki/JSONP) works around limitations of certain
1344 * API endpoints that don't support newer,
1345 * and preferable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) protocol.
1346 * JSONP treats the endpoint API as a JavaScript file and tricks the browser to process the
1347 * requests even if the API endpoint is not located on the same domain (origin) as the client-side
1348 * application making the request.
1349 * The endpoint API must support JSONP callback for JSONP requests to work.
1350 * The resource API returns the JSON response wrapped in a callback function.
1351 * You can pass the callback function name as one of the query parameters.
1352 * Note that JSONP requests can only be used with `GET` requests.
1353 *
1354 * @param url The resource URL.
1355 * @param callbackParam The callback function name.
1356 *
1357 */
1358 jsonp(url, callbackParam) {
1359 return this.request('JSONP', url, {
1360 params: new HttpParams().append(callbackParam, 'JSONP_CALLBACK'),
1361 observe: 'body',
1362 responseType: 'json',
1363 });
1364 }
1365 /**
1366 * Constructs an `Observable` that, when subscribed, causes the configured
1367 * `OPTIONS` request to execute on the server. This method allows the client
1368 * to determine the supported HTTP methods and other capabilities of an endpoint,
1369 * without implying a resource action. See the individual overloads for
1370 * details on the return type.
1371 */
1372 options(url, options = {}) {
1373 return this.request('OPTIONS', url, options);
1374 }
1375 /**
1376 * Constructs an observable that, when subscribed, causes the configured
1377 * `PATCH` request to execute on the server. See the individual overloads for
1378 * details on the return type.
1379 */
1380 patch(url, body, options = {}) {
1381 return this.request('PATCH', url, addBody(options, body));
1382 }
1383 /**
1384 * Constructs an observable that, when subscribed, causes the configured
1385 * `POST` request to execute on the server. The server responds with the location of
1386 * the replaced resource. See the individual overloads for
1387 * details on the return type.
1388 */
1389 post(url, body, options = {}) {
1390 return this.request('POST', url, addBody(options, body));
1391 }
1392 /**
1393 * Constructs an observable that, when subscribed, causes the configured
1394 * `PUT` request to execute on the server. The `PUT` method replaces an existing resource
1395 * with a new set of values.
1396 * See the individual overloads for details on the return type.
1397 */
1398 put(url, body, options = {}) {
1399 return this.request('PUT', url, addBody(options, body));
1400 }
1401}
1402HttpClient.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable });
1403HttpClient.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClient });
1404i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClient, decorators: [{
1405 type: Injectable
1406 }], ctorParameters: function () { return [{ type: HttpHandler }]; } });
1407
1408/**
1409 * @license
1410 * Copyright Google LLC All Rights Reserved.
1411 *
1412 * Use of this source code is governed by an MIT-style license that can be
1413 * found in the LICENSE file at https://angular.io/license
1414 */
1415/**
1416 * `HttpHandler` which applies an `HttpInterceptor` to an `HttpRequest`.
1417 *
1418 *
1419 */
1420class HttpInterceptorHandler {
1421 constructor(next, interceptor) {
1422 this.next = next;
1423 this.interceptor = interceptor;
1424 }
1425 handle(req) {
1426 return this.interceptor.intercept(req, this.next);
1427 }
1428}
1429/**
1430 * A multi-provider token that represents the array of registered
1431 * `HttpInterceptor` objects.
1432 *
1433 * @publicApi
1434 */
1435const HTTP_INTERCEPTORS = new InjectionToken('HTTP_INTERCEPTORS');
1436class NoopInterceptor {
1437 intercept(req, next) {
1438 return next.handle(req);
1439 }
1440}
1441NoopInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: NoopInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1442NoopInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: NoopInterceptor });
1443i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: NoopInterceptor, decorators: [{
1444 type: Injectable
1445 }] });
1446
1447/**
1448 * @license
1449 * Copyright Google LLC All Rights Reserved.
1450 *
1451 * Use of this source code is governed by an MIT-style license that can be
1452 * found in the LICENSE file at https://angular.io/license
1453 */
1454// Every request made through JSONP needs a callback name that's unique across the
1455// whole page. Each request is assigned an id and the callback name is constructed
1456// from that. The next id to be assigned is tracked in a global variable here that
1457// is shared among all applications on the page.
1458let nextRequestId = 0;
1459/**
1460 * When a pending <script> is unsubscribed we'll move it to this document, so it won't be
1461 * executed.
1462 */
1463let foreignDocument;
1464// Error text given when a JSONP script is injected, but doesn't invoke the callback
1465// passed in its URL.
1466const JSONP_ERR_NO_CALLBACK = 'JSONP injected script did not invoke callback.';
1467// Error text given when a request is passed to the JsonpClientBackend that doesn't
1468// have a request method JSONP.
1469const JSONP_ERR_WRONG_METHOD = 'JSONP requests must use JSONP request method.';
1470const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json response type.';
1471// Error text given when a request is passed to the JsonpClientBackend that has
1472// headers set
1473const JSONP_ERR_HEADERS_NOT_SUPPORTED = 'JSONP requests do not support headers.';
1474/**
1475 * DI token/abstract type representing a map of JSONP callbacks.
1476 *
1477 * In the browser, this should always be the `window` object.
1478 *
1479 *
1480 */
1481class JsonpCallbackContext {
1482}
1483/**
1484 * Processes an `HttpRequest` with the JSONP method,
1485 * by performing JSONP style requests.
1486 * @see `HttpHandler`
1487 * @see `HttpXhrBackend`
1488 *
1489 * @publicApi
1490 */
1491class JsonpClientBackend {
1492 constructor(callbackMap, document) {
1493 this.callbackMap = callbackMap;
1494 this.document = document;
1495 /**
1496 * A resolved promise that can be used to schedule microtasks in the event handlers.
1497 */
1498 this.resolvedPromise = Promise.resolve();
1499 }
1500 /**
1501 * Get the name of the next callback method, by incrementing the global `nextRequestId`.
1502 */
1503 nextCallback() {
1504 return `ng_jsonp_callback_${nextRequestId++}`;
1505 }
1506 /**
1507 * Processes a JSONP request and returns an event stream of the results.
1508 * @param req The request object.
1509 * @returns An observable of the response events.
1510 *
1511 */
1512 handle(req) {
1513 // Firstly, check both the method and response type. If either doesn't match
1514 // then the request was improperly routed here and cannot be handled.
1515 if (req.method !== 'JSONP') {
1516 throw new Error(JSONP_ERR_WRONG_METHOD);
1517 }
1518 else if (req.responseType !== 'json') {
1519 throw new Error(JSONP_ERR_WRONG_RESPONSE_TYPE);
1520 }
1521 // Check the request headers. JSONP doesn't support headers and
1522 // cannot set any that were supplied.
1523 if (req.headers.keys().length > 0) {
1524 throw new Error(JSONP_ERR_HEADERS_NOT_SUPPORTED);
1525 }
1526 // Everything else happens inside the Observable boundary.
1527 return new Observable((observer) => {
1528 // The first step to make a request is to generate the callback name, and replace the
1529 // callback placeholder in the URL with the name. Care has to be taken here to ensure
1530 // a trailing &, if matched, gets inserted back into the URL in the correct place.
1531 const callback = this.nextCallback();
1532 const url = req.urlWithParams.replace(/=JSONP_CALLBACK(&|$)/, `=${callback}$1`);
1533 // Construct the <script> tag and point it at the URL.
1534 const node = this.document.createElement('script');
1535 node.src = url;
1536 // A JSONP request requires waiting for multiple callbacks. These variables
1537 // are closed over and track state across those callbacks.
1538 // The response object, if one has been received, or null otherwise.
1539 let body = null;
1540 // Whether the response callback has been called.
1541 let finished = false;
1542 // Set the response callback in this.callbackMap (which will be the window
1543 // object in the browser. The script being loaded via the <script> tag will
1544 // eventually call this callback.
1545 this.callbackMap[callback] = (data) => {
1546 // Data has been received from the JSONP script. Firstly, delete this callback.
1547 delete this.callbackMap[callback];
1548 // Set state to indicate data was received.
1549 body = data;
1550 finished = true;
1551 };
1552 // cleanup() is a utility closure that removes the <script> from the page and
1553 // the response callback from the window. This logic is used in both the
1554 // success, error, and cancellation paths, so it's extracted out for convenience.
1555 const cleanup = () => {
1556 // Remove the <script> tag if it's still on the page.
1557 if (node.parentNode) {
1558 node.parentNode.removeChild(node);
1559 }
1560 // Remove the response callback from the callbackMap (window object in the
1561 // browser).
1562 delete this.callbackMap[callback];
1563 };
1564 // onLoad() is the success callback which runs after the response callback
1565 // if the JSONP script loads successfully. The event itself is unimportant.
1566 // If something went wrong, onLoad() may run without the response callback
1567 // having been invoked.
1568 const onLoad = (event) => {
1569 // We wrap it in an extra Promise, to ensure the microtask
1570 // is scheduled after the loaded endpoint has executed any potential microtask itself,
1571 // which is not guaranteed in Internet Explorer and EdgeHTML. See issue #39496
1572 this.resolvedPromise.then(() => {
1573 // Cleanup the page.
1574 cleanup();
1575 // Check whether the response callback has run.
1576 if (!finished) {
1577 // It hasn't, something went wrong with the request. Return an error via
1578 // the Observable error path. All JSONP errors have status 0.
1579 observer.error(new HttpErrorResponse({
1580 url,
1581 status: 0,
1582 statusText: 'JSONP Error',
1583 error: new Error(JSONP_ERR_NO_CALLBACK),
1584 }));
1585 return;
1586 }
1587 // Success. body either contains the response body or null if none was
1588 // returned.
1589 observer.next(new HttpResponse({
1590 body,
1591 status: 200 /* HttpStatusCode.Ok */,
1592 statusText: 'OK',
1593 url,
1594 }));
1595 // Complete the stream, the response is over.
1596 observer.complete();
1597 });
1598 };
1599 // onError() is the error callback, which runs if the script returned generates
1600 // a Javascript error. It emits the error via the Observable error channel as
1601 // a HttpErrorResponse.
1602 const onError = (error) => {
1603 cleanup();
1604 // Wrap the error in a HttpErrorResponse.
1605 observer.error(new HttpErrorResponse({
1606 error,
1607 status: 0,
1608 statusText: 'JSONP Error',
1609 url,
1610 }));
1611 };
1612 // Subscribe to both the success (load) and error events on the <script> tag,
1613 // and add it to the page.
1614 node.addEventListener('load', onLoad);
1615 node.addEventListener('error', onError);
1616 this.document.body.appendChild(node);
1617 // The request has now been successfully sent.
1618 observer.next({ type: HttpEventType.Sent });
1619 // Cancellation handler.
1620 return () => {
1621 if (!finished) {
1622 this.removeListeners(node);
1623 }
1624 // And finally, clean up the page.
1625 cleanup();
1626 };
1627 });
1628 }
1629 removeListeners(script) {
1630 // Issue #34818
1631 // Changing <script>'s ownerDocument will prevent it from execution.
1632 // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block
1633 if (!foreignDocument) {
1634 foreignDocument = this.document.implementation.createHTMLDocument();
1635 }
1636 foreignDocument.adoptNode(script);
1637 }
1638}
1639JsonpClientBackend.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
1640JsonpClientBackend.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpClientBackend });
1641i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpClientBackend, decorators: [{
1642 type: Injectable
1643 }], ctorParameters: function () { return [{ type: JsonpCallbackContext }, { type: undefined, decorators: [{
1644 type: Inject,
1645 args: [DOCUMENT]
1646 }] }]; } });
1647/**
1648 * Identifies requests with the method JSONP and
1649 * shifts them to the `JsonpClientBackend`.
1650 *
1651 * @see `HttpInterceptor`
1652 *
1653 * @publicApi
1654 */
1655class JsonpInterceptor {
1656 constructor(jsonp) {
1657 this.jsonp = jsonp;
1658 }
1659 /**
1660 * Identifies and handles a given JSONP request.
1661 * @param req The outgoing request object to handle.
1662 * @param next The next interceptor in the chain, or the backend
1663 * if no interceptors remain in the chain.
1664 * @returns An observable of the event stream.
1665 */
1666 intercept(req, next) {
1667 if (req.method === 'JSONP') {
1668 return this.jsonp.handle(req);
1669 }
1670 // Fall through for normal HTTP requests.
1671 return next.handle(req);
1672 }
1673}
1674JsonpInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpInterceptor, deps: [{ token: JsonpClientBackend }], target: i0.ɵɵFactoryTarget.Injectable });
1675JsonpInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpInterceptor });
1676i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: JsonpInterceptor, decorators: [{
1677 type: Injectable
1678 }], ctorParameters: function () { return [{ type: JsonpClientBackend }]; } });
1679
1680/**
1681 * @license
1682 * Copyright Google LLC All Rights Reserved.
1683 *
1684 * Use of this source code is governed by an MIT-style license that can be
1685 * found in the LICENSE file at https://angular.io/license
1686 */
1687const XSSI_PREFIX = /^\)\]\}',?\n/;
1688/**
1689 * Determine an appropriate URL for the response, by checking either
1690 * XMLHttpRequest.responseURL or the X-Request-URL header.
1691 */
1692function getResponseUrl(xhr) {
1693 if ('responseURL' in xhr && xhr.responseURL) {
1694 return xhr.responseURL;
1695 }
1696 if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
1697 return xhr.getResponseHeader('X-Request-URL');
1698 }
1699 return null;
1700}
1701/**
1702 * Uses `XMLHttpRequest` to send requests to a backend server.
1703 * @see `HttpHandler`
1704 * @see `JsonpClientBackend`
1705 *
1706 * @publicApi
1707 */
1708class HttpXhrBackend {
1709 constructor(xhrFactory) {
1710 this.xhrFactory = xhrFactory;
1711 }
1712 /**
1713 * Processes a request and returns a stream of response events.
1714 * @param req The request object.
1715 * @returns An observable of the response events.
1716 */
1717 handle(req) {
1718 // Quick check to give a better error message when a user attempts to use
1719 // HttpClient.jsonp() without installing the HttpClientJsonpModule
1720 if (req.method === 'JSONP') {
1721 throw new Error(`Attempted to construct Jsonp request without HttpClientJsonpModule installed.`);
1722 }
1723 // Everything happens on Observable subscription.
1724 return new Observable((observer) => {
1725 // Start by setting up the XHR object with request method, URL, and withCredentials flag.
1726 const xhr = this.xhrFactory.build();
1727 xhr.open(req.method, req.urlWithParams);
1728 if (!!req.withCredentials) {
1729 xhr.withCredentials = true;
1730 }
1731 // Add all the requested headers.
1732 req.headers.forEach((name, values) => xhr.setRequestHeader(name, values.join(',')));
1733 // Add an Accept header if one isn't present already.
1734 if (!req.headers.has('Accept')) {
1735 xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
1736 }
1737 // Auto-detect the Content-Type header if one isn't present already.
1738 if (!req.headers.has('Content-Type')) {
1739 const detectedType = req.detectContentTypeHeader();
1740 // Sometimes Content-Type detection fails.
1741 if (detectedType !== null) {
1742 xhr.setRequestHeader('Content-Type', detectedType);
1743 }
1744 }
1745 // Set the responseType if one was requested.
1746 if (req.responseType) {
1747 const responseType = req.responseType.toLowerCase();
1748 // JSON responses need to be processed as text. This is because if the server
1749 // returns an XSSI-prefixed JSON response, the browser will fail to parse it,
1750 // xhr.response will be null, and xhr.responseText cannot be accessed to
1751 // retrieve the prefixed JSON data in order to strip the prefix. Thus, all JSON
1752 // is parsed by first requesting text and then applying JSON.parse.
1753 xhr.responseType = ((responseType !== 'json') ? responseType : 'text');
1754 }
1755 // Serialize the request body if one is present. If not, this will be set to null.
1756 const reqBody = req.serializeBody();
1757 // If progress events are enabled, response headers will be delivered
1758 // in two events - the HttpHeaderResponse event and the full HttpResponse
1759 // event. However, since response headers don't change in between these
1760 // two events, it doesn't make sense to parse them twice. So headerResponse
1761 // caches the data extracted from the response whenever it's first parsed,
1762 // to ensure parsing isn't duplicated.
1763 let headerResponse = null;
1764 // partialFromXhr extracts the HttpHeaderResponse from the current XMLHttpRequest
1765 // state, and memoizes it into headerResponse.
1766 const partialFromXhr = () => {
1767 if (headerResponse !== null) {
1768 return headerResponse;
1769 }
1770 const statusText = xhr.statusText || 'OK';
1771 // Parse headers from XMLHttpRequest - this step is lazy.
1772 const headers = new HttpHeaders(xhr.getAllResponseHeaders());
1773 // Read the response URL from the XMLHttpResponse instance and fall back on the
1774 // request URL.
1775 const url = getResponseUrl(xhr) || req.url;
1776 // Construct the HttpHeaderResponse and memoize it.
1777 headerResponse = new HttpHeaderResponse({ headers, status: xhr.status, statusText, url });
1778 return headerResponse;
1779 };
1780 // Next, a few closures are defined for the various events which XMLHttpRequest can
1781 // emit. This allows them to be unregistered as event listeners later.
1782 // First up is the load event, which represents a response being fully available.
1783 const onLoad = () => {
1784 // Read response state from the memoized partial data.
1785 let { headers, status, statusText, url } = partialFromXhr();
1786 // The body will be read out if present.
1787 let body = null;
1788 if (status !== 204 /* HttpStatusCode.NoContent */) {
1789 // Use XMLHttpRequest.response if set, responseText otherwise.
1790 body = (typeof xhr.response === 'undefined') ? xhr.responseText : xhr.response;
1791 }
1792 // Normalize another potential bug (this one comes from CORS).
1793 if (status === 0) {
1794 status = !!body ? 200 /* HttpStatusCode.Ok */ : 0;
1795 }
1796 // ok determines whether the response will be transmitted on the event or
1797 // error channel. Unsuccessful status codes (not 2xx) will always be errors,
1798 // but a successful status code can still result in an error if the user
1799 // asked for JSON data and the body cannot be parsed as such.
1800 let ok = status >= 200 && status < 300;
1801 // Check whether the body needs to be parsed as JSON (in many cases the browser
1802 // will have done that already).
1803 if (req.responseType === 'json' && typeof body === 'string') {
1804 // Save the original body, before attempting XSSI prefix stripping.
1805 const originalBody = body;
1806 body = body.replace(XSSI_PREFIX, '');
1807 try {
1808 // Attempt the parse. If it fails, a parse error should be delivered to the user.
1809 body = body !== '' ? JSON.parse(body) : null;
1810 }
1811 catch (error) {
1812 // Since the JSON.parse failed, it's reasonable to assume this might not have been a
1813 // JSON response. Restore the original body (including any XSSI prefix) to deliver
1814 // a better error response.
1815 body = originalBody;
1816 // If this was an error request to begin with, leave it as a string, it probably
1817 // just isn't JSON. Otherwise, deliver the parsing error to the user.
1818 if (ok) {
1819 // Even though the response status was 2xx, this is still an error.
1820 ok = false;
1821 // The parse error contains the text of the body that failed to parse.
1822 body = { error, text: body };
1823 }
1824 }
1825 }
1826 if (ok) {
1827 // A successful response is delivered on the event stream.
1828 observer.next(new HttpResponse({
1829 body,
1830 headers,
1831 status,
1832 statusText,
1833 url: url || undefined,
1834 }));
1835 // The full body has been received and delivered, no further events
1836 // are possible. This request is complete.
1837 observer.complete();
1838 }
1839 else {
1840 // An unsuccessful request is delivered on the error channel.
1841 observer.error(new HttpErrorResponse({
1842 // The error in this case is the response body (error from the server).
1843 error: body,
1844 headers,
1845 status,
1846 statusText,
1847 url: url || undefined,
1848 }));
1849 }
1850 };
1851 // The onError callback is called when something goes wrong at the network level.
1852 // Connection timeout, DNS error, offline, etc. These are actual errors, and are
1853 // transmitted on the error channel.
1854 const onError = (error) => {
1855 const { url } = partialFromXhr();
1856 const res = new HttpErrorResponse({
1857 error,
1858 status: xhr.status || 0,
1859 statusText: xhr.statusText || 'Unknown Error',
1860 url: url || undefined,
1861 });
1862 observer.error(res);
1863 };
1864 // The sentHeaders flag tracks whether the HttpResponseHeaders event
1865 // has been sent on the stream. This is necessary to track if progress
1866 // is enabled since the event will be sent on only the first download
1867 // progerss event.
1868 let sentHeaders = false;
1869 // The download progress event handler, which is only registered if
1870 // progress events are enabled.
1871 const onDownProgress = (event) => {
1872 // Send the HttpResponseHeaders event if it hasn't been sent already.
1873 if (!sentHeaders) {
1874 observer.next(partialFromXhr());
1875 sentHeaders = true;
1876 }
1877 // Start building the download progress event to deliver on the response
1878 // event stream.
1879 let progressEvent = {
1880 type: HttpEventType.DownloadProgress,
1881 loaded: event.loaded,
1882 };
1883 // Set the total number of bytes in the event if it's available.
1884 if (event.lengthComputable) {
1885 progressEvent.total = event.total;
1886 }
1887 // If the request was for text content and a partial response is
1888 // available on XMLHttpRequest, include it in the progress event
1889 // to allow for streaming reads.
1890 if (req.responseType === 'text' && !!xhr.responseText) {
1891 progressEvent.partialText = xhr.responseText;
1892 }
1893 // Finally, fire the event.
1894 observer.next(progressEvent);
1895 };
1896 // The upload progress event handler, which is only registered if
1897 // progress events are enabled.
1898 const onUpProgress = (event) => {
1899 // Upload progress events are simpler. Begin building the progress
1900 // event.
1901 let progress = {
1902 type: HttpEventType.UploadProgress,
1903 loaded: event.loaded,
1904 };
1905 // If the total number of bytes being uploaded is available, include
1906 // it.
1907 if (event.lengthComputable) {
1908 progress.total = event.total;
1909 }
1910 // Send the event.
1911 observer.next(progress);
1912 };
1913 // By default, register for load and error events.
1914 xhr.addEventListener('load', onLoad);
1915 xhr.addEventListener('error', onError);
1916 xhr.addEventListener('timeout', onError);
1917 xhr.addEventListener('abort', onError);
1918 // Progress events are only enabled if requested.
1919 if (req.reportProgress) {
1920 // Download progress is always enabled if requested.
1921 xhr.addEventListener('progress', onDownProgress);
1922 // Upload progress depends on whether there is a body to upload.
1923 if (reqBody !== null && xhr.upload) {
1924 xhr.upload.addEventListener('progress', onUpProgress);
1925 }
1926 }
1927 // Fire the request, and notify the event stream that it was fired.
1928 xhr.send(reqBody);
1929 observer.next({ type: HttpEventType.Sent });
1930 // This is the return from the Observable function, which is the
1931 // request cancellation handler.
1932 return () => {
1933 // On a cancellation, remove all registered event listeners.
1934 xhr.removeEventListener('error', onError);
1935 xhr.removeEventListener('abort', onError);
1936 xhr.removeEventListener('load', onLoad);
1937 xhr.removeEventListener('timeout', onError);
1938 if (req.reportProgress) {
1939 xhr.removeEventListener('progress', onDownProgress);
1940 if (reqBody !== null && xhr.upload) {
1941 xhr.upload.removeEventListener('progress', onUpProgress);
1942 }
1943 }
1944 // Finally, abort the in-flight request.
1945 if (xhr.readyState !== xhr.DONE) {
1946 xhr.abort();
1947 }
1948 };
1949 });
1950 }
1951}
1952HttpXhrBackend.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXhrBackend, deps: [{ token: i1.XhrFactory }], target: i0.ɵɵFactoryTarget.Injectable });
1953HttpXhrBackend.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXhrBackend });
1954i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXhrBackend, decorators: [{
1955 type: Injectable
1956 }], ctorParameters: function () { return [{ type: i1.XhrFactory }]; } });
1957
1958/**
1959 * @license
1960 * Copyright Google LLC All Rights Reserved.
1961 *
1962 * Use of this source code is governed by an MIT-style license that can be
1963 * found in the LICENSE file at https://angular.io/license
1964 */
1965const XSRF_COOKIE_NAME = new InjectionToken('XSRF_COOKIE_NAME');
1966const XSRF_HEADER_NAME = new InjectionToken('XSRF_HEADER_NAME');
1967/**
1968 * Retrieves the current XSRF token to use with the next outgoing request.
1969 *
1970 * @publicApi
1971 */
1972class HttpXsrfTokenExtractor {
1973}
1974/**
1975 * `HttpXsrfTokenExtractor` which retrieves the token from a cookie.
1976 */
1977class HttpXsrfCookieExtractor {
1978 constructor(doc, platform, cookieName) {
1979 this.doc = doc;
1980 this.platform = platform;
1981 this.cookieName = cookieName;
1982 this.lastCookieString = '';
1983 this.lastToken = null;
1984 /**
1985 * @internal for testing
1986 */
1987 this.parseCount = 0;
1988 }
1989 getToken() {
1990 if (this.platform === 'server') {
1991 return null;
1992 }
1993 const cookieString = this.doc.cookie || '';
1994 if (cookieString !== this.lastCookieString) {
1995 this.parseCount++;
1996 this.lastToken = ɵparseCookieValue(cookieString, this.cookieName);
1997 this.lastCookieString = cookieString;
1998 }
1999 return this.lastToken;
2000 }
2001}
2002HttpXsrfCookieExtractor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: XSRF_COOKIE_NAME }], target: i0.ɵɵFactoryTarget.Injectable });
2003HttpXsrfCookieExtractor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfCookieExtractor });
2004i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfCookieExtractor, decorators: [{
2005 type: Injectable
2006 }], ctorParameters: function () { return [{ type: undefined, decorators: [{
2007 type: Inject,
2008 args: [DOCUMENT]
2009 }] }, { type: undefined, decorators: [{
2010 type: Inject,
2011 args: [PLATFORM_ID]
2012 }] }, { type: undefined, decorators: [{
2013 type: Inject,
2014 args: [XSRF_COOKIE_NAME]
2015 }] }]; } });
2016/**
2017 * `HttpInterceptor` which adds an XSRF token to eligible outgoing requests.
2018 */
2019class HttpXsrfInterceptor {
2020 constructor(tokenService, headerName) {
2021 this.tokenService = tokenService;
2022 this.headerName = headerName;
2023 }
2024 intercept(req, next) {
2025 const lcUrl = req.url.toLowerCase();
2026 // Skip both non-mutating requests and absolute URLs.
2027 // Non-mutating requests don't require a token, and absolute URLs require special handling
2028 // anyway as the cookie set
2029 // on our origin is not the same as the token expected by another origin.
2030 if (req.method === 'GET' || req.method === 'HEAD' || lcUrl.startsWith('http://') ||
2031 lcUrl.startsWith('https://')) {
2032 return next.handle(req);
2033 }
2034 const token = this.tokenService.getToken();
2035 // Be careful not to overwrite an existing header of the same name.
2036 if (token !== null && !req.headers.has(this.headerName)) {
2037 req = req.clone({ headers: req.headers.set(this.headerName, token) });
2038 }
2039 return next.handle(req);
2040 }
2041}
2042HttpXsrfInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: HttpXsrfTokenExtractor }, { token: XSRF_HEADER_NAME }], target: i0.ɵɵFactoryTarget.Injectable });
2043HttpXsrfInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfInterceptor });
2044i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpXsrfInterceptor, decorators: [{
2045 type: Injectable
2046 }], ctorParameters: function () { return [{ type: HttpXsrfTokenExtractor }, { type: undefined, decorators: [{
2047 type: Inject,
2048 args: [XSRF_HEADER_NAME]
2049 }] }]; } });
2050
2051/**
2052 * @license
2053 * Copyright Google LLC All Rights Reserved.
2054 *
2055 * Use of this source code is governed by an MIT-style license that can be
2056 * found in the LICENSE file at https://angular.io/license
2057 */
2058/**
2059 * An injectable `HttpHandler` that applies multiple interceptors
2060 * to a request before passing it to the given `HttpBackend`.
2061 *
2062 * The interceptors are loaded lazily from the injector, to allow
2063 * interceptors to themselves inject classes depending indirectly
2064 * on `HttpInterceptingHandler` itself.
2065 * @see `HttpInterceptor`
2066 */
2067class HttpInterceptingHandler {
2068 constructor(backend, injector) {
2069 this.backend = backend;
2070 this.injector = injector;
2071 this.chain = null;
2072 }
2073 handle(req) {
2074 if (this.chain === null) {
2075 const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
2076 this.chain = interceptors.reduceRight((next, interceptor) => new HttpInterceptorHandler(next, interceptor), this.backend);
2077 }
2078 return this.chain.handle(req);
2079 }
2080}
2081HttpInterceptingHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpInterceptingHandler, deps: [{ token: HttpBackend }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
2082HttpInterceptingHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpInterceptingHandler });
2083i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpInterceptingHandler, decorators: [{
2084 type: Injectable
2085 }], ctorParameters: function () { return [{ type: HttpBackend }, { type: i0.Injector }]; } });
2086/**
2087 * Constructs an `HttpHandler` that applies interceptors
2088 * to a request before passing it to the given `HttpBackend`.
2089 *
2090 * Use as a factory function within `HttpClientModule`.
2091 *
2092 *
2093 */
2094function interceptingHandler(backend, interceptors = []) {
2095 if (!interceptors) {
2096 return backend;
2097 }
2098 return interceptors.reduceRight((next, interceptor) => new HttpInterceptorHandler(next, interceptor), backend);
2099}
2100/**
2101 * Factory function that determines where to store JSONP callbacks.
2102 *
2103 * Ordinarily JSONP callbacks are stored on the `window` object, but this may not exist
2104 * in test environments. In that case, callbacks are stored on an anonymous object instead.
2105 *
2106 *
2107 */
2108function jsonpCallbackContext() {
2109 if (typeof window === 'object') {
2110 return window;
2111 }
2112 return {};
2113}
2114/**
2115 * Configures XSRF protection support for outgoing requests.
2116 *
2117 * For a server that supports a cookie-based XSRF protection system,
2118 * use directly to configure XSRF protection with the correct
2119 * cookie and header names.
2120 *
2121 * If no names are supplied, the default cookie name is `XSRF-TOKEN`
2122 * and the default header name is `X-XSRF-TOKEN`.
2123 *
2124 * @publicApi
2125 */
2126class HttpClientXsrfModule {
2127 /**
2128 * Disable the default XSRF protection.
2129 */
2130 static disable() {
2131 return {
2132 ngModule: HttpClientXsrfModule,
2133 providers: [
2134 { provide: HttpXsrfInterceptor, useClass: NoopInterceptor },
2135 ],
2136 };
2137 }
2138 /**
2139 * Configure XSRF protection.
2140 * @param options An object that can specify either or both
2141 * cookie name or header name.
2142 * - Cookie name default is `XSRF-TOKEN`.
2143 * - Header name default is `X-XSRF-TOKEN`.
2144 *
2145 */
2146 static withOptions(options = {}) {
2147 return {
2148 ngModule: HttpClientXsrfModule,
2149 providers: [
2150 options.cookieName ? { provide: XSRF_COOKIE_NAME, useValue: options.cookieName } : [],
2151 options.headerName ? { provide: XSRF_HEADER_NAME, useValue: options.headerName } : [],
2152 ],
2153 };
2154 }
2155}
2156HttpClientXsrfModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2157HttpClientXsrfModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.4", ngImport: i0, type: HttpClientXsrfModule });
2158HttpClientXsrfModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientXsrfModule, providers: [
2159 HttpXsrfInterceptor,
2160 { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
2161 { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
2162 { provide: XSRF_COOKIE_NAME, useValue: 'XSRF-TOKEN' },
2163 { provide: XSRF_HEADER_NAME, useValue: 'X-XSRF-TOKEN' },
2164 ] });
2165i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientXsrfModule, decorators: [{
2166 type: NgModule,
2167 args: [{
2168 providers: [
2169 HttpXsrfInterceptor,
2170 { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
2171 { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
2172 { provide: XSRF_COOKIE_NAME, useValue: 'XSRF-TOKEN' },
2173 { provide: XSRF_HEADER_NAME, useValue: 'X-XSRF-TOKEN' },
2174 ],
2175 }]
2176 }] });
2177/**
2178 * Configures the [dependency injector](guide/glossary#injector) for `HttpClient`
2179 * with supporting services for XSRF. Automatically imported by `HttpClientModule`.
2180 *
2181 * You can add interceptors to the chain behind `HttpClient` by binding them to the
2182 * multiprovider for built-in [DI token](guide/glossary#di-token) `HTTP_INTERCEPTORS`.
2183 *
2184 * @publicApi
2185 */
2186class HttpClientModule {
2187}
2188HttpClientModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2189HttpClientModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.4", ngImport: i0, type: HttpClientModule, imports: [HttpClientXsrfModule] });
2190HttpClientModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientModule, providers: [
2191 HttpClient,
2192 { provide: HttpHandler, useClass: HttpInterceptingHandler },
2193 HttpXhrBackend,
2194 { provide: HttpBackend, useExisting: HttpXhrBackend },
2195 ], imports: [HttpClientXsrfModule.withOptions({
2196 cookieName: 'XSRF-TOKEN',
2197 headerName: 'X-XSRF-TOKEN',
2198 })] });
2199i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientModule, decorators: [{
2200 type: NgModule,
2201 args: [{
2202 /**
2203 * Optional configuration for XSRF protection.
2204 */
2205 imports: [
2206 HttpClientXsrfModule.withOptions({
2207 cookieName: 'XSRF-TOKEN',
2208 headerName: 'X-XSRF-TOKEN',
2209 }),
2210 ],
2211 /**
2212 * Configures the [dependency injector](guide/glossary#injector) where it is imported
2213 * with supporting services for HTTP communications.
2214 */
2215 providers: [
2216 HttpClient,
2217 { provide: HttpHandler, useClass: HttpInterceptingHandler },
2218 HttpXhrBackend,
2219 { provide: HttpBackend, useExisting: HttpXhrBackend },
2220 ],
2221 }]
2222 }] });
2223/**
2224 * Configures the [dependency injector](guide/glossary#injector) for `HttpClient`
2225 * with supporting services for JSONP.
2226 * Without this module, Jsonp requests reach the backend
2227 * with method JSONP, where they are rejected.
2228 *
2229 * You can add interceptors to the chain behind `HttpClient` by binding them to the
2230 * multiprovider for built-in [DI token](guide/glossary#di-token) `HTTP_INTERCEPTORS`.
2231 *
2232 * @publicApi
2233 */
2234class HttpClientJsonpModule {
2235}
2236HttpClientJsonpModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2237HttpClientJsonpModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.4", ngImport: i0, type: HttpClientJsonpModule });
2238HttpClientJsonpModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientJsonpModule, providers: [
2239 JsonpClientBackend,
2240 { provide: JsonpCallbackContext, useFactory: jsonpCallbackContext },
2241 { provide: HTTP_INTERCEPTORS, useClass: JsonpInterceptor, multi: true },
2242 ] });
2243i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.4", ngImport: i0, type: HttpClientJsonpModule, decorators: [{
2244 type: NgModule,
2245 args: [{
2246 providers: [
2247 JsonpClientBackend,
2248 { provide: JsonpCallbackContext, useFactory: jsonpCallbackContext },
2249 { provide: HTTP_INTERCEPTORS, useClass: JsonpInterceptor, multi: true },
2250 ],
2251 }]
2252 }] });
2253
2254/**
2255 * @license
2256 * Copyright Google LLC All Rights Reserved.
2257 *
2258 * Use of this source code is governed by an MIT-style license that can be
2259 * found in the LICENSE file at https://angular.io/license
2260 */
2261/**
2262 * A wrapper around the `XMLHttpRequest` constructor.
2263 *
2264 * @publicApi
2265 * @see `XhrFactory`
2266 * @deprecated
2267 * `XhrFactory` has moved, please import `XhrFactory` from `@angular/common` instead.
2268 */
2269const XhrFactory = XhrFactory$1;
2270
2271/**
2272 * @license
2273 * Copyright Google LLC All Rights Reserved.
2274 *
2275 * Use of this source code is governed by an MIT-style license that can be
2276 * found in the LICENSE file at https://angular.io/license
2277 */
2278
2279/**
2280 * Generated bundle index. Do not edit.
2281 */
2282
2283export { HTTP_INTERCEPTORS, HttpBackend, HttpClient, HttpClientJsonpModule, HttpClientModule, HttpClientXsrfModule, HttpContext, HttpContextToken, HttpErrorResponse, HttpEventType, HttpHandler, HttpHeaderResponse, HttpHeaders, HttpParams, HttpRequest, HttpResponse, HttpResponseBase, HttpUrlEncodingCodec, HttpXhrBackend, HttpXsrfTokenExtractor, JsonpClientBackend, JsonpInterceptor, XhrFactory, HttpInterceptingHandler as ɵHttpInterceptingHandler };
2284//# sourceMappingURL=http.mjs.map