content_encoding: accept up to 4 unknown trailer bytes after raw deflate data

Some servers issue raw deflate data that may be followed by an undocumented
trailer. This commit makes curl tolerate such a trailer of up to 4 bytes
before considering the data is in error.

Reported-by: clbr on github
Fixes #2719
This commit is contained in:
Patrick Monnerat 2018-07-12 22:46:15 +02:00
parent 5b511b0958
commit f8be737d8f

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -73,9 +73,9 @@
typedef enum { typedef enum {
ZLIB_UNINIT, /* uninitialized */ ZLIB_UNINIT, /* uninitialized */
ZLIB_INIT, /* initialized */ ZLIB_INIT, /* initialized */
ZLIB_INFLATING, /* Inflating started. */ ZLIB_INFLATING, /* inflating started. */
ZLIB_EXTERNAL_TRAILER, /* reading external trailer */
ZLIB_GZIP_HEADER, /* reading gzip header */ ZLIB_GZIP_HEADER, /* reading gzip header */
ZLIB_GZIP_TRAILER, /* reading gzip trailer */
ZLIB_GZIP_INFLATING, /* inflating gzip stream */ ZLIB_GZIP_INFLATING, /* inflating gzip stream */
ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
} zlibInitState; } zlibInitState;
@ -150,8 +150,8 @@ static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp)
if(result || !zp->trailerlen) if(result || !zp->trailerlen)
result = exit_zlib(conn, z, &zp->zlib_init, result); result = exit_zlib(conn, z, &zp->zlib_init, result);
else { else {
/* Only occurs for gzip with zlib < 1.2.0.4. */ /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
zp->zlib_init = ZLIB_GZIP_TRAILER; zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
} }
return result; return result;
} }
@ -233,6 +233,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
z->next_in = orig_in; z->next_in = orig_in;
z->avail_in = nread; z->avail_in = nread;
zp->zlib_init = ZLIB_INFLATING; zp->zlib_init = ZLIB_INFLATING;
zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
done = FALSE; done = FALSE;
break; break;
} }
@ -287,6 +288,9 @@ static CURLcode deflate_unencode_write(struct connectdata *conn,
z->next_in = (Bytef *) buf; z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes; z->avail_in = (uInt) nbytes;
if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
return process_trailer(conn, zp);
/* Now uncompress the data */ /* Now uncompress the data */
return inflate_stream(conn, writer, ZLIB_INFLATING); return inflate_stream(conn, writer, ZLIB_INFLATING);
} }
@ -532,7 +536,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
} }
break; break;
case ZLIB_GZIP_TRAILER: case ZLIB_EXTERNAL_TRAILER:
z->next_in = (Bytef *) buf; z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes; z->avail_in = (uInt) nbytes;
return process_trailer(conn, zp); return process_trailer(conn, zp);