From 2516fb7807453df39448a14995d349641cdb6894 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 24 Jun 2015 14:16:59 +0200 Subject: [PATCH] winhttp: Fix a couple of corner cases in header processing. --- dlls/winhttp/request.c | 98 ++++++++++++++++-------------------- dlls/winhttp/tests/winhttp.c | 61 +++++++++++++++++++++- 2 files changed, 103 insertions(+), 56 deletions(-) diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index bdcbb96e490..aa8a6f96cb4 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -327,12 +327,8 @@ static header_t *parse_header( LPCWSTR string ) q++; /* skip past colon */ while (*q == ' ') q++; - if (!*q) - { - WARN("no value in line %s\n", debugstr_w(string)); - return header; - } len = strlenW( q ); + if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) { free_header( header ); @@ -404,76 +400,65 @@ static BOOL delete_header( request_t *request, DWORD index ) static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only ) { int index; - header_t *header; + header_t hdr; TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags); - /* replace wins out over add */ - if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) flags &= ~WINHTTP_ADDREQ_FLAG_ADD; - - if (flags & WINHTTP_ADDREQ_FLAG_ADD) index = -1; - else - index = get_header_index( request, field, 0, request_only ); - - if (index >= 0) + if ((index = get_header_index( request, field, 0, request_only )) >= 0) { if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE; - header = &request->headers[index]; } - else if (value) + + if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) { - header_t hdr; + if (index >= 0) + { + delete_header( request, index ); + if (!value || !value[0]) return TRUE; + } + else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD)) + { + set_last_error( ERROR_WINHTTP_HEADER_NOT_FOUND ); + return FALSE; + } hdr.field = (LPWSTR)field; hdr.value = (LPWSTR)value; hdr.is_request = request_only; - return insert_header( request, &hdr ); } - /* no value to delete */ - else return TRUE; - - if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) + else if (value) { - delete_header( request, index ); - if (value) + + if ((flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON)) && + index >= 0) { - header_t hdr; + WCHAR *tmp; + int len, len_orig, len_value; + header_t *header = &request->headers[index]; - hdr.field = (LPWSTR)field; - hdr.value = (LPWSTR)value; - hdr.is_request = request_only; + len_orig = strlenW( header->value ); + len_value = strlenW( value ); - return insert_header( request, &hdr ); - } - return TRUE; - } - else if (flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON)) - { - WCHAR sep, *tmp; - int len, orig_len, value_len; - - orig_len = strlenW( header->value ); - value_len = strlenW( value ); - - if (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) sep = ','; - else sep = ';'; - - len = orig_len + value_len + 2; - if ((tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) - { + len = len_orig + len_value + 2; + if (!(tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return FALSE; header->value = tmp; + header->value[len_orig++] = (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) ? ',' : ';'; + header->value[len_orig++] = ' '; - header->value[orig_len] = sep; - orig_len++; - header->value[orig_len] = ' '; - orig_len++; - - memcpy( &header->value[orig_len], value, value_len * sizeof(WCHAR) ); + memcpy( &header->value[len_orig], value, len_value * sizeof(WCHAR) ); header->value[len] = 0; return TRUE; } + else + { + hdr.field = (LPWSTR)field; + hdr.value = (LPWSTR)value; + hdr.is_request = request_only; + return insert_header( request, &hdr ); + } } + return TRUE; } @@ -2128,7 +2113,9 @@ static BOOL read_reply( request_t *request ) /* we rely on the fact that the protocol is ascii */ MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len ); status_codeW[len] = 0; - if (!(process_header( request, attr_status, status_codeW, WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) return FALSE; + if (!(process_header( request, attr_status, status_codeW, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) + return FALSE; len = status_code - buffer; if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; @@ -2358,7 +2345,7 @@ static BOOL handle_redirect( request_t *request, DWORD status ) } else heap_free( hostname ); - if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; + if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; if (!(ret = open_connection( request ))) goto end; heap_free( request->path ); @@ -3227,7 +3214,8 @@ static HRESULT WINAPI winhttp_request_SetRequestHeader( goto done; } sprintfW( str, fmtW, header, value ? value : emptyW ); - if (!WinHttpAddRequestHeaders( request->hrequest, str, len, WINHTTP_ADDREQ_FLAG_REPLACE )) + if (!WinHttpAddRequestHeaders( request->hrequest, str, len, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) { err = get_last_error(); } diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index d808ff60772..30115ef4c7b 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -420,6 +420,8 @@ static void test_WinHttpAddHeaders(void) {'P','O','S','T',' ','h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',':','8','0','/','p','o','s','t','.','p','h','p',' ','H','T','T','P','/','1'}; static const WCHAR test_header_end[] = {'\r','\n','\r','\n',0}; static const WCHAR test_header_name[] = {'W','a','r','n','i','n','g',0}; + static const WCHAR test_header_name2[] = {'n','a','m','e',0}; + static const WCHAR test_header_name3[] = {'a',0}; static const WCHAR test_header_range[] = {'R','a','n','g','e',0}; static const WCHAR test_header_range_bytes[] = {'R','a','n','g','e',':',' ','b','y','t','e','s','=','0','-','7','7','3','\r','\n',0}; static const WCHAR test_header_bytes[] = {'b','y','t','e','s','=','0','-','7','7','3',0}; @@ -438,6 +440,7 @@ static void test_WinHttpAddHeaders(void) static const WCHAR field[] = {'f','i','e','l','d',0}; static const WCHAR value[] = {'v','a','l','u','e',' ',0}; static const WCHAR value_nospace[] = {'v','a','l','u','e',0}; + static const WCHAR empty[] = {0}; static const WCHAR test_headers[][14] = { @@ -454,7 +457,9 @@ static void test_WinHttpAddHeaders(void) {':','b',0}, {'c','d',0}, {' ','e',' ',':','f',0}, - {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0} + {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0}, + {'n','a','m','e',':',' ','v','a','l','u','e',0}, + {'n','a','m','e',':',0} }; static const WCHAR test_indices[][6] = { @@ -763,6 +768,14 @@ static void test_WinHttpAddHeaders(void) ret = WinHttpAddRequestHeaders(request, test_headers[9], ~0u, WINHTTP_ADDREQ_FLAG_ADD); ok(ret, "WinHttpAddRequestHeaders failed\n"); + index = 0; + memset(buffer, 0xff, sizeof(buffer)); + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name3, buffer, &len, &index); + ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(!memcmp(buffer, empty, sizeof(empty)), "unexpected result\n"); + ret = WinHttpAddRequestHeaders(request, test_headers[10], ~0u, WINHTTP_ADDREQ_FLAG_ADD); ok(!ret, "WinHttpAddRequestHeaders failed\n"); @@ -803,6 +816,52 @@ static void test_WinHttpAddHeaders(void) ok(len == lstrlenW(test_header_bytes) * sizeof(WCHAR), "wrong length %u\n", len); ok(index == 1, "wrong index %u\n", index); + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name2, buffer, &len, &index); + ok(!ret, "unexpected success\n"); + + SetLastError(0xdeadbeef); + ret = WinHttpAddRequestHeaders(request, test_headers[14], ~0u, WINHTTP_ADDREQ_FLAG_REPLACE); + err = GetLastError(); + ok(!ret, "unexpected success\n"); + ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", err); + + ret = WinHttpAddRequestHeaders(request, test_headers[14], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "got %u\n", GetLastError()); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name2, buffer, &len, &index); + ok(ret, "got %u\n", GetLastError()); + ok(index == 1, "wrong index %u\n", index); + ok(!memcmp(buffer, value_nospace, sizeof(value_nospace)), "incorrect string\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[15], ~0u, WINHTTP_ADDREQ_FLAG_REPLACE); + ok(ret, "got %u\n", GetLastError()); + + index = 0; + len = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name2, buffer, &len, &index); + err = GetLastError(); + ok(!ret, "unexpected success\n"); + ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", err); + + ret = WinHttpAddRequestHeaders(request, test_headers[14], -1L, 0); + ok(ret, "got %u\n", GetLastError()); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name2, buffer, &len, &index); + ok(ret, "got %u\n", GetLastError()); + ok(index == 1, "wrong index %u\n", index); + ok(!memcmp(buffer, value_nospace, sizeof(value_nospace)), "incorrect string\n"); + ret = WinHttpCloseHandle(request); ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); done: