Skip to content

Commit 7c066a4

Browse files
JeanMechethePunderWoman
authored andcommitted
fix(http): Use the response content-type to set the blob type. (#52840)
When downloading a PDF with the fetch client, the blob had no content. It couldn't be displayed in an iframe. This commit fixes this. Relate to: https://stackoverflow.com/questions/77470626/possible-bug-in-httpclient-when-using-the-blob-data-type PR Close #52840
1 parent 6a1d4ed commit 7c066a4

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

packages/common/http/src/fetch.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ export class FetchBackend implements HttpBackend {
145145
// Combine all chunks.
146146
const chunksAll = this.concatChunks(chunks, receivedLength);
147147
try {
148-
body = this.parseBody(request, chunksAll);
148+
const contentType = response.headers.get('Content-Type') ?? '';
149+
body = this.parseBody(request, chunksAll, contentType);
149150
} catch (error) {
150151
// Body loading or parsing failed
151152
observer.error(new HttpErrorResponse({
@@ -193,8 +194,8 @@ export class FetchBackend implements HttpBackend {
193194
}
194195
}
195196

196-
private parseBody(request: HttpRequest<any>, binContent: Uint8Array): string|ArrayBuffer|Blob
197-
|object|null {
197+
private parseBody(request: HttpRequest<any>, binContent: Uint8Array, contentType: string): string
198+
|ArrayBuffer|Blob|object|null {
198199
switch (request.responseType) {
199200
case 'json':
200201
// stripping the XSSI when present
@@ -203,7 +204,7 @@ export class FetchBackend implements HttpBackend {
203204
case 'text':
204205
return new TextDecoder().decode(binContent);
205206
case 'blob':
206-
return new Blob([binContent]);
207+
return new Blob([binContent], {type: contentType});
207208
case 'arraybuffer':
208209
return binContent.buffer;
209210
}

packages/common/http/test/fetch_spec.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,16 @@ describe('FetchBackend', async () => {
217217
expect(res.body!.data).toBe('some data');
218218
});
219219

220+
it('handles a blob with a mime type', async () => {
221+
const promise = trackEvents(backend.handle(TEST_POST.clone({responseType: 'blob'})));
222+
const type = 'aplication/pdf';
223+
fetchMock.mockFlush(HttpStatusCode.Ok, 'OK', new Blob(), {'Content-Type': type});
224+
const events = await promise;
225+
expect(events.length).toBe(2);
226+
const res = events[1] as HttpResponse<Blob>;
227+
expect(res.body?.type).toBe(type);
228+
});
229+
220230
it('emits unsuccessful responses via the error path', done => {
221231
backend.handle(TEST_POST).subscribe({
222232
error: (err: HttpErrorResponse) => {
@@ -400,12 +410,18 @@ export class MockFetchFactory extends FetchFactory {
400410
return this.promise;
401411
}
402412

403-
mockFlush(status: number, statusText: string, body?: string): void {
413+
mockFlush(
414+
status: number, statusText: string, body?: string|Blob, headers?: Record<string, string>):
415+
void {
404416
this.clearWarningTimeout?.();
405-
this.response.setupBodyStream(body);
406-
407-
const response =
408-
new Response(this.response.stream, {statusText, headers: this.response.headers});
417+
if (typeof body === 'string') {
418+
this.response.setupBodyStream(body);
419+
} else {
420+
this.response.setBody(body);
421+
}
422+
const response = new Response(
423+
this.response.stream,
424+
{statusText, headers: {...this.response.headers, ...(headers ?? {})}});
409425

410426
// Have to be set outside the constructor because it might throw
411427
// RangeError: init["status"] must be in the range of 200 to 599, inclusive
@@ -470,6 +486,11 @@ class MockFetchResponse {
470486
},
471487
});
472488

489+
public setBody(body: any) {
490+
this.sub$.next(body);
491+
this.sub$.complete();
492+
}
493+
473494
public setupBodyStream(body?: string) {
474495
if (body && this.progress.length) {
475496
this.headers['content-length'] = `${body.length}`;

0 commit comments

Comments
 (0)