Author: akhaldi Date: Sun Jun 4 01:48:31 2017 New Revision: 74864
URL: http://svn.reactos.org/svn/reactos?rev=74864&view=rev Log: [WINHTTP] Sync with Wine Staging 2.9. CORE-13362
2fa86fd winhttp: Always drain content before sending the next request. 6b6ffb3 winhttp: Ignore unknown schemes in WinHttpQueryAuthSchemes. 08603e5 winhttp: Fix a memory leak in insert_header (Valgrind). be78574 winhttp: Cookie attributes are case-insensitive. 8595cc5 winhttp: Parse cookie attributes.
Modified: trunk/reactos/dll/win32/winhttp/cookie.c trunk/reactos/dll/win32/winhttp/request.c trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/winhttp/cookie.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/winhttp/cookie.c?... ============================================================================== --- trunk/reactos/dll/win32/winhttp/cookie.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/winhttp/cookie.c [iso-8859-1] Sun Jun 4 01:48:31 2017 @@ -155,17 +155,79 @@ return cookie; }
+struct attr +{ + WCHAR *name; + WCHAR *value; +}; + +static void free_attr( struct attr *attr ) +{ + if (!attr) return; + heap_free( attr->name ); + heap_free( attr->value ); + heap_free( attr ); +} + +static struct attr *parse_attr( const WCHAR *str, int *used ) +{ + const WCHAR *p = str, *q; + struct attr *attr; + int len; + + while (*p == ' ') p++; + q = p; + while (*q && *q != ' ' && *q != '=' && *q != ';') q++; + len = q - p; + if (!len) return NULL; + + if (!(attr = heap_alloc( sizeof(struct attr) ))) return NULL; + if (!(attr->name = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + { + heap_free( attr ); + return NULL; + } + memcpy( attr->name, p, len * sizeof(WCHAR) ); + attr->name[len] = 0; + attr->value = NULL; + + p = q; + while (*p == ' ') p++; + if (*p++ == '=') + { + while (*p == ' ') p++; + q = p; + while (*q && *q != ';') q++; + len = q - p; + while (len && p[len - 1] == ' ') len--; + + if (!(attr->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + { + free_attr( attr ); + return NULL; + } + memcpy( attr->value, p, len * sizeof(WCHAR) ); + attr->value[len] = 0; + } + + while (*q == ' ') q++; + if (*q == ';') q++; + *used = q - str; + + return attr; +} + BOOL set_cookies( request_t *request, const WCHAR *cookies ) { static const WCHAR pathW[] = {'p','a','t','h',0}; static const WCHAR domainW[] = {'d','o','m','a','i','n',0}; - BOOL ret = FALSE; - WCHAR *buffer, *p, *q, *r; + WCHAR *buffer, *p; WCHAR *cookie_domain = NULL, *cookie_path = NULL; + struct attr *attr, *domain = NULL, *path = NULL; session_t *session = request->connect->session; cookie_t *cookie; - int len; + int len, used;
len = strlenW( cookies ); if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; @@ -179,32 +241,26 @@ heap_free( buffer ); return FALSE; } - if ((q = strstrW( p, domainW ))) /* FIXME: do real attribute parsing */ - { - while (*q && *q != '=') q++; - if (!*q) goto end; - - r = ++q; - while (*r && *r != ';') r++; - len = r - q; - - if (!(cookie_domain = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; - memcpy( cookie_domain, q, len * sizeof(WCHAR) ); - cookie_domain[len] = 0; - - } - if ((q = strstrW( p, pathW ))) - { - while (*q && *q != '=') q++; - if (!*q) goto end; - - r = ++q; - while (*r && *r != ';') r++; - len = r - q; - - if (!(cookie_path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; - memcpy( cookie_path, q, len * sizeof(WCHAR) ); - cookie_path[len] = 0; + len = strlenW( p ); + while (len && (attr = parse_attr( p, &used ))) + { + if (!strcmpiW( attr->name, domainW )) + { + domain = attr; + cookie_domain = attr->value; + } + else if (!strcmpiW( attr->name, pathW )) + { + path = attr; + cookie_path = attr->value; + } + else + { + FIXME( "unhandled attribute %s\n", debugstr_w(attr->name) ); + free_attr( attr ); + } + len -= used; + p += used; } if (!cookie_domain && !(cookie_domain = strdupW( request->connect->servername ))) goto end; if (!cookie_path && !(cookie_path = strdupW( request->path ))) goto end; @@ -214,8 +270,10 @@
end: if (!ret) free_cookie( cookie ); - heap_free( cookie_domain ); - heap_free( cookie_path ); + if (domain) free_attr( domain ); + else heap_free( cookie_domain ); + if (path) free_attr( path ); + else heap_free( cookie_path ); heap_free( buffer ); return ret; }
Modified: trunk/reactos/dll/win32/winhttp/request.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/winhttp/request.c... ============================================================================== --- trunk/reactos/dll/win32/winhttp/request.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/winhttp/request.c [iso-8859-1] Sun Jun 4 01:48:31 2017 @@ -357,25 +357,21 @@
static BOOL insert_header( request_t *request, header_t *header ) { - DWORD count; + DWORD count = request->num_headers + 1; header_t *hdrs;
- count = request->num_headers + 1; - if (count > 1) + if (request->headers) hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count ); else - hdrs = heap_alloc_zero( sizeof(header_t) * count ); - - if (hdrs) - { - request->headers = hdrs; - request->headers[count - 1].field = strdupW( header->field ); - request->headers[count - 1].value = strdupW( header->value ); - request->headers[count - 1].is_request = header->is_request; - request->num_headers++; - return TRUE; - } - return FALSE; + hdrs = heap_alloc_zero( sizeof(header_t) ); + if (!hdrs) return FALSE; + + request->headers = hdrs; + request->headers[count - 1].field = strdupW( header->field ); + request->headers[count - 1].value = strdupW( header->value ); + request->headers[count - 1].is_request = header->is_request; + request->num_headers = count; + return TRUE; }
static BOOL delete_header( request_t *request, DWORD index ) @@ -1106,6 +1102,205 @@ } }
+/* remove some amount of data from the read buffer */ +static void remove_data( request_t *request, int count ) +{ + if (!(request->read_size -= count)) request->read_pos = 0; + else request->read_pos += count; +} + +/* read some more data into the read buffer */ +static BOOL read_more_data( request_t *request, int maxlen, BOOL notify ) +{ + int len; + BOOL ret; + + if (request->read_chunked_eof) return FALSE; + + if (request->read_size && request->read_pos) + { + /* move existing data to the start of the buffer */ + memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size ); + request->read_pos = 0; + } + if (maxlen == -1) maxlen = sizeof(request->read_buf); + + if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + + ret = netconn_recv( &request->netconn, request->read_buf + request->read_size, + maxlen - request->read_size, 0, &len ); + + if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); + + request->read_size += len; + return ret; +} + +/* discard data contents until we reach end of line */ +static BOOL discard_eol( request_t *request, BOOL notify ) +{ + do + { + char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); + if (eol) + { + remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); + break; + } + request->read_pos = request->read_size = 0; /* discard everything */ + if (!read_more_data( request, -1, notify )) return FALSE; + } while (request->read_size); + return TRUE; +} + +/* read the size of the next chunk */ +static BOOL start_next_chunk( request_t *request, BOOL notify ) +{ + DWORD chunk_size = 0; + + assert(!request->read_chunked_size || request->read_chunked_size == ~0u); + + if (request->read_chunked_eof) return FALSE; + + /* read terminator for the previous chunk */ + if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE; + + for (;;) + { + while (request->read_size) + { + char ch = request->read_buf[request->read_pos]; + if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; + else if (ch == ';' || ch == '\r' || ch == '\n') + { + TRACE("reading %u byte chunk\n", chunk_size); + + if (request->content_length == ~0u) request->content_length = chunk_size; + else request->content_length += chunk_size; + + request->read_chunked_size = chunk_size; + if (!chunk_size) request->read_chunked_eof = TRUE; + + return discard_eol( request, notify ); + } + remove_data( request, 1 ); + } + if (!read_more_data( request, -1, notify )) return FALSE; + if (!request->read_size) + { + request->content_length = request->content_read = 0; + request->read_chunked_size = 0; + return TRUE; + } + } +} + +static BOOL refill_buffer( request_t *request, BOOL notify ) +{ + int len = sizeof(request->read_buf); + + if (request->read_chunked) + { + if (request->read_chunked_eof) return FALSE; + if (request->read_chunked_size == ~0u || !request->read_chunked_size) + { + if (!start_next_chunk( request, notify )) return FALSE; + } + len = min( len, request->read_chunked_size ); + } + else if (request->content_length != ~0u) + { + len = min( len, request->content_length - request->content_read ); + } + + if (len <= request->read_size) return TRUE; + if (!read_more_data( request, len, notify )) return FALSE; + if (!request->read_size) request->content_length = request->content_read = 0; + return TRUE; +} + +static void finished_reading( request_t *request ) +{ + static const WCHAR closeW[] = {'c','l','o','s','e',0}; + + BOOL close = FALSE; + WCHAR connection[20]; + DWORD size = sizeof(connection); + + if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE; + else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) || + query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL )) + { + if (!strcmpiW( connection, closeW )) close = TRUE; + } + else if (!strcmpW( request->version, http1_0 )) close = TRUE; + if (close) close_connection( request ); +} + +/* return the size of data available to be read immediately */ +static DWORD get_available_data( request_t *request ) +{ + if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); + return request->read_size; +} + +/* check if we have reached the end of the data to read */ +static BOOL end_of_read_data( request_t *request ) +{ + if (!request->content_length) return TRUE; + if (request->read_chunked) return request->read_chunked_eof; + if (request->content_length == ~0u) return FALSE; + return (request->content_length == request->content_read); +} + +static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) +{ + int count, bytes_read = 0; + + if (end_of_read_data( request )) goto done; + + while (size) + { + if (!(count = get_available_data( request ))) + { + if (!refill_buffer( request, async )) goto done; + if (!(count = get_available_data( request ))) goto done; + } + count = min( count, size ); + memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count ); + remove_data( request, count ); + if (request->read_chunked) request->read_chunked_size -= count; + size -= count; + bytes_read += count; + request->content_read += count; + if (end_of_read_data( request )) goto done; + } + if (request->read_chunked && !request->read_chunked_size) refill_buffer( request, async ); + +done: + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length ); + + if (async) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); + if (read) *read = bytes_read; + if (end_of_read_data( request )) finished_reading( request ); + return TRUE; +} + +/* read any content returned by the server so that the connection can be reused */ +static void drain_content( request_t *request ) +{ + DWORD bytes_read; + char buffer[2048]; + + refill_buffer( request, FALSE ); + for (;;) + { + if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return; + } +} + static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) { @@ -1122,6 +1317,7 @@ DWORD len;
clear_response_headers( request ); + drain_content( request );
if (session->agent) process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); @@ -1300,7 +1496,7 @@
static BOOL query_auth_schemes( request_t *request, DWORD level, LPDWORD supported, LPDWORD first ) { - DWORD index = 0; + DWORD index = 0, supported_schemes = 0, first_scheme = 0; BOOL ret = FALSE;
for (;;) @@ -1321,14 +1517,18 @@ } scheme = auth_scheme_from_header( buffer ); heap_free( buffer ); - if (!scheme) break; - - if (first && index == 1) - *first = *supported = scheme; - else - *supported |= scheme; + if (!scheme) continue; + + if (!first_scheme) first_scheme = scheme; + supported_schemes |= scheme;
ret = TRUE; + } + + if (ret) + { + *supported = supported_schemes; + *first = first_scheme; } return ret; } @@ -1894,40 +2094,6 @@ return request->content_length; }
-/* read some more data into the read buffer */ -static BOOL read_more_data( request_t *request, int maxlen, BOOL notify ) -{ - int len; - BOOL ret; - - if (request->read_chunked_eof) return FALSE; - - if (request->read_size && request->read_pos) - { - /* move existing data to the start of the buffer */ - memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size ); - request->read_pos = 0; - } - if (maxlen == -1) maxlen = sizeof(request->read_buf); - - if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); - - ret = netconn_recv( &request->netconn, request->read_buf + request->read_size, - maxlen - request->read_size, 0, &len ); - - if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); - - request->read_size += len; - return ret; -} - -/* remove some amount of data from the read buffer */ -static void remove_data( request_t *request, int count ) -{ - if (!(request->read_size -= count)) request->read_pos = 0; - else request->read_pos += count; -} - static BOOL read_line( request_t *request, char *buffer, DWORD *len ) { int count, bytes_read, pos = 0; @@ -1963,107 +2129,6 @@ } buffer[*len - 1] = 0; TRACE("returning %s\n", debugstr_a(buffer)); - return TRUE; -} - -/* discard data contents until we reach end of line */ -static BOOL discard_eol( request_t *request, BOOL notify ) -{ - do - { - char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); - if (eol) - { - remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); - break; - } - request->read_pos = request->read_size = 0; /* discard everything */ - if (!read_more_data( request, -1, notify )) return FALSE; - } while (request->read_size); - return TRUE; -} - -/* read the size of the next chunk */ -static BOOL start_next_chunk( request_t *request, BOOL notify ) -{ - DWORD chunk_size = 0; - - assert(!request->read_chunked_size || request->read_chunked_size == ~0u); - - if (request->read_chunked_eof) return FALSE; - - /* read terminator for the previous chunk */ - if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE; - - for (;;) - { - while (request->read_size) - { - char ch = request->read_buf[request->read_pos]; - if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; - else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; - else if (ch == ';' || ch == '\r' || ch == '\n') - { - TRACE("reading %u byte chunk\n", chunk_size); - - if (request->content_length == ~0u) request->content_length = chunk_size; - else request->content_length += chunk_size; - - request->read_chunked_size = chunk_size; - if (!chunk_size) request->read_chunked_eof = TRUE; - - return discard_eol( request, notify ); - } - remove_data( request, 1 ); - } - if (!read_more_data( request, -1, notify )) return FALSE; - if (!request->read_size) - { - request->content_length = request->content_read = 0; - request->read_chunked_size = 0; - return TRUE; - } - } -} - -/* return the size of data available to be read immediately */ -static DWORD get_available_data( request_t *request ) -{ - if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); - return request->read_size; -} - -/* check if we have reached the end of the data to read */ -static BOOL end_of_read_data( request_t *request ) -{ - if (!request->content_length) return TRUE; - if (request->read_chunked) return request->read_chunked_eof; - if (request->content_length == ~0u) return FALSE; - return (request->content_length == request->content_read); -} - -static BOOL refill_buffer( request_t *request, BOOL notify ) -{ - int len = sizeof(request->read_buf); - - if (request->read_chunked) - { - if (request->read_chunked_eof) return FALSE; - if (request->read_chunked_size == ~0u || !request->read_chunked_size) - { - if (!start_next_chunk( request, notify )) return FALSE; - } - len = min( len, request->read_chunked_size ); - } - else if (request->content_length != ~0u) - { - len = min( len, request->content_length - request->content_read ); - } - - if (len <= request->read_size) return TRUE; - if (!read_more_data( request, len, notify )) return FALSE; - if (!request->read_size) request->content_length = request->content_read = 0; return TRUE; }
@@ -2167,70 +2232,6 @@
TRACE("raw headers: %s\n", debugstr_w(raw_headers)); return TRUE; -} - -static void finished_reading( request_t *request ) -{ - static const WCHAR closeW[] = {'c','l','o','s','e',0}; - - BOOL close = FALSE; - WCHAR connection[20]; - DWORD size = sizeof(connection); - - if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE; - else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) || - query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL )) - { - if (!strcmpiW( connection, closeW )) close = TRUE; - } - else if (!strcmpW( request->version, http1_0 )) close = TRUE; - if (close) close_connection( request ); -} - -static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) -{ - int count, bytes_read = 0; - - if (end_of_read_data( request )) goto done; - - while (size) - { - if (!(count = get_available_data( request ))) - { - if (!refill_buffer( request, async )) goto done; - if (!(count = get_available_data( request ))) goto done; - } - count = min( count, size ); - memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count ); - remove_data( request, count ); - if (request->read_chunked) request->read_chunked_size -= count; - size -= count; - bytes_read += count; - request->content_read += count; - if (end_of_read_data( request )) goto done; - } - if (request->read_chunked && !request->read_chunked_size) refill_buffer( request, async ); - -done: - TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length ); - - if (async) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); - if (read) *read = bytes_read; - if (end_of_read_data( request )) finished_reading( request ); - return TRUE; -} - -/* read any content returned by the server so that the connection can be reused */ -static void drain_content( request_t *request ) -{ - DWORD bytes_read; - char buffer[2048]; - - refill_buffer( request, FALSE ); - for (;;) - { - if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return; - } }
static void record_cookies( request_t *request ) @@ -2299,7 +2300,6 @@ heap_free( request->path ); request->path = path;
- drain_content( request ); send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_url + 1 ); } else @@ -2316,7 +2316,6 @@ request->hdr.flags |= WINHTTP_FLAG_SECURE; }
- drain_content( request ); send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_url + 1 );
len = uc.dwHostNameLength; @@ -2407,7 +2406,6 @@ if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break;
if (!handle_authorization( request, status )) break; - drain_content( request );
/* recurse synchronously */ if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue;
Modified: trunk/reactos/media/doc/README.WINE URL: http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=7... ============================================================================== --- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original) +++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Sun Jun 4 01:48:31 2017 @@ -200,7 +200,7 @@ reactos/dll/win32/windowscodecsext # Synced to WineStaging-1.9.11 reactos/dll/win32/winemp3.acm # Synced to WineStaging-2.2 reactos/dll/win32/wing32 # Synced to WineStaging-1.9.11 -reactos/dll/win32/winhttp # Synced to WineStaging-2.2 +reactos/dll/win32/winhttp # Synced to WineStaging-2.9 reactos/dll/win32/wininet # Synced to WineStaging-2.2 reactos/dll/win32/winmm # Forked at Wine-20050628 reactos/dll/win32/winmm/midimap # Forked at Wine-20050628