[PATCH v3 1/3] wininet: Return error from HttpQueryInfo if number argument is invalid.
Daniel Lehman
dlehman25 at gmail.com
Tue Sep 3 20:41:32 CDT 2019
Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
v3:
- more tests
- check errno
v2:
- just use strtoulW with overflow check
- make this patch first since it's really 0003 that needs it
---
dlls/wininet/http.c | 22 +++++++++--
dlls/wininet/tests/http.c | 82 +++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 538fc2bf6b..3230749d40 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -42,6 +42,7 @@
#include <stdio.h>
#include <time.h>
#include <assert.h>
+#include <errno.h>
#include "windef.h"
#include "winbase.h"
@@ -3724,9 +3725,24 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
/* coalesce value to requested type */
if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
{
- *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
- TRACE(" returning number: %d\n", *(int *)lpBuffer);
- }
+ unsigned long value;
+
+ if (*lpdwBufferLength != sizeof(DWORD))
+ {
+ LeaveCriticalSection( &request->headers_section );
+ return ERROR_HTTP_INVALID_HEADER;
+ }
+
+ value = strtoulW( lphttpHdr->lpszValue, NULL, 10 );
+ if (value > UINT_MAX || (value == ULONG_MAX && errno == ERANGE))
+ {
+ LeaveCriticalSection( &request->headers_section );
+ return ERROR_HTTP_INVALID_HEADER;
+ }
+
+ *(DWORD *)lpBuffer = value;
+ TRACE(" returning number: %u\n", *(DWORD *)lpBuffer);
+ }
else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
{
time_t tmpTime;
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c
index cb96abe612..fcbd95b837 100644
--- a/dlls/wininet/tests/http.c
+++ b/dlls/wininet/tests/http.c
@@ -23,6 +23,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include "windef.h"
#include "winbase.h"
@@ -2061,6 +2062,12 @@ static const char okmsg2[] =
"Set-Cookie: two\r\n"
"\r\n";
+static DWORD64 content_length;
+static const char largemsg[] =
+"HTTP/1.1 200 OK\r\n"
+"Content-Length: %I64u\r\n"
+"\r\n";
+
static const char notokmsg[] =
"HTTP/1.1 400 Bad Request\r\n"
"Server: winetest\r\n"
@@ -2455,6 +2462,12 @@ static DWORD CALLBACK server_thread(LPVOID param)
{
send(c, okmsg, sizeof(okmsg)-1, 0);
}
+ if (strstr(buffer, "HEAD /test_large_content"))
+ {
+ char msg[sizeof(largemsg) + 16];
+ sprintf(msg, largemsg, content_length);
+ send(c, msg, strlen(msg), 0);
+ }
shutdown(c, 2);
closesocket(c);
c = -1;
@@ -5515,6 +5528,74 @@ static void test_remove_dot_segments(int port)
close_request(&req);
}
+struct large_test
+{
+ DWORD64 content_length;
+ BOOL ret;
+};
+
+static void test_large_content(int port)
+{
+ struct large_test tests[] = {
+ { 0, TRUE },
+ { UINT_MAX-1, TRUE },
+ { UINT_MAX, TRUE },
+ { (DWORD64)UINT_MAX+1, FALSE },
+ { ~0, FALSE },
+ };
+ test_request_t req;
+ DWORD sizelen, len;
+ DWORD64 len64;
+ BOOL ret;
+ size_t i;
+
+ open_simple_request(&req, "localhost", port, "HEAD", "/test_large_content");
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++)
+ {
+ content_length = tests[i].content_length;
+ ret = HttpSendRequestA(req.request, NULL, 0, NULL, 0);
+ ok(ret, "HttpSendRequest failed: %u\n", GetLastError());
+
+ len = ~0;
+ sizelen = sizeof(len);
+ SetLastError(0xdeadbeef);
+ ret = HttpQueryInfoA(req.request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+ &len, &sizelen, 0);
+ if (tests[i].ret)
+ {
+ ok(ret, "HttpQueryInfo should have succeeded\n");
+ ok(GetLastError() == ERROR_SUCCESS ||
+ broken(GetLastError() == 0xdeadbeef), /* xp, 2k8, vista */
+ "expected ERROR_SUCCESS, got %x\n", GetLastError());
+ ok(len == (DWORD)tests[i].content_length, "expected %u, got %u\n",
+ (DWORD)tests[i].content_length, len);
+ }
+ else
+ {
+ ok(!ret, "HttpQueryInfo should have failed\n");
+ ok(GetLastError() == ERROR_HTTP_INVALID_HEADER,
+ "expected ERROR_HTTP_INVALID_HEADER, got %x\n", GetLastError());
+ ok(len == ~0, "expected ~0, got %u\n", len);
+ }
+ ok(sizelen == sizeof(DWORD), "sizelen %u\n", sizelen);
+ }
+
+ /* test argument size */
+ len64 = ~0;
+ sizelen = sizeof(len64);
+ SetLastError(0xdeadbeef);
+ ret = HttpQueryInfoA(req.request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+ &len64, &len, 0);
+ ok(!ret, "HttpQueryInfo should have failed\n");
+ ok(GetLastError() == ERROR_HTTP_INVALID_HEADER,
+ "expected ERROR_HTTP_INVALID_HEADER, got %x\n", GetLastError());
+ ok(sizelen == sizeof(DWORD64), "sizelen %u\n", sizelen);
+ ok(len64 == ~0, "len64 %x%08x\n", (DWORD)(len64 >> 32), (DWORD)len64);
+
+ close_request(&req);
+}
+
static void test_http_connection(void)
{
struct server_info si;
@@ -5573,6 +5654,7 @@ static void test_http_connection(void)
test_redirect(si.port);
test_persistent_connection(si.port);
test_remove_dot_segments(si.port);
+ test_large_content(si.port);
/* send the basic request again to shutdown the server thread */
test_basic_request(si.port, "GET", "/quit");
--
2.17.1
More information about the wine-devel
mailing list