[PATCH v5 0/2] MR9369: wininet: Return correct errors and put handle into invalid state when seeking beyond end of file.
When `InternetSetFilePointer` is used to seek and then read beyond the size of the remote file, the initial read will fail with `ERROR_NOACCESS` and put the handle into an invalid state such that `InternetSetFilePointer`, `InternetReadFile`, and `InternetQueryDataAvailable` will return errors from then on. Based on !9644. -- v5: wininet: Return correct errors and put handle into invalid state when seeking beyond end of file. wininet/tests: Add tests for seeking beyond end of file. https://gitlab.winehq.org/wine/wine/-/merge_requests/9369
From: Torge Matthies <openglfreak@googlemail.com> --- dlls/wininet/tests/http.c | 93 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index d63f42e27d7..3fa48ba8996 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -587,6 +587,7 @@ static void InternetSetFilePointer_test(const char *host, const char *path) { BYTE expect_response[8192], buf[8192]; HINTERNET hi = 0, hic = 0, hor = 0; + HANDLE file = INVALID_HANDLE_VALUE; BOOL res, expected; DWORD count, size, i, pos, err; @@ -706,6 +707,8 @@ static void InternetSetFilePointer_test(const char *host, const char *path) expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); + SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); SET_EXPECT(INTERNET_STATUS_HANDLE_CLOSING); InternetCloseHandle(hor); @@ -844,6 +847,96 @@ static void InternetSetFilePointer_test(const char *host, const char *path) CLEAR_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); CLEAR_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED); + SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); + SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); + SET_EXPECT(INTERNET_STATUS_HANDLE_CLOSING); + InternetCloseHandle(hor); + + SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); + hor = HttpOpenRequestA(hic, NULL, path, NULL, NULL, NULL, + INTERNET_FLAG_RELOAD, + 0xdeadbead); + ok(hor != 0x0, "HttpOpenRequest failed: %lu\n", GetLastError()); + if(hor == 0x0) goto abort; + CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); + + SET_OPTIONAL(INTERNET_STATUS_CONNECTING_TO_SERVER); + SET_OPTIONAL(INTERNET_STATUS_CONNECTED_TO_SERVER); + + SET_EXPECT(INTERNET_STATUS_SENDING_REQUEST); + SET_EXPECT(INTERNET_STATUS_REQUEST_SENT); + SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED); + + res = HttpSendRequestA(hor, NULL, 0, NULL, 0); + err = !res ? GetLastError() : NO_ERROR; + expected = res && err == NO_ERROR; + ok(expected, "HttpSendRequest failed: %lu\n", err); + + CHECK_NOTIFIED(INTERNET_STATUS_SENDING_REQUEST); + CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_SENT); + CHECK_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); + CHECK_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED); + + SetLastError(0xdeadbeef); + res = InternetReadFile(hor, buf, 10, &count); + err = !res ? GetLastError() : NO_ERROR; + ok(res, "InternetReadFile failed: %lu\n", err); + ok(count, "InternetReadFile returned no content\n"); + + SetLastError(0xdeadbeef); + pos = InternetSetFilePointer(hor, INT_MAX, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INT_MAX && err == NO_ERROR; + ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INT_MAX, pos, err); + + SetLastError(0xdeadbeef); + res = InternetReadFile(hor, buf, 1024, &count); + err = !res ? GetLastError() : NO_ERROR; + todo_wine + ok(!res, "InternetReadFile succeeded unexpectedly\n"); + todo_wine + ok(err == ERROR_NOACCESS, "InternetReadFile unexpected error %lu\n", err); + + SetLastError(0xdeadbeef); + res = InternetReadFile(hor, buf, 1024, &count); + err = !res ? GetLastError() : NO_ERROR; + todo_wine + ok(!res, "InternetReadFile succeeded unexpectedly\n"); + todo_wine + ok(err == ERROR_INTERNET_INCORRECT_HANDLE_STATE, "InternetReadFile unexpected error %lu\n", err); + + SetLastError(0xdeadbeef); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; + todo_wine + ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INVALID_SET_FILE_POINTER, pos, err); + + count = 0; + SetLastError(0xdeadbeef); + res = InternetQueryDataAvailable(hor, &count, 0x0, 0x0); + err = !res ? GetLastError() : NO_ERROR; + todo_wine + ok(!res, "InternetQueryDataAvailable succeeded unexpectedly\n"); + todo_wine + ok(err == ERROR_INTERNET_INCORRECT_HANDLE_STATE, "InternetQueryDataAvailable unexpected error %lu\n", err); + todo_wine + ok(count == 0, "InternetQueryDataAvailable unexpected count: %lu\n", count); + + size = ARRAY_SIZE(buf); + res = InternetQueryOptionA(hor, INTERNET_OPTION_URL, buf, &size); + ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed with error %ld\n", GetLastError()); + + res = TRUE; + res = InternetSetOptionA(hor, INTERNET_OPTION_HTTP_DECODING, &res, sizeof(res)); + ok(res, "InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %ld\n", GetLastError()); + + res = InternetLockRequestFile(hor, &file); + if (res) + InternetUnlockRequestFile(file); + ok(res, "InternetLockRequestFile failed: %ld\n", GetLastError()); + abort: SET_OPTIONAL(INTERNET_STATUS_CLOSING_CONNECTION); SET_OPTIONAL(INTERNET_STATUS_CONNECTION_CLOSED); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9369
From: Torge Matthies <openglfreak@googlemail.com> --- dlls/wininet/http.c | 35 ++++++++++++++++++++++++++++++++--- dlls/wininet/tests/http.c | 8 -------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index c1bba8a6594..c8cd193bdaf 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3053,6 +3053,11 @@ static DWORD read_req_file(http_request_t *req, BYTE *buffer, DWORD size, DWORD &ret_read, allow_blocking); if (res != ERROR_SUCCESS) return res; + if (!ret_read && req->content_pos > req->cache_size) { + req->state = ERROR_INTERNET_INCORRECT_HANDLE_STATE; + *read = 0; + return ERROR_NOACCESS; + } if (!ret_read) { *read = 0; return ERROR_SUCCESS; @@ -3065,6 +3070,10 @@ static DWORD read_req_file(http_request_t *req, BYTE *buffer, DWORD size, DWORD return GetLastError(); if (!ReadFile(req->req_file->file_handle, buffer, size, &ret_read, NULL)) return GetLastError(); + } else if (req->content_pos > req->cache_size) { + req->state = ERROR_INTERNET_INCORRECT_HANDLE_STATE; + *read = 0; + return ERROR_NOACCESS; } *read = ret_read; @@ -3153,6 +3162,13 @@ static void async_read_file_proc(task_header_t *hdr) while (req->content_pos > req->cache_size) { ret = read_http_stream(req, (BYTE*)buf, min(sizeof(buf), req->content_pos - req->cache_size), &ret_read, TRUE); + if (!ret_read && req->content_pos > req->cache_size) { + req->state = ERROR_INTERNET_INCORRECT_HANDLE_STATE; + if(task->ret_read) + *task->ret_read = 0; + send_request_complete(req, FALSE, ERROR_NOACCESS); + return; + } if(ret != ERROR_SUCCESS || !ret_read) break; } @@ -3219,6 +3235,12 @@ static DWORD HTTPREQ_SetFilePointer(object_header_t *hdr, LONG lDistanceToMove, EnterCriticalSection(&req->read_section); + if (req->state != ERROR_SUCCESS) { + LeaveCriticalSection(&req->read_section); + SetLastError(ERROR_INTERNET_INVALID_OPERATION); + return INVALID_SET_FILE_POINTER; + } + switch (dwMoveContext) { case FILE_BEGIN: res = lDistanceToMove; @@ -3269,8 +3291,10 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD req->state = INTERNET_HANDLE_IN_USE; else if(req->state == INTERNET_HANDLE_IN_USE) req->state = ERROR_INTERNET_INTERNAL_ERROR; + else + res = req->state; - if(req->read_size) { + if(res == ERROR_SUCCESS && req->read_size) { read = min(size, req->read_size); memcpy(buf, req->read_buf + req->read_pos, read); req->read_size -= read; @@ -3278,7 +3302,7 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD req->content_pos += read; } - if(read < size && req->req_file && req->req_file->file_handle) { + if(res == ERROR_SUCCESS && read < size && req->req_file && req->req_file->file_handle) { res = read_req_file(req, (BYTE*)buf + read, size - read, &cread, allow_blocking); if(res == ERROR_SUCCESS) { read += cread; @@ -3300,7 +3324,7 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD } } - if(req->state == INTERNET_HANDLE_IN_USE) + if(res == ERROR_SUCCESS && req->state == INTERNET_HANDLE_IN_USE) req->state = 0; else error = req->state; @@ -3366,6 +3390,11 @@ static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, else if(req->state == INTERNET_HANDLE_IN_USE) req->state = ERROR_INTERNET_INTERNAL_ERROR; + if (req->state != ERROR_SUCCESS) { + LeaveCriticalSection( &req->read_section ); + return req->state; + } + avail = req->read_size; if(req->cache_size > req->content_pos) avail = max(avail, req->cache_size - req->content_pos); diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index 3fa48ba8996..42d40dc26e3 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -893,35 +893,27 @@ static void InternetSetFilePointer_test(const char *host, const char *path) SetLastError(0xdeadbeef); res = InternetReadFile(hor, buf, 1024, &count); err = !res ? GetLastError() : NO_ERROR; - todo_wine ok(!res, "InternetReadFile succeeded unexpectedly\n"); - todo_wine ok(err == ERROR_NOACCESS, "InternetReadFile unexpected error %lu\n", err); SetLastError(0xdeadbeef); res = InternetReadFile(hor, buf, 1024, &count); err = !res ? GetLastError() : NO_ERROR; - todo_wine ok(!res, "InternetReadFile succeeded unexpectedly\n"); - todo_wine ok(err == ERROR_INTERNET_INCORRECT_HANDLE_STATE, "InternetReadFile unexpected error %lu\n", err); SetLastError(0xdeadbeef); pos = InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; - todo_wine ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INVALID_SET_FILE_POINTER, pos, err); count = 0; SetLastError(0xdeadbeef); res = InternetQueryDataAvailable(hor, &count, 0x0, 0x0); err = !res ? GetLastError() : NO_ERROR; - todo_wine ok(!res, "InternetQueryDataAvailable succeeded unexpectedly\n"); - todo_wine ok(err == ERROR_INTERNET_INCORRECT_HANDLE_STATE, "InternetQueryDataAvailable unexpected error %lu\n", err); - todo_wine ok(count == 0, "InternetQueryDataAvailable unexpected count: %lu\n", count); size = ARRAY_SIZE(buf); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9369
participants (2)
-
Torge Matthies -
Torge Matthies (@tmatthies)