From 462f56d468984d2d2a3bf3ae21771b64c206eec1 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Thu, 25 Sep 2014 14:21:37 +0200 Subject: [PATCH] wininet: Protect the request headers array with a critical section. --- dlls/wininet/http.c | 181 ++++++++++++++++++++++++++++++++++++++-------- dlls/wininet/internet.h | 3 + dlls/wininet/tests/http.c | 50 +++++++++++++ 3 files changed, 205 insertions(+), 29 deletions(-) diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 2486fbffa01..40f8d9a17ea 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -369,6 +369,11 @@ static DWORD WINAPI collect_connections_proc(void *arg) FreeLibraryAndExitThread(WININET_hModule, 0); } +/*********************************************************************** + * HTTP_GetHeader (internal) + * + * Headers section must be held + */ static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) { int HeaderIndex = 0; @@ -379,6 +384,17 @@ static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) return &req->custHeaders[HeaderIndex]; } +static WCHAR *get_host_header( http_request_t *req ) +{ + HTTPHEADERW *header; + WCHAR *ret = NULL; + + EnterCriticalSection( &req->headers_section ); + if ((header = HTTP_GetHeader( req, hostW ))) ret = heap_strdupW( header->lpszValue ); + LeaveCriticalSection( &req->headers_section ); + return ret; +} + struct data_stream_vtbl_t { DWORD (*get_avail_data)(data_stream_t*,http_request_t*); BOOL (*end_of_data)(data_stream_t*,http_request_t*); @@ -553,9 +569,11 @@ static DWORD init_gzip_stream(http_request_t *req, BOOL is_gzip) return ERROR_OUTOFMEMORY; } + EnterCriticalSection( &req->headers_section ); index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE); if(index != -1) HTTP_DeleteCustomHeader(req, index); + LeaveCriticalSection( &req->headers_section ); if(req->read_size) { memcpy(gzip_stream->buf, req->read_buf+req->read_pos, req->read_size); @@ -629,19 +647,24 @@ static void HTTP_FixURL(http_request_t *request) static WCHAR* build_request_header(http_request_t *request, const WCHAR *verb, const WCHAR *path, const WCHAR *version, BOOL use_cr) { + static const WCHAR szSpace[] = {' ',0}; + static const WCHAR szColon[] = {':',' ',0}; + static const WCHAR szCr[] = {'\r',0}; + static const WCHAR szLf[] = {'\n',0}; LPWSTR requestString; DWORD len, n; LPCWSTR *req; UINT i; - static const WCHAR szSpace[] = { ' ',0 }; - static const WCHAR szColon[] = { ':',' ',0 }; - static const WCHAR szCr[] = { '\r',0 }; - static const WCHAR szLf[] = { '\n',0 }; + EnterCriticalSection( &request->headers_section ); /* allocate space for an array of all the string pointers to be added */ - len = (request->nCustHeaders)*5 + 10; - req = heap_alloc(len*sizeof(LPCWSTR)); + len = request->nCustHeaders * 5 + 10; + if (!(req = heap_alloc( len * sizeof(const WCHAR *) ))) + { + LeaveCriticalSection( &request->headers_section ); + return NULL; + } /* add the verb, path and HTTP version string */ n = 0; @@ -678,6 +701,7 @@ static WCHAR* build_request_header(http_request_t *request, const WCHAR *verb, requestString = HTTP_build_req( req, 4 ); heap_free( req ); + LeaveCriticalSection( &request->headers_section ); return requestString; } @@ -687,14 +711,17 @@ static WCHAR* build_response_header(http_request_t *request, BOOL use_cr) static const WCHAR crW[] = { '\r',0 }; static const WCHAR lfW[] = { '\n',0 }; static const WCHAR status_fmt[] = { ' ','%','u',' ',0 }; - const WCHAR **req; WCHAR *ret, buf[14]; DWORD i, n = 0; - req = heap_alloc((request->nCustHeaders*5+8)*sizeof(WCHAR*)); - if(!req) + EnterCriticalSection( &request->headers_section ); + + if (!(req = heap_alloc( (request->nCustHeaders * 5 + 8) * sizeof(WCHAR *) ))) + { + LeaveCriticalSection( &request->headers_section ); return NULL; + } if (request->status_code) { @@ -731,6 +758,7 @@ static WCHAR* build_response_header(http_request_t *request, BOOL use_cr) ret = HTTP_build_req(req, 0); heap_free(req); + LeaveCriticalSection( &request->headers_section ); return ret; } @@ -743,6 +771,8 @@ static void HTTP_ProcessCookies( http_request_t *request ) if(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) return; + EnterCriticalSection( &request->headers_section ); + while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, szSet_Cookie, numCookies++, FALSE)) != -1) { HTTPHEADERW *host; @@ -770,6 +800,8 @@ static void HTTP_ProcessCookies( http_request_t *request ) set_cookie(host->lpszValue, request->path, name, data, INTERNET_COOKIE_HTTPONLY); heap_free(name); } + + LeaveCriticalSection( &request->headers_section ); } static void strip_spaces(LPWSTR start) @@ -1878,6 +1910,8 @@ static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) if(!host_header) return FALSE; + EnterCriticalSection( &req->headers_section ); + if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) scheme = https; else @@ -1887,6 +1921,8 @@ static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) if (req->path[0] != '/') strcatW(buf, slash); strcatW(buf, req->path); + + LeaveCriticalSection( &req->headers_section ); return TRUE; } @@ -1909,6 +1945,8 @@ static void HTTPREQ_Destroy(object_header_t *hdr) if(request->req_file) req_file_release(request->req_file); + request->headers_section.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &request->headers_section ); request->read_section.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &request->read_section ); WININET_Release(&request->session->hdr); @@ -2118,17 +2156,18 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe return ERROR_SUCCESS; case INTERNET_OPTION_URL: { + static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; WCHAR url[INTERNET_MAX_URL_LENGTH]; HTTPHEADERW *host; - static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; - TRACE("INTERNET_OPTION_URL\n"); + EnterCriticalSection( &req->headers_section ); host = HTTP_GetHeader(req, hostW); strcpyW(url, httpW); strcatW(url, host->lpszValue); strcatW(url, req->path); + LeaveCriticalSection( &req->headers_section ); TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url)); return str_to_buffer(url, buffer, size, unicode); @@ -2404,7 +2443,11 @@ static void create_cache_entry(http_request_t *req) b = FALSE; if(b) { - int header_idx = HTTP_GetCustomHeaderIndex(req, szCache_Control, 0, FALSE); + int header_idx; + + EnterCriticalSection( &req->headers_section ); + + header_idx = HTTP_GetCustomHeaderIndex(req, szCache_Control, 0, FALSE); if(header_idx != -1) { WCHAR *ptr; @@ -2429,6 +2472,8 @@ static void create_cache_entry(http_request_t *req) ptr++; } } + + LeaveCriticalSection( &req->headers_section ); } if(!b) { @@ -2929,17 +2974,23 @@ static DWORD set_content_length(http_request_t *request) static const WCHAR deflateW[] = {'d','e','f','l','a','t','e',0}; static const WCHAR gzipW[] = {'g','z','i','p',0}; + EnterCriticalSection( &request->headers_section ); + encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE); if(encoding_idx != -1) { if(!strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) { HTTP_DeleteCustomHeader(request, encoding_idx); + LeaveCriticalSection( &request->headers_section ); return init_gzip_stream(request, TRUE); } if(!strcmpiW(request->custHeaders[encoding_idx].lpszValue, deflateW)) { HTTP_DeleteCustomHeader(request, encoding_idx); + LeaveCriticalSection( &request->headers_section ); return init_gzip_stream(request, FALSE); } } + + LeaveCriticalSection( &request->headers_section ); } return ERROR_SUCCESS; @@ -3309,6 +3360,9 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session, request->send_timeout = session->send_timeout; request->receive_timeout = session->receive_timeout; + InitializeCriticalSection( &request->headers_section ); + request->headers_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.headers_section"); + InitializeCriticalSection( &request->read_section ); request->read_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.read_section"); @@ -3526,11 +3580,17 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); INT index = -1; + EnterCriticalSection( &request->headers_section ); + /* Find requested header structure */ switch (level) { case HTTP_QUERY_CUSTOM: - if (!lpBuffer) return ERROR_INVALID_PARAMETER; + if (!lpBuffer) + { + LeaveCriticalSection( &request->headers_section ); + return ERROR_INVALID_PARAMETER; + } index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only); break; case HTTP_QUERY_RAW_HEADERS_CRLF: @@ -3544,7 +3604,10 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, else headers = build_response_header(request, TRUE); if (!headers) + { + LeaveCriticalSection( &request->headers_section ); return ERROR_OUTOFMEMORY; + } len = strlenW(headers) * sizeof(WCHAR); if (len + sizeof(WCHAR) > *lpdwBufferLength) @@ -3561,6 +3624,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, *lpdwBufferLength = len; heap_free(headers); + LeaveCriticalSection( &request->headers_section ); return res; } case HTTP_QUERY_RAW_HEADERS: @@ -3572,14 +3636,19 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, headers = build_request_header(request, request->verb, request->path, request->version, FALSE); else headers = build_response_header(request, FALSE); + if (!headers) + { + LeaveCriticalSection( &request->headers_section ); return ERROR_OUTOFMEMORY; + } len = strlenW(headers) * sizeof(WCHAR); if (len > *lpdwBufferLength) { *lpdwBufferLength = len; heap_free(headers); + LeaveCriticalSection( &request->headers_section ); return ERROR_INSUFFICIENT_BUFFER; } @@ -3599,6 +3668,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, *lpdwBufferLength = len - sizeof(WCHAR); heap_free(headers); + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } case HTTP_QUERY_STATUS_TEXT: @@ -3608,6 +3678,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); + LeaveCriticalSection( &request->headers_section ); return ERROR_INSUFFICIENT_BUFFER; } if (lpBuffer) @@ -3616,6 +3687,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } *lpdwBufferLength = len * sizeof(WCHAR); + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } break; @@ -3626,6 +3698,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); + LeaveCriticalSection( &request->headers_section ); return ERROR_INSUFFICIENT_BUFFER; } if (lpBuffer) @@ -3634,6 +3707,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } *lpdwBufferLength = len * sizeof(WCHAR); + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } break; @@ -3645,7 +3719,10 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, DWORD res = ERROR_SUCCESS; if(request_only) + { + LeaveCriticalSection( &request->headers_section ); return ERROR_HTTP_INVALID_QUERY_REQUEST; + } if(requested_index) break; @@ -3672,6 +3749,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, *lpdwBufferLength = size; } + LeaveCriticalSection( &request->headers_section ); return res; } default: @@ -3690,6 +3768,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && (~lphttpHdr->wFlags & HDR_ISREQUEST))) { + LeaveCriticalSection( &request->headers_section ); return ERROR_HTTP_HEADER_NOT_FOUND; } @@ -3729,6 +3808,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, if (len > *lpdwBufferLength) { *lpdwBufferLength = len; + LeaveCriticalSection( &request->headers_section ); return ERROR_INSUFFICIENT_BUFFER; } if (lpBuffer) @@ -3739,6 +3819,8 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, *lpdwBufferLength = len - sizeof(WCHAR); } if (lpdwIndex) (*lpdwIndex)++; + + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } @@ -4140,13 +4222,15 @@ static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl) } } + EnterCriticalSection( &request->headers_section ); + /* Remove custom content-type/length headers on redirects. */ index = HTTP_GetCustomHeaderIndex(request, szContent_Type, 0, TRUE); - if (0 <= index) - HTTP_DeleteCustomHeader(request, index); + if (index != -1) HTTP_DeleteCustomHeader(request, index); index = HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE); - if (0 <= index) - HTTP_DeleteCustomHeader(request, index); + if (index != -1) HTTP_DeleteCustomHeader(request, index); + + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } @@ -4604,6 +4688,8 @@ static void HTTP_ProcessExpires(http_request_t *request) BOOL expirationFound = FALSE; int headerIndex; + EnterCriticalSection( &request->headers_section ); + /* Look for a Cache-Control header with a max-age directive, as it takes * precedence over the Expires header. */ @@ -4684,12 +4770,16 @@ static void HTTP_ProcessExpires(http_request_t *request) request->expires.dwLowDateTime = t.u.LowPart; request->expires.dwHighDateTime = t.u.HighPart; } + + LeaveCriticalSection( &request->headers_section ); } static void HTTP_ProcessLastModified(http_request_t *request) { int headerIndex; + EnterCriticalSection( &request->headers_section ); + headerIndex = HTTP_GetCustomHeaderIndex(request, szLast_Modified, 0, FALSE); if (headerIndex != -1) { @@ -4699,18 +4789,24 @@ static void HTTP_ProcessLastModified(http_request_t *request) if (HTTP_ParseDate(expiresHeader->lpszValue, &ft)) request->last_modified = ft; } + + LeaveCriticalSection( &request->headers_section ); } static void http_process_keep_alive(http_request_t *req) { int index; + EnterCriticalSection( &req->headers_section ); + if ((index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE)) != -1) req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); else if ((index = HTTP_GetCustomHeaderIndex(req, szProxy_Connection, 0, FALSE)) != -1) req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); else req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1); + + LeaveCriticalSection( &req->headers_section ); } static DWORD open_http_connection(http_request_t *request, BOOL *reusing) @@ -4882,8 +4978,12 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, if (TRACE_ON(wininet)) { - LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW); - TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(request->path)); + HTTPHEADERW *host; + + EnterCriticalSection( &request->headers_section ); + host = HTTP_GetHeader( request, hostW ); + TRACE("Going to url %s %s\n", debugstr_w(host->lpszValue), debugstr_w(request->path)); + LeaveCriticalSection( &request->headers_section ); } HTTP_FixURL(request); @@ -5037,15 +5137,14 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, dwBufferSize=2048; if (request->status_code == HTTP_STATUS_DENIED) { - LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW); + WCHAR *host = get_host_header( request ); DWORD dwIndex = 0; while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(request, szAuthValue, &request->authInfo, request->session->userName, - request->session->password, - Host->lpszValue)) + request->session->password, host)) { heap_free(requestString); if(!drain_content(request, TRUE)) { @@ -5056,6 +5155,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, break; } } + heap_free( host ); if(!loop_next) { TRACE("Cleaning wrong authorization data\n"); @@ -5102,8 +5202,11 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, http_release_netconn( request, FALSE ); break; } + EnterCriticalSection( &request->headers_section ); index = HTTP_GetCustomHeaderIndex(request, szProxy_Authorization, 0, TRUE); if (index != -1) HTTP_DeleteCustomHeader(request, index); + LeaveCriticalSection( &request->headers_section ); + destroy_authinfo(request->proxyAuthInfo); request->proxyAuthInfo = NULL; @@ -5812,6 +5915,8 @@ static void HTTP_clear_response_headers( http_request_t *request ) { DWORD i; + EnterCriticalSection( &request->headers_section ); + for( i=0; inCustHeaders; i++) { if( !request->custHeaders[i].lpszField ) @@ -5823,6 +5928,8 @@ static void HTTP_clear_response_headers( http_request_t *request ) HTTP_DeleteCustomHeader( request, i ); i--; } + + LeaveCriticalSection( &request->headers_section ); } /*********************************************************************** @@ -6023,12 +6130,14 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier) { LPHTTPHEADERW lphttpHdr = NULL; - INT index = -1; + INT index; BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ; DWORD res = ERROR_HTTP_INVALID_HEADER; TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); + EnterCriticalSection( &request->headers_section ); + /* REPLACE wins out over ADD */ if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) dwModifier &= ~HTTP_ADDHDR_FLAG_ADD; @@ -6041,7 +6150,10 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR if (index >= 0) { if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) + { + LeaveCriticalSection( &request->headers_section ); return ERROR_HTTP_INVALID_HEADER; + } lphttpHdr = &request->custHeaders[index]; } else if (value) @@ -6055,10 +6167,16 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR if (dwModifier & HTTP_ADDHDR_FLAG_REQ) hdr.wFlags |= HDR_ISREQUEST; - return HTTP_InsertCustomHeader(request, &hdr); + res = HTTP_InsertCustomHeader(request, &hdr); + LeaveCriticalSection( &request->headers_section ); + return res; } /* no value to delete */ - else return ERROR_SUCCESS; + else + { + LeaveCriticalSection( &request->headers_section ); + return ERROR_SUCCESS; + } if (dwModifier & HTTP_ADDHDR_FLAG_REQ) lphttpHdr->wFlags |= HDR_ISREQUEST; @@ -6080,9 +6198,12 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR if (dwModifier & HTTP_ADDHDR_FLAG_REQ) hdr.wFlags |= HDR_ISREQUEST; - return HTTP_InsertCustomHeader(request, &hdr); + res = HTTP_InsertCustomHeader(request, &hdr); + LeaveCriticalSection( &request->headers_section ); + return res; } + LeaveCriticalSection( &request->headers_section ); return ERROR_SUCCESS; } else if (dwModifier & COALESCEFLAGS) @@ -6130,6 +6251,7 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR } } TRACE("<-- %d\n", res); + LeaveCriticalSection( &request->headers_section ); return res; } @@ -6137,7 +6259,7 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR * HTTP_GetCustomHeaderIndex (internal) * * Return index of custom header from header array - * + * Headers section must be held */ static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField, int requested_index, BOOL request_only) @@ -6174,7 +6296,7 @@ static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField, * HTTP_InsertCustomHeader (internal) * * Insert header into array - * + * Headers section must be held */ static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHdr) { @@ -6206,7 +6328,8 @@ static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHd * HTTP_DeleteCustomHeader (internal) * * Delete header from array - * If this function is called, the indexs may change. + * If this function is called, the index may change. + * Headers section must be held */ static BOOL HTTP_DeleteCustomHeader(http_request_t *request, DWORD index) { diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 54f688d3d6f..49f7bf50a27 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -364,8 +364,11 @@ typedef struct LPWSTR statusText; DWORD bytesToWrite; DWORD bytesWritten; + + CRITICAL_SECTION headers_section; /* section to protect the headers array */ HTTPHEADERW *custHeaders; DWORD nCustHeaders; + FILETIME last_modified; HANDLE hCacheFile; req_file_t *req_file; diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index e7c3e1798ec..ca5f4affdf5 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -5475,6 +5475,55 @@ static void init_status_tests(void) #undef STATUS_STRING } +static void WINAPI header_cb( HINTERNET handle, DWORD_PTR ctx, DWORD status, LPVOID info, DWORD len ) +{ + if (status == INTERNET_STATUS_REQUEST_COMPLETE) SetEvent( (HANDLE)ctx ); +} + +static void test_concurrent_header_access(void) +{ + HINTERNET ses, con, req; + DWORD index, len, err; + BOOL ret; + char buf[128]; + HANDLE wait = CreateEventW( NULL, FALSE, FALSE, NULL ); + + ses = InternetOpenA( "winetest", 0, NULL, NULL, INTERNET_FLAG_ASYNC ); + ok( ses != NULL, "InternetOpenA failed\n" ); + + con = InternetConnectA( ses, "test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, 0 ); + ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() ); + + req = HttpOpenRequestA( con, NULL, "/", NULL, NULL, NULL, 0, (DWORD_PTR)wait ); + ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() ); + + pInternetSetStatusCallbackA( req, header_cb ); + + SetLastError( 0xdeadbeef ); + ret = HttpSendRequestA( req, NULL, 0, NULL, 0 ); + err = GetLastError(); + ok( !ret, "HttpSendRequestA succeeded\n" ); + ok( err == ERROR_IO_PENDING, "got %u\n", ERROR_IO_PENDING ); + + ret = HttpAddRequestHeadersA( req, "winetest: winetest", ~0u, HTTP_ADDREQ_FLAG_ADD ); + ok( ret, "HttpAddRequestHeadersA failed %u\n", GetLastError() ); + + index = 0; + len = sizeof(buf); + ret = HttpQueryInfoA( req, HTTP_QUERY_RAW_HEADERS_CRLF|HTTP_QUERY_FLAG_REQUEST_HEADERS, + buf, &len, &index ); + ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() ); + ok( strstr( buf, "winetest: winetest" ) != NULL, "header missing\n" ); + + WaitForSingleObject( wait, 5000 ); + + InternetCloseHandle( req ); + InternetCloseHandle( con ); + InternetCloseHandle( ses ); + CloseHandle( wait ); +} + START_TEST(http) { HMODULE hdll; @@ -5517,4 +5566,5 @@ START_TEST(http) InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[3]); test_connection_failure(); test_default_service_port(); + test_concurrent_header_access(); } -- 2.11.4.GIT