mirror of
https://github.com/reactos/wine.git
synced 2024-11-26 05:00:30 +00:00
wininet: Fixed gzip decoding on chunked stream.
This commit is contained in:
parent
4540d74f49
commit
a76db21978
@ -165,14 +165,16 @@ struct HttpAuthInfo
|
||||
BOOL finished; /* finished authenticating */
|
||||
};
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
struct gzip_stream_t {
|
||||
#ifdef HAVE_ZLIB
|
||||
z_stream zstream;
|
||||
BYTE buf[4096];
|
||||
};
|
||||
|
||||
#endif
|
||||
BYTE buf[8192];
|
||||
DWORD buf_size;
|
||||
DWORD buf_pos;
|
||||
BOOL end_of_data;
|
||||
};
|
||||
|
||||
static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
|
||||
static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear);
|
||||
@ -223,6 +225,11 @@ static void init_gzip_stream(WININETHTTPREQW *req)
|
||||
gzip_stream->zstream.opaque = NULL;
|
||||
gzip_stream->zstream.next_in = NULL;
|
||||
gzip_stream->zstream.avail_in = 0;
|
||||
gzip_stream->zstream.next_out = NULL;
|
||||
gzip_stream->zstream.avail_out = 0;
|
||||
gzip_stream->buf_pos = 0;
|
||||
gzip_stream->buf_size = 0;
|
||||
gzip_stream->end_of_data = FALSE;
|
||||
|
||||
zres = inflateInit2(&gzip_stream->zstream, 0x1f);
|
||||
if(zres != Z_OK) {
|
||||
@ -232,14 +239,6 @@ static void init_gzip_stream(WININETHTTPREQW *req)
|
||||
}
|
||||
|
||||
req->gzip_stream = gzip_stream;
|
||||
req->dwContentLength = ~0u;
|
||||
|
||||
if(req->read_size) {
|
||||
memcpy(gzip_stream->buf, req->read_buf + req->read_pos, req->read_size);
|
||||
gzip_stream->zstream.next_in = gzip_stream->buf;
|
||||
gzip_stream->zstream.avail_in = req->read_size;
|
||||
req->read_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1750,61 +1749,6 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf
|
||||
return ERROR_INTERNET_INVALID_OPTION;
|
||||
}
|
||||
|
||||
static inline BOOL is_gzip_buf_empty(gzip_stream_t *gzip_stream)
|
||||
{
|
||||
#ifdef HAVE_ZLIB
|
||||
return gzip_stream->zstream.avail_in == 0;
|
||||
#else
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static DWORD read_gzip_data(WININETHTTPREQW *req, BYTE *buf, int size, int flags, int *read_ret)
|
||||
{
|
||||
DWORD ret = ERROR_SUCCESS;
|
||||
int read = 0;
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
int res, len, zres;
|
||||
z_stream *zstream;
|
||||
|
||||
zstream = &req->gzip_stream->zstream;
|
||||
|
||||
while(read < size) {
|
||||
if(is_gzip_buf_empty(req->gzip_stream)) {
|
||||
res = NETCON_recv( &req->netConnection, req->gzip_stream->buf,
|
||||
sizeof(req->gzip_stream->buf), flags, &len);
|
||||
if(!res) {
|
||||
if(!read)
|
||||
ret = INTERNET_GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
zstream->next_in = req->gzip_stream->buf;
|
||||
zstream->avail_in = len;
|
||||
}
|
||||
|
||||
zstream->next_out = buf+read;
|
||||
zstream->avail_out = size-read;
|
||||
zres = inflate(zstream, Z_FULL_FLUSH);
|
||||
read = size - zstream->avail_out;
|
||||
if(zres == Z_STREAM_END) {
|
||||
TRACE("end of data\n");
|
||||
req->dwContentLength = req->dwContentRead + req->read_size + read;
|
||||
break;
|
||||
}else if(zres != Z_OK) {
|
||||
WARN("inflate failed %d\n", zres);
|
||||
if(!read)
|
||||
ret = ERROR_INTERNET_DECODING_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*read_ret = read;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read some more data into the read buffer (the read section must be held) */
|
||||
static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
|
||||
{
|
||||
@ -1820,14 +1764,9 @@ static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
|
||||
|
||||
if (maxlen == -1) maxlen = sizeof(req->read_buf);
|
||||
|
||||
if (req->gzip_stream) {
|
||||
if(read_gzip_data(req, req->read_buf + req->read_size, maxlen - req->read_size, 0, &len) != ERROR_SUCCESS)
|
||||
return FALSE;
|
||||
}else {
|
||||
if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
|
||||
maxlen - req->read_size, 0, &len ))
|
||||
return FALSE;
|
||||
}
|
||||
if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
|
||||
maxlen - req->read_size, 0, &len ))
|
||||
return FALSE;
|
||||
|
||||
req->read_size += len;
|
||||
return TRUE;
|
||||
@ -1939,17 +1878,10 @@ static BOOL start_next_chunk( WININETHTTPREQW *req )
|
||||
}
|
||||
}
|
||||
|
||||
/* return the size of data available to be read immediately (the read section must be held) */
|
||||
static DWORD get_avail_data( WININETHTTPREQW *req )
|
||||
{
|
||||
if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
|
||||
return 0;
|
||||
return min( req->read_size, req->dwContentLength - req->dwContentRead );
|
||||
}
|
||||
|
||||
/* check if we have reached the end of the data to read (the read section must be held) */
|
||||
static BOOL end_of_read_data( WININETHTTPREQW *req )
|
||||
{
|
||||
if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
|
||||
if (req->read_chunked) return (req->dwContentLength == 0);
|
||||
if (req->dwContentLength == ~0u) return FALSE;
|
||||
return (req->dwContentLength == req->dwContentRead);
|
||||
@ -1973,6 +1905,76 @@ static BOOL refill_buffer( WININETHTTPREQW *req )
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD read_gzip_data(WININETHTTPREQW *req, BYTE *buf, int size, BOOL sync, int *read_ret)
|
||||
{
|
||||
DWORD ret = ERROR_SUCCESS;
|
||||
int read = 0;
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
z_stream *zstream = &req->gzip_stream->zstream;
|
||||
int zres;
|
||||
|
||||
while(read < size && !req->gzip_stream->end_of_data) {
|
||||
if(!req->read_size) {
|
||||
if(!sync || !refill_buffer(req))
|
||||
break;
|
||||
}
|
||||
|
||||
zstream->next_in = req->read_buf+req->read_pos;
|
||||
zstream->avail_in = req->read_size;
|
||||
zstream->next_out = buf+read;
|
||||
zstream->avail_out = size-read;
|
||||
zres = inflate(zstream, Z_FULL_FLUSH);
|
||||
read = size - zstream->avail_out;
|
||||
remove_data(req, req->read_size-zstream->avail_in);
|
||||
if(zres == Z_STREAM_END) {
|
||||
TRACE("end of data\n");
|
||||
req->gzip_stream->end_of_data = TRUE;
|
||||
}else if(zres != Z_OK) {
|
||||
WARN("inflate failed %d\n", zres);
|
||||
if(!read)
|
||||
ret = ERROR_INTERNET_DECODING_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*read_ret = read;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void refill_gzip_buffer(WININETHTTPREQW *req)
|
||||
{
|
||||
DWORD res;
|
||||
int len;
|
||||
|
||||
if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
|
||||
return;
|
||||
|
||||
if(req->gzip_stream->buf_pos) {
|
||||
if(req->gzip_stream->buf_size)
|
||||
memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
|
||||
req->gzip_stream->buf_pos = 0;
|
||||
}
|
||||
|
||||
res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
|
||||
sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
|
||||
if(res == ERROR_SUCCESS)
|
||||
req->gzip_stream->buf_size += len;
|
||||
}
|
||||
|
||||
/* return the size of data available to be read immediately (the read section must be held) */
|
||||
static DWORD get_avail_data( WININETHTTPREQW *req )
|
||||
{
|
||||
if (req->gzip_stream) {
|
||||
refill_gzip_buffer(req);
|
||||
return req->gzip_stream->buf_size;
|
||||
}
|
||||
if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
|
||||
return 0;
|
||||
return min( req->read_size, req->dwContentLength - req->dwContentRead );
|
||||
}
|
||||
|
||||
static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif)
|
||||
{
|
||||
INTERNET_ASYNC_RESULT iar;
|
||||
@ -1996,37 +1998,51 @@ static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif)
|
||||
/* read data from the http connection (the read section must be held) */
|
||||
static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
|
||||
{
|
||||
BOOL finished_reading = FALSE;
|
||||
int len, bytes_read = 0;
|
||||
DWORD ret = ERROR_SUCCESS;
|
||||
|
||||
EnterCriticalSection( &req->read_section );
|
||||
|
||||
if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
|
||||
{
|
||||
if (!start_next_chunk( req )) goto done;
|
||||
}
|
||||
if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
|
||||
|
||||
if (req->read_size)
|
||||
{
|
||||
bytes_read = min( req->read_size, size );
|
||||
memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
|
||||
remove_data( req, bytes_read );
|
||||
}
|
||||
if(req->gzip_stream) {
|
||||
if(req->gzip_stream->buf_size) {
|
||||
bytes_read = min(req->gzip_stream->buf_size, size);
|
||||
memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
|
||||
req->gzip_stream->buf_pos += bytes_read;
|
||||
req->gzip_stream->buf_size -= bytes_read;
|
||||
}else if(!req->read_size && !req->gzip_stream->end_of_data) {
|
||||
refill_buffer(req);
|
||||
}
|
||||
|
||||
if (size > bytes_read)
|
||||
{
|
||||
if (req->gzip_stream) {
|
||||
if(is_gzip_buf_empty(req->gzip_stream) || !bytes_read || sync) {
|
||||
ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size - bytes_read, sync ? MSG_WAITALL : 0, &len);
|
||||
if(ret == ERROR_SUCCESS)
|
||||
bytes_read += len;
|
||||
}
|
||||
}else if (!bytes_read || sync) {
|
||||
if(size > bytes_read) {
|
||||
ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
|
||||
if(ret == ERROR_SUCCESS)
|
||||
bytes_read += len;
|
||||
}
|
||||
|
||||
finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
|
||||
}else {
|
||||
if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
|
||||
|
||||
if (req->read_size) {
|
||||
bytes_read = min( req->read_size, size );
|
||||
memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
|
||||
remove_data( req, bytes_read );
|
||||
}
|
||||
|
||||
if (size > bytes_read && (!bytes_read || sync)) {
|
||||
if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
|
||||
sync ? MSG_WAITALL : 0, &len))
|
||||
bytes_read += len;
|
||||
/* always return success, even if the network layer returns an error */
|
||||
}
|
||||
|
||||
finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
|
||||
}
|
||||
done:
|
||||
req->dwContentRead += bytes_read;
|
||||
@ -2044,7 +2060,7 @@ done:
|
||||
WARN("WriteFile failed: %u\n", GetLastError());
|
||||
}
|
||||
|
||||
if(!bytes_read && (req->dwContentRead == req->dwContentLength))
|
||||
if(finished_reading)
|
||||
HTTP_FinishedReading(req);
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user