wininet: Added support for decompressing gzip encoded content.
This commit is contained in:
parent
26bbf072aa
commit
11ca05f6ae
|
@ -669,6 +669,7 @@ ALSALIBS
|
|||
ESDLIBS
|
||||
ESDINCL
|
||||
ESDCONFIG
|
||||
ZLIB
|
||||
FREETYPEINCL
|
||||
FREETYPELIBS
|
||||
ft_devel
|
||||
|
@ -5776,6 +5777,7 @@ done
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_header in \
|
||||
|
@ -5899,7 +5901,8 @@ for ac_header in \
|
|||
unistd.h \
|
||||
utime.h \
|
||||
valgrind/memcheck.h \
|
||||
valgrind/valgrind.h
|
||||
valgrind/valgrind.h \
|
||||
zlib.h
|
||||
|
||||
do
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
|
@ -15051,6 +15054,85 @@ done
|
|||
|
||||
LIBS="$ac_wine_check_funcs_save_LIBS"
|
||||
|
||||
if test "$ac_cv_header_zlib_h" = "yes"
|
||||
then
|
||||
{ $as_echo "$as_me:$LINENO: checking for inflate in -lz" >&5
|
||||
$as_echo_n "checking for inflate in -lz... " >&6; }
|
||||
if test "${ac_cv_lib_z_inflate+set}" = set; then
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lz $LIBS"
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char inflate ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return inflate ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext && {
|
||||
test "$cross_compiling" = yes ||
|
||||
$as_test_x conftest$ac_exeext
|
||||
}; then
|
||||
ac_cv_lib_z_inflate=yes
|
||||
else
|
||||
$as_echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_lib_z_inflate=no
|
||||
fi
|
||||
|
||||
rm -rf conftest.dSYM
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_z_inflate" >&5
|
||||
$as_echo "$ac_cv_lib_z_inflate" >&6; }
|
||||
if test "x$ac_cv_lib_z_inflate" = x""yes; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_ZLIB 1
|
||||
_ACEOF
|
||||
|
||||
ZLIB="-lz"
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test "x$with_esd" != xno
|
||||
then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -377,7 +377,8 @@ AC_CHECK_HEADERS(\
|
|||
unistd.h \
|
||||
utime.h \
|
||||
valgrind/memcheck.h \
|
||||
valgrind/valgrind.h
|
||||
valgrind/valgrind.h \
|
||||
zlib.h
|
||||
)
|
||||
AC_HEADER_STAT()
|
||||
|
||||
|
@ -1172,6 +1173,13 @@ WINE_CHECK_LIB_FUNCS(\
|
|||
pthread_get_stacksize_np,
|
||||
[$LIBPTHREAD])
|
||||
|
||||
dnl **** Check for zlib ****
|
||||
if test "$ac_cv_header_zlib_h" = "yes"
|
||||
then
|
||||
AC_CHECK_LIB(z,inflate,[AC_DEFINE(HAVE_ZLIB,1,[Define to 1 if you have the `z' library (-lz).])
|
||||
AC_SUBST(ZLIB,"-lz")])
|
||||
fi
|
||||
|
||||
dnl **** Check for EsounD ****
|
||||
if test "x$with_esd" != xno
|
||||
then
|
||||
|
|
|
@ -7,7 +7,7 @@ MODULE = wininet.dll
|
|||
IMPORTLIB = wininet
|
||||
IMPORTS = mpr shlwapi shell32 user32 advapi32 kernel32 ntdll
|
||||
DELAYIMPORTS = secur32 crypt32
|
||||
EXTRALIBS = @SOCKETLIBS@
|
||||
EXTRALIBS = @SOCKETLIBS@ @ZLIB@
|
||||
|
||||
C_SRCS = \
|
||||
cookie.c \
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
#endif
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_ZLIB
|
||||
# include <zlib.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -162,6 +165,15 @@ struct HttpAuthInfo
|
|||
BOOL finished; /* finished authenticating */
|
||||
};
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
struct gzip_stream_t {
|
||||
z_stream zstream;
|
||||
BYTE buf[4096];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
|
||||
static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear);
|
||||
static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
|
||||
|
@ -188,6 +200,57 @@ static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
|
|||
return &req->pCustHeaders[HeaderIndex];
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, items*size);
|
||||
}
|
||||
|
||||
static void wininet_zfree(voidpf opaque, voidpf address)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
}
|
||||
|
||||
static void init_gzip_stream(WININETHTTPREQW *req)
|
||||
{
|
||||
gzip_stream_t *gzip_stream;
|
||||
int zres;
|
||||
|
||||
gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
|
||||
gzip_stream->zstream.zalloc = wininet_zalloc;
|
||||
gzip_stream->zstream.zfree = wininet_zfree;
|
||||
gzip_stream->zstream.opaque = NULL;
|
||||
gzip_stream->zstream.next_in = NULL;
|
||||
gzip_stream->zstream.avail_in = 0;
|
||||
|
||||
zres = inflateInit2(&gzip_stream->zstream, 0x1f);
|
||||
if(zres != Z_OK) {
|
||||
ERR("inflateInit failed: %d\n", zres);
|
||||
HeapFree(GetProcessHeap(), 0, gzip_stream);
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
static void init_gzip_stream(WININETHTTPREQW *req)
|
||||
{
|
||||
ERR("gzip stream not supported, missing zlib.\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* set the request content length based on the headers */
|
||||
static DWORD set_content_length( LPWININETHTTPREQW lpwhr )
|
||||
{
|
||||
|
@ -208,6 +271,16 @@ static DWORD set_content_length( LPWININETHTTPREQW lpwhr )
|
|||
lpwhr->read_chunked = TRUE;
|
||||
}
|
||||
|
||||
if(lpwhr->decoding) {
|
||||
int encoding_idx;
|
||||
|
||||
static const WCHAR gzipW[] = {'g','z','i','p',0};
|
||||
|
||||
encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
|
||||
if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
|
||||
init_gzip_stream(lpwhr);
|
||||
}
|
||||
|
||||
return lpwhr->dwContentLength;
|
||||
}
|
||||
|
||||
|
@ -1476,6 +1549,14 @@ static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr)
|
|||
|
||||
TRACE("%p\n",lpwhr);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
if(lpwhr->gzip_stream) {
|
||||
inflateEnd(&lpwhr->gzip_stream->zstream);
|
||||
HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
|
||||
lpwhr->gzip_stream = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!NETCON_connected(&lpwhr->netConnection))
|
||||
return;
|
||||
|
||||
|
@ -1659,26 +1740,95 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf
|
|||
HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
|
||||
if (!(req->lpHttpSession->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
|
||||
return ERROR_SUCCESS;
|
||||
case INTERNET_OPTION_HTTP_DECODING:
|
||||
if(size != sizeof(BOOL))
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
req->decoding = *(BOOL*)buffer;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
int len;
|
||||
|
||||
if (req->read_size && req->read_pos)
|
||||
if (req->read_pos)
|
||||
{
|
||||
/* move existing data to the start of the buffer */
|
||||
memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
|
||||
if(req->read_size)
|
||||
memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
|
||||
req->read_pos = 0;
|
||||
}
|
||||
|
||||
if (maxlen == -1) maxlen = sizeof(req->read_buf);
|
||||
if (!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
|
||||
maxlen - req->read_size, 0, &len )) return FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
req->read_size += len;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1847,6 +1997,7 @@ static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif)
|
|||
static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
|
||||
{
|
||||
int len, bytes_read = 0;
|
||||
DWORD ret = ERROR_SUCCESS;
|
||||
|
||||
EnterCriticalSection( &req->read_section );
|
||||
if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
|
||||
|
@ -1862,12 +2013,20 @@ static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD
|
|||
remove_data( req, bytes_read );
|
||||
}
|
||||
|
||||
if (size > bytes_read && (!bytes_read || sync))
|
||||
if (size > bytes_read)
|
||||
{
|
||||
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 */
|
||||
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 (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 */
|
||||
}
|
||||
}
|
||||
done:
|
||||
req->dwContentRead += bytes_read;
|
||||
|
@ -1876,7 +2035,7 @@ done:
|
|||
TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
|
||||
LeaveCriticalSection( &req->read_section );
|
||||
|
||||
if(req->lpszCacheFile) {
|
||||
if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
|
||||
BOOL res;
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
|
@ -1888,7 +2047,7 @@ done:
|
|||
if(!bytes_read && (req->dwContentRead == req->dwContentLength))
|
||||
HTTP_FinishedReading(req);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2101,7 +2260,7 @@ static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *availab
|
|||
}
|
||||
|
||||
done:
|
||||
if (*available == sizeof(req->read_buf)) /* check if we have even more pending in the socket */
|
||||
if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */
|
||||
{
|
||||
DWORD extra;
|
||||
if (NETCON_query_data_available(&req->netConnection, &extra))
|
||||
|
@ -2396,6 +2555,16 @@ static BOOL HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel,
|
|||
index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
|
||||
break;
|
||||
|
||||
case HTTP_QUERY_CONTENT_LENGTH:
|
||||
if(lpwhr->gzip_stream) {
|
||||
INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
|
||||
requested_index,request_only);
|
||||
break;
|
||||
|
||||
case HTTP_QUERY_RAW_HEADERS_CRLF:
|
||||
{
|
||||
LPWSTR headers;
|
||||
|
@ -2504,6 +2673,10 @@ static BOOL HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel,
|
|||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case HTTP_QUERY_CONTENT_ENCODING:
|
||||
index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
|
||||
requested_index,request_only);
|
||||
break;
|
||||
default:
|
||||
assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
|
||||
|
||||
|
|
|
@ -183,6 +183,8 @@ typedef struct
|
|||
|
||||
struct HttpAuthInfo;
|
||||
|
||||
typedef struct gzip_stream_t gzip_stream_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WININETHANDLEHEADER hdr;
|
||||
|
@ -209,6 +211,9 @@ typedef struct
|
|||
DWORD read_pos; /* current read position in read_buf */
|
||||
DWORD read_size; /* valid data size in read_buf */
|
||||
BYTE read_buf[4096]; /* buffer for already read but not returned data */
|
||||
|
||||
BOOL decoding;
|
||||
gzip_stream_t *gzip_stream;
|
||||
} WININETHTTPREQW, *LPWININETHTTPREQW;
|
||||
|
||||
|
||||
|
|
|
@ -1041,6 +1041,12 @@
|
|||
/* Define if Xrender has the XRenderSetPictureTransform function */
|
||||
#undef HAVE_XRENDERSETPICTURETRANSFORM
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#undef HAVE_ZLIB
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Define to 1 if you have the `_pclose' function. */
|
||||
#undef HAVE__PCLOSE
|
||||
|
||||
|
|
Loading…
Reference in New Issue