Skip to content

refactor(http): Improves base64 encoding/decoding with feature detection#67002

Open
SkyZeroZx wants to merge 5 commits intoangular:mainfrom
SkyZeroZx:refactor/http-from-to-64
Open

refactor(http): Improves base64 encoding/decoding with feature detection#67002
SkyZeroZx wants to merge 5 commits intoangular:mainfrom
SkyZeroZx:refactor/http-from-to-64

Conversation

@SkyZeroZx
Copy link
Contributor

Use feature detection for Uint8Array.prototype.toBase64 and Uint8Array.fromBase64, falling back to the existing implementation when native support is not available

This is considerably faster when we have sizes like 50kb some like

https://github.com/SkyZeroZx/benchmark-encode-decode-64

encode workaround x 3,732 ops/sec ±2.72% (92 runs sampled)
encode native x 232,185 ops/sec ±1.93% (91 runs sampled)
decode workaround x 258 ops/sec ±2.56% (88 runs sampled)
decode native x 39,383 ops/sec ±1.92% (89 runs sampled)

@pullapprove pullapprove bot requested a review from AndrewKushnir February 10, 2026 18:31
@angular-robot angular-robot bot added the area: common/http Issues related to HTTP and HTTP Client label Feb 10, 2026
@ngbot ngbot bot added this to the Backlog milestone Feb 10, 2026
Copy link
Contributor

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for this.

@alan-agius4 alan-agius4 added target: patch This PR is targeted for the next patch release action: merge The PR is ready for merge by the caretaker action: review The PR is still awaiting reviews from at least one requested reviewer and removed action: merge The PR is ready for merge by the caretaker labels Feb 11, 2026
Comment on lines +23 to +24
export function toBase64(buffer: unknown): string {
const bytes = new Uint8Array(buffer as ArrayBufferLike);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks off. Since toBase64 can get a Blob would it throw ?

I would very much prefer that this function is correctly typed and that the type assertion is made in the transfer cache.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve just updated it. It’s weird, but it doesn’t throw an exception if we pass a Blob; it just sets the Uint8Array length to 0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Uint8Array array empty if we pass it a blob ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can pass some like

const myBlob = new Blob(['hello' , 'world'])
const u8 = new Uint8Array(myBlob)
console.log(u8)

@SkyZeroZx SkyZeroZx force-pushed the refactor/http-from-to-64 branch from bd809c2 to 3fe3545 Compare February 11, 2026 16:59
[BODY]:
req.responseType === 'arraybuffer' || req.responseType === 'blob'
? toBase64(event.body)
? toBase64(event.body as ArrayBufferLike)
Copy link
Member

@JeanMeche JeanMeche Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct for a blob? If yes we should at least have a test that would show that this is okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I'll add a test for that and validate it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a comment, because that type assertion doesn't make it obvious

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct for a blob? If yes we should at least have a test that would show that this is okay.

I added a fix in this PR because parsing was needed. I tested it with Protocol Buffer, and I was confused by the response because it was always a Uint8Array (which is curious, since it works fine when setting a Blob). That was misleading on my part. This should fix the issue, and I tested both cases ( Blob and Uint8Array ) to ensure consistency

Copy link
Contributor

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

@SkyZeroZx SkyZeroZx force-pushed the refactor/http-from-to-64 branch from 7e21743 to 62f6ea1 Compare February 12, 2026 20:35
@SkyZeroZx
Copy link
Contributor Author

We can rerun the pipeline that the test failed in (hydration_spec.ts), since TransferCache now has asynchronous behavior

@SkyZeroZx SkyZeroZx force-pushed the refactor/http-from-to-64 branch from 32db6da to 086710c Compare February 19, 2026 01:44
Copy link
Contributor

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alan-agius4 alan-agius4 requested review from JeanMeche and removed request for AndrewKushnir February 27, 2026 07:02
@JeanMeche JeanMeche added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Mar 3, 2026
thePunderWoman pushed a commit that referenced this pull request Mar 4, 2026
…ion (#67002)

Use feature detection for `Uint8Array.prototype.toBase64` and
`Uint8Array.fromBase64`, falling back to the existing implementation
when native support is not available

PR Close #67002
thePunderWoman pushed a commit that referenced this pull request Mar 4, 2026
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data

PR Close #67002
@thePunderWoman
Copy link
Contributor

This PR was merged into the repository. The changes were merged into the following branches:

thePunderWoman pushed a commit that referenced this pull request Mar 4, 2026
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data

PR Close #67002
@thePunderWoman
Copy link
Contributor

This appears to have broken tests in main. We're looking into it.

@SkyZeroZx
Copy link
Contributor Author

This appears to have broken tests in main. We're looking into it.

Could this be related to how tests were written , now that it behaves asynchronously due to the recent changes?

return event$.pipe(
concatMap(async (event: HttpEvent<unknown>) => {
// Only cache successful HTTP responses.
if (event instanceof HttpResponse) {
let body = event.body;
if (req.responseType === 'blob') {
// Note: Blob is converted to ArrayBuffer because Uint8Array constructor
// doesn't accept Blob directly, which would result in an empty array.
// Type assertion is safe here: when responseType is 'blob', the body is guaranteed to be a Blob
const arrayBuffer = await (event.body as Blob).arrayBuffer();
body = toBase64(arrayBuffer);
} else if (req.responseType === 'arraybuffer') {

thePunderWoman added a commit to thePunderWoman/angular that referenced this pull request Mar 4, 2026
thePunderWoman added a commit to thePunderWoman/angular that referenced this pull request Mar 4, 2026
@thePunderWoman thePunderWoman mentioned this pull request Mar 4, 2026
@thePunderWoman
Copy link
Contributor

This definitely was the root cause. We're reverting this for now. Please take a look, @SkyZeroZx.

@thePunderWoman thePunderWoman reopened this Mar 4, 2026
@thePunderWoman thePunderWoman added action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews and removed action: merge The PR is ready for merge by the caretaker labels Mar 4, 2026
thePunderWoman added a commit that referenced this pull request Mar 4, 2026
thePunderWoman added a commit that referenced this pull request Mar 4, 2026
thePunderWoman added a commit that referenced this pull request Mar 4, 2026
…e detection (#67002)"

This reverts commit aafeb1d.

(cherry picked from commit 5338b59)
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data
Ensure httpResource properly handles the response flow
@SkyZeroZx SkyZeroZx force-pushed the refactor/http-from-to-64 branch from 086710c to 8312083 Compare March 4, 2026 17:51
@angular-robot angular-robot bot requested a review from JeanMeche March 4, 2026 17:51
@@ -424,15 +425,10 @@ describe('httpResource', () => {

it('should synchronously resolve with a cached value from TransferState', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to my review, this test was failing due to the recent changes to the transfer cache, which now behaves asynchronously.
I'm not sure if we should change the test name or if it's correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was intentional to ensure there's no loading state when pulling data from the transfer cache. #67307

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think it would stay as it is, only keeping the change I made due to the TransferCache update

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thePunderWoman With the latest changes, I think it would be okay to merge, or would we still need to adjust something?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews area: common/http Issues related to HTTP and HTTP Client target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants