Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request dont decompress response body #2260

Open
PandaWorker opened this issue Sep 9, 2023 · 15 comments
Open

request dont decompress response body #2260

PandaWorker opened this issue Sep 9, 2023 · 15 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@PandaWorker
Copy link

PandaWorker commented Sep 9, 2023

Bug Description

Why doesn't request support response body decompression?

import { request } from "undici";

const resp = await request('https://jsonplaceholder.typicode.com/todos/1', {
    headers: {
        'accept-encoding': 'gzip'
    }
});

const content = await resp.body.text();
console.log(`status:`, resp.statusCode);
console.log(`encoding:`, resp.headers['content-encoding']);
console.log(`body:`, content); // compressed

Logs & Screenshots

using fetch
image

using request
image

Environment

undici@5.24.0

@PandaWorker PandaWorker added the bug Something isn't working label Sep 9, 2023
@metcoder95 metcoder95 removed the bug Something isn't working label Sep 9, 2023
@metcoder95
Copy link
Member

That’s because there’s no hard need for request to decompress the body. By spec fetch requires to do so.

This is not a bug in Undici but rather an expected outcome. Decompress is up to the responde handler and not to the client itself per se

@PandaWorker
Copy link
Author

Maybe you need to add some parameter to unpack body ?

@KhafraDev KhafraDev added the enhancement New feature or request label Sep 9, 2023
@metcoder95
Copy link
Member

I'm not 100% convinced but not against it. I have the feeling that it can cause several regressions, as well as hide possible optimizations that can be made on the implementer's side. Like custom backpressure and whatnot.

@ronag @mcollina @KhafraDev any thoughts? I think Khafra is already +1 😄 ?

@mcollina
Copy link
Member

I'm -1 in adding it to request, it would slow us down even if it's not enabled.

I'm ok to add it under an option, if you really think it's necessary.

@PandaWorker
Copy link
Author

I think we need to add the decompress: boolean parameter in requestOptions

@Ealenn
Copy link

Ealenn commented Oct 25, 2023

Hello ! Maybe something automatic, like if the response contains gzip encoding header we should decompress it ?

@metcoder95
Copy link
Member

I'm more into the possibility of creating a DecompressHandler that infers the content-encoding header and applies decompression, similar to what we are doing for retries on #2264, but -1 on adding it as part of the request options or within core at all

@KhafraDev
Copy link
Member

#1155 (comment)

I think that if we are going to recommend request over fetch, it should be just as easy to use. I'm fine with it not being enabled by default, but it wouldn't be that hard to reuse the logic from fetch.

@ronag
Copy link
Member

ronag commented Oct 25, 2023

I'm fine with an option. An alternative is to add it through a handler, similar to what https://github.com/nxtedition/nxt-undici does.

Not sure if I like our current "interceptor" pattern but it could go through something like that.

@mcollina
Copy link
Member

I'm +1 to an option or a documentated interceptor.

@metcoder95 metcoder95 added the good first issue Good for newcomers label Oct 25, 2023
@metcoder95
Copy link
Member

Marking as good-first-issue

@Lewiscowles1986
Copy link

See #951 as well RE: last comment.

@metcoder95
Copy link
Member

See RetryHandler to get a sense of how an interceptor looks like.

@KhafraDev
Copy link
Member

undici/lib/fetch/index.js

Lines 2171 to 2210 in 6a04edc

this.body = new Readable({ read: resume })
const decoders = []
const willFollow = location && request.redirect === 'follow' &&
redirectStatusSet.has(status)
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
for (let i = 0; i < codings.length; ++i) {
const coding = codings[i]
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
if (coding === 'x-gzip' || coding === 'gzip') {
decoders.push(zlib.createGunzip({
// Be less strict when decoding compressed responses, since sometimes
// servers send slightly invalid responses that are still accepted
// by common browsers.
// Always using Z_SYNC_FLUSH is what cURL does.
flush: zlib.constants.Z_SYNC_FLUSH,
finishFlush: zlib.constants.Z_SYNC_FLUSH
}))
} else if (coding === 'deflate') {
decoders.push(zlib.createInflate())
} else if (coding === 'br') {
decoders.push(zlib.createBrotliDecompress())
} else {
decoders.length = 0
break
}
}
}
resolve({
status,
statusText,
headersList,
body: decoders.length
? pipeline(this.body, ...decoders, () => { })
: this.body.on('error', () => {})
})
for the actual decompressing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

7 participants