Replaces the remaining hand-rolled deferred promise implementations
with the native `Promise.withResolvers()` API and removes the now
unused helper and import.
Follow-up to #69739.
`getTagSinceVersion` matched `\d+(\.\d+)?` anywhere in the tag comment. That
works for `@developerPreview`, `@experimental` and `@stable`, whose comment is
only a version, but `@deprecated` also carries a message, so any number in the
prose won. https://angular.dev/api/common/getLocaleCurrencyCode reads
"deprecated since v4217", taken from "a map of locale to ISO 4217 currency
codes", and eighteen sibling pages take v18 from the "i18n" in "relying on the
`Intl` API for i18n".
Anchoring the match, and allowing the `since`/`from`/`as of` prefixes the
comments use, leaves all seventy-nine correctly versioned comments untouched.
`generate_manifest` carries its own copy of the regex, so the API list badges
had the same values.
Those `@angular/common` comments never stated a version, so they now say `18.0`
explicitly, the release `d34c033902` (#54483) first shipped in, matching the
`@deprecated 18.0` already on `FormatWidth` in the same file. Nine tags in that
file had no version at all and were showing no badge; they are from the same
commit and now say `18.0` too.
Preserve hasUAVisualTransition through Location and the Router navigation pipeline. This prevents withViewTransitions from starting an author transition after the browser has already performed one, including across redirects and when using experimental platform navigation.
We keep getting PRs that target single usages of `hasOwnProperty` and we have ~100 of them. These changes aim to address the issue centrally by swapping out all the instances and adding a lint rule against introducing new ones.
Previously, when you passed an object typed like
Record<'a' | 'b', number> into the `keyvalue` pipe, TypeScript would
"forget" that the keys could only ever be 'a' or 'b', and just tell
you the key was a plain `string` instead. So code like this used to
fail to compile, even though it's correct:
```ts
const input: Record<'a' | 'b', number> = {a: 1, b: 2};
const result = pipe.transform(input);
const key: 'a' | 'b' = result[0].key; // error: string is not 'a' | 'b'
```
This happened because the pipe has multiple overloaded versions of
transform(), and TypeScript checks them top to bottom, using the
first one that matches. The "number keys" overload was listed first,
and it happened to also match string-keyed objects by accident, so
it "won" before the correct "string keys" overload ever got a
chance to run.
The fix just reorders those two overloads so the string-keys one is
checked first. Nothing about runtime behavior changes — objects with
actual numeric keys (e.g. Record<1 | 2, string>) still correctly
report their keys as plain `string`, matching what Object.keys()
really returns at runtime.
Cancel the unread response body before reporting NG02825 when its declared Content-Length exceeds the configured buffer limit. Without cancellation, SSR can finish while the underlying connection remains open.
Add regression coverage for the declared-length rejection path.
Prevent AbortController.abort() from executing during Observable teardown when a FetchBackend HTTP request has already completed successfully or errored.
Previously, FetchBackend unconditionally called abort() upon stream termination. When requests completed normally, calling abort() after delivery caused Chromium-based browsers to mark the resolved request as net::ERR_ABORTED in DevTools due to a race condition, leading to missing response body payloads ("Failed to load response data"). By tracking whether the request has already settled—similar to XhrBackend checking for xhr.readyState !== xhr.DONE—we ensure abort() is only called for unsettled, in-flight requests upon unsubscription.
Fixes#70071
Previously, `parseCookieValue` did not strip enclosing double quotes (`DQUOTE`) from quoted cookie values as specified in RFC 6265 Section 4.1.1. In addition, malformed percent-encoding in cookie values caused an unhandled `URIError` when calling `decodeURIComponent`.
Extract the charset parameter from the Content-Type response header in FetchBackend and pass it to TextDecoder when decoding text and json responses. When no valid charset is provided or supported, gracefully fall back to default utf-8 decoding.
Fixes#70061
Replace synchronous detectChanges calls with zoneless-compatible scheduling and stability waits. Preserve NgComponentOutlet coverage for components declared by NgModules.
Represent withRequestsMadeViaParent() with an internal delegating backend so the interceptor handler can distinguish delegated clients from independent child configurations.
Include the XSRF interceptor in the root token factory so the automatically provided HttpClient retains the documented default protection without requiring provideHttpClient().
Normalize value-specific HttpHeaders deletions before filtering. The string overload previously used String#indexOf and removed shorter values contained within the requested deletion value, potentially widening outgoing request metadata.
Preserve delete-all behavior only when no value is supplied, and cover string, array, and empty-string deletion.
Prevent lazy HttpHeaders and HttpParams clones from reusing value arrays owned by a materialized source. Append and value-specific delete operations previously mutated those shared arrays, violating the immutable API contract and allowing request metadata to bleed into later requests.
Share value arrays until an update mutates a specific header or parameter, then copy only that array. Cover the affected append and delete paths with regression tests that materialize the source first.
Propagate the crossorigin attribute from priority NgOptimizedImage hosts to SSR-generated preload links. Keep preload and image requests in the same credentials mode to avoid an anonymous image issuing an earlier credentialed request.
`makeCacheKey` joined the request fields with `|` before hashing. The url
and the serialized body can contain `|` themselves, so a shifted field
boundary (url `/items/a` + body `b|c` vs url `/items/a|b` + body `c`)
produced the same joined string and the same key, letting two distinct
requests share a transfer cache slot.
Join with `\0` instead, which cannot occur in a valid url or in encoded
params, so the field boundaries cannot be forged by field content.
The NAMED_FORMATS and DATE_FORMATS caches were plain objects read with a
truthy check keyed by a token from the format string, so a token matching
an inherited Object member (e.g. `__proto__`) resolved to a prototype
value. Create both caches with a null prototype so only real entries are
returned.
When `HttpClient` is called from within an `effect()` or other reactive
context, any signal reads performed inside HTTP interceptors were
inadvertently tracked by that context. This caused the effect to
re-execute whenever those signals changed, regardless of whether the
signal was semantically related to the HTTP call.
The fix wraps the interceptor chain invocation in `untracked()` so that
signal reads inside interceptors — both functional (`withInterceptors`)
and class-based (`withInterceptorsFromDi`) — are invisible to the
calling reactive context. This matches the precedent set by the resource
API, which also wraps its loader in `untracked()` for the same reason.
Fixes#58682
Adds build-time validation to catch broken, stale, or miscased internal documentation links in both JSDoc and markdown, including `/api/` and `/guide/` URLs and their fragments. Updates the documentation pipeline to share the canonical route manifest, ensuring that all references are checked against the current navigation structure.
`parseQueryParam` and the AngularJS-compat `parseKeyValue` accumulate query params into a plain object and check key presence with `obj.hasOwnProperty`, so a `hasOwnProperty` query key clobbers the method and the next lookup throws `TypeError`. Switch both to `Object.hasOwn`, which can't be shadowed by a query key.
`I18nSelectPipe.transform()` called `mapping.hasOwnProperty()` directly,
which fails in two edge cases:
- Mappings created with `Object.create(null)` have no prototype and
therefore no `hasOwnProperty` method, causing a TypeError at runtime.
- Mappings where a key literally named `hasOwnProperty` shadows the
built-in method return incorrect results silently.
Replace both call sites with `Object.hasOwn(mapping, key)`, which
delegates through `Object` directly and is immune to both issues.
Add two regression tests that demonstrate the broken behaviour before
the fix and pass after it.
Skip HttpTransferCache serialization for HTTP responses that contain a
Set-Cookie header.
Cookie-setting responses commonly represent session-specific,
user-specific, or security-sensitive state. Serializing their bodies into
SSR TransferState can embed sensitive data into the generated HTML, where
it may be reused during hydration or replayed by a shared cache/CDN.
Serialize transfer cache request parameters without comma-joining repeated values so distinct HttpClient requests cannot reuse the same cached response.
`findAnchorFromDocument` interpolates the raw url fragment into
`[name="${target}"]` for the shadow DOM lookup, so a fragment reachable
through the router when `anchorScrolling` is on can break out of the
attribute selector and make `querySelector` throw or match unrelated
nodes, and it also breaks legitimate anchor names containing a quote.
Wrap the value in `CSS.escape` so it stays a single attribute-value token.
Replace `in` operator with `Object.hasOwn` in
formatDateTime to prevent prototype pollution attacks.
The `in` operator traverses the prototype chain, meaning a polluted
Object.prototype key could be picked up as a valid replacement value.
This is especially critical in SSR environments where a single
prototype pollution attack persists across all subsequent requests in
the shared Node.js process, potentially injecting malicious content
into every user's rendered HTML.
Using `Object.hasOwn` restricts the lookup to
own properties only, blocking prototype chain traversal.
The `escapeCssUrl` helper used by `NgOptimizedImage` to sanitize placeholder URLs for use in the `background-image` CSS property previously escaped only backslashes and double quotes. However, several characters that can terminate a CSS quoted string according to the CSS Syntax Level 3 specification were left unescaped, allowing a crafted placeholder URL to break out of the `url("...")` context and inject arbitrary CSS.
This change additionally escapes the following characters using CSS hex escapes:
* `U+000A` (LINE FEED) → `\A `
* `U+000D` (CARRIAGE RETURN) → `\D `
* `U+000C` (FORM FEED) → `\C `
* `U+0000` (NULL) → `\0 `
For example:
```text id="1w5vkp"
x.com/img\nx.jpg → x.com/img\A x.jpg
x.com/img\rx.jpg → x.com/img\D x.jpg
x.com/img\fx.jpg → x.com/img\C x.jpg
x.com/img\0x.jpg → x.com/img\0 x.jpg
```
The trailing space is required by the CSS tokenizer to terminate the escape sequence and prevent the following character from being interpreted as part of the escape.
The backslash replacement remains first in the chain to avoid double-escaping the backslashes introduced by subsequent replacements.
Preserve `referrer: ''` when constructing and cloning HttpRequest.
An empty string is a valid Fetch referrer value and is documented by
Angular as the way to omit referrer information for sensitive requests.
The previous truthy checks treated it as if the option was not provided,
causing requests to fall back to the browser default referrer behavior.
Replace the custom 64-bit non-cryptographic combined DJB2 hashing implementation in HttpTransferCache with a robust, pure JavaScript, synchronous SHA-256 algorithm.
Introduces a maximum length of 256 characters for date format strings.
This prevents potential Denial of Service (DoS) attacks by throwing an
`INVALID_DATE_FORMAT` error if an excessively long format string is
provided to `formatDate` or `DatePipe`, safeguarding against performance
degradation or application crashes.
JSONP is deprecated because it is prone to Cross-Site Scripting (XSS) attacks. Since JSONP works by executing arbitrary scripts in the global context, it bypasses modern Content Security Policies (CSP) and can lead to severe security vulnerabilities if the server or endpoint is compromised.
DEPRECATED: `HttpClient.jsonp`, `HttpClientJsonpModule`, and related JSONP classes/functions are deprecated. Use standard HTTP requests instead.
Previously, when making an HTTP request where the URL contained a fragment (`#`) and `HttpParams` were provided, the parameters were appended to the very end of the URL (after the fragment). This resulted in the parameters being treated as part of the fragment rather than query parameters, potentially bypassing server-side logic and validation.
This commit updates the URL parsing logic in `HttpRequest` to split the URL by the fragment, correctly inserting the query string before any fragment.
Do not store HTTP transfer cache entries when either the request or response
uses `Cache-Control: no-store`, `Cache-Control: private`, or
`Cache-Control: no-cache`.
Also skip transfer cache when requests use the Fetch API `cache` option with
`no-store` or `no-cache`.
Because transfer cache serializes SSR HTTP responses into the rendered HTML,
Angular now treats these directives conservatively to avoid exposing sensitive
or explicitly uncacheable data through `TransferState`.
PR Close#69017
Treat HttpClient requests using `credentials: 'include'` and `same-origin` as credentialed
when deciding whether a response can be stored in the HTTP transfer cache.
The transfer cache already skips requests with `withCredentials`, `Cookie`,
`Authorization`, or `Proxy-Authorization` because those responses may contain
user-specific data. Fetch-backed requests can express the same credentialed
behavior through the `credentials` option, so these responses must not be
serialized into the SSR HTML.
This keeps credentialed SSR responses out of TransferState and aligns the
cache eligibility check with the fetch request options supported by HttpClient.
PR Close#69017
Hit this while exercising `Location.normalize` with route paths that end in non-`.html` suffixes.
The unescaped `.` in the strip regex inside `_stripIndexHtml` matches any character, so e.g. `/foo/indexXhtml` and `/foo/index_html` both collapse to `/foo` before the base-path strip and end up resolving to the wrong route.
Escape the dot so only the literal `/index.html` suffix is stripped.
By default, the `FetchBackend` on SSR will limit the response body size to 10 MB.
If the response body exceeds this limit, an error will be thrown.
This default value can be configured by providing by setting the `maxResponseBodySize` in `provideServerRendering`.
This is to prevent DoS on the server when loading large files
Update the transfer cache check to safely exclude all requests sent with the `withCredentials` flag.
By default, the HTTP transfer cache avoids caching user-specific responses to prevent sensitive data exposure or incorrect caching. While requests with explicit headers like `Cookie` or `Authorization` are excluded by default, requests can also be sent with credentials via the `withCredentials` flag without having those headers explicitly declared on the request object.
To keep user-specific responses from being cached, exclude `withCredentials` requests unconditionally, even when the `includeRequestsWithAuthHeaders` option is set to true.
Treat requests with a Cookie header like other auth-bearing requests and skip TransferCache caching them by default.
This preserves the explicit opt-in path via includeRequestsWithAuthHeaders, adds regression coverage for cookie-bearing requests, and updates the SSR guide to document the behavior.