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
compress/flate: implement partial flush #31514
Comments
I assume this is in the flate package where you need this? At least initially? /cc @nigeltao |
From what I could tell, the real work is in the flate package, but then the zlib package should also also expose it, because SSH produces and consumes the zlib version header. |
What about the reader side of things? Wouldn't a partial flush on the writer only be useful if the reader had API to synchronize on these specialized flushing modes? I should note that this is more difficult on the reader side for API design, since the reader lacks an exported concrete type. |
Also, my reading of partial flush suggests that partial flush is a subset of sync flush, which the writer already supports. |
I've seen that the bytes already get decompressed correctly (so it kind of works), but then the reader wants to read on and finds EOF. The reader should know to stop further reads when it encounters a partial flush. For API: when the reader encounters partial flush, it could just return the bytes thus far read without error. In SSH then, the caller could use bytes.Buffer{} as input to the reader, and stop requesting further zlib bytes when the buffer is empty. |
@hanwen, is there internal framing within the SSH protocol such that it can distinguish between a return from |
SSH protocol has packets, that are up to 32kb in size. The entire packet payload is compressed, so one would read until the entire packet was processed. I think there is could be chunking going on, so that you may need to do multiple reads to process a single packet. |
I'm not sure if that answered my question. More specifically: how does SSH handle framing for the packet? For the un-compressed data does it have a length-prefix or a delimiter marking the length or end of the packet? Or does it rely on a partial flush in DEFLATE to determine the end of a packet? If the former, all that's required in |
there is no size prefix or delimiter. On the read side, you just keep reading until there are no compressed bytes left to process. If the read API would be changed to be // Read up to buf bytes, or up to the next partial or full flush encountered in the compressed input then you could do
this might break current users that expect to be able to read a certain amount of data in a single Read call, though. There is packet framing, but it is around the compressed payload: the compressed data is padded, encrypted, mac'd and prefixed with total length for the encrypted packet. |
@hanwen if we put limit on number of bytes read from underlying Reader and return error if maximum read limit is reached, then I think this will solve problem of reading till EOF. We will need new interface for decompressor:
Also, we need to add new property to store limit on number of bytes read from underlying Reader.
if Add
We will need two more functions for decompressor:
And finally, we need to replace Then in application, you can do
Above code will return ReadLimitReached error after reading 10 bytes but it will not read till EOF This will not break current users |
Change https://golang.org/cl/187018 mentions this issue: |
Change https://golang.org/cl/198757 mentions this issue: |
The docs on the synchronization example at https://golang.org/pkg/compress/flate/ need to be updated. They state: // Read the message length.
// This is guaranteed to return for every corresponding
// Flush and Close on the transmitter side. But that is not true for Flush on a writer without pending data. compress/flate will write the 4 byte sync marker but the read side will never return. See go/src/compress/flate/inflate.go Line 336 in 4b43700
The loop only returns if there are additional bytes in the buffer to be read. |
In order to implement context takeover compression for WebSockets, I was able to get around the above issue by using Janky but works for now. |
Funnily enough, the hack of ignoring |
There are also PDF files out there with seemingly embedded partial flushed flate encoded streams. |
What version of Go are you using (
go version
)?go-1.11.5
while trying to implement zlib compression for SSH (by internal Google request,
#31369), I stumbled on lack of support for partial flush.
partial flush is described more precisely here: https://www.bolet.org/~pornin/deflate-flush.html (look for Z_PARTIAL_FLUSH). While this is deprecated functionality, it has also made its way into the SSH RFC.
For the write side, it looks like I can't truncate the sync marker from a full flush to get the same effect.
For the read side, feeding packets from OpenSSH into zlib.Reader leads to errors ("unexpected EOF").
The text was updated successfully, but these errors were encountered: