The function is implemented by setting cache file pointer to fill read_buf. Consequently, when HTTPREQ_ReadFile is called, it will try reading data from cache after read_buf is depleted, before continuing reading from http stream.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26570
-- v3: wininet: Implement InternetSetFilePointer wininet/tests: Add InternetSetFilePointer tests.
From: Jason Kuo j20001970@gmail.com
--- dlls/wininet/tests/http.c | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index 8fcb9df293a..44b8dba3aa1 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -581,6 +581,102 @@ static void close_async_handle(HINTERNET handle, int handle_cnt) CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt); }
+static void InternetSetFilePointer_test(void) +{ + HINTERNET hi = 0, hic = 0, hor = 0; + BOOL res, expect; + DWORD i, pos, err; + + hi = InternetOpenA("Winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok((hi != 0x0), "InternetOpen failed with error %lu\n", GetLastError()); + if(hi == 0x0) goto abort; + + hic = InternetConnectA(hi, "test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, + NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok((hic != 0x0), "InternetConnect failed with error %lu\n", GetLastError()); + if(hic == 0x0) goto abort; + + hor = HttpOpenRequestA(hic, NULL, "/favicon.ico", NULL, NULL, NULL, + INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE, + 0x0); + ok((hor != 0x0), "HttpOpenRequest failed with error %lu\n", GetLastError()); + if(hor == 0x0) goto abort; + + pos = InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + err = GetLastError(); + expect = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; + ok(expect, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INVALID_SET_FILE_POINTER, pos, err); + if(hor) InternetCloseHandle(hor); + + hor = HttpOpenRequestA(hic, NULL, "/favicon.ico", NULL, NULL, NULL, + INTERNET_FLAG_RELOAD, + 0x0); + ok((hor != 0x0), "HttpOpenRequest failed with error %lu\n", GetLastError()); + if(hor == 0x0) goto abort; + + res = HttpSendRequestW(hor, NULL, 0, NULL, 0); + ok(res, "HttpSendRequest failed with error %lu\n", GetLastError()); + + i = 0; + while(i < 4) { + pos = InternetSetFilePointer(hor, i, NULL, FILE_BEGIN, 0); + err = GetLastError(); + expect = pos == i && err == NO_ERROR; + ok(expect, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + i = i + 1; + } + while(i > 0) { + pos = InternetSetFilePointer(hor, i, NULL, FILE_BEGIN, 0); + err = GetLastError(); + expect = pos == i && err == NO_ERROR; + ok(expect, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + i = i - 1; + } + + InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + i = 0; + while(i < 4) { + i = i + 1; + pos = InternetSetFilePointer(hor, 1, NULL, FILE_CURRENT, 0); + err = GetLastError(); + expect = pos == i && err == NO_ERROR; + ok(expect, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + } + while(i > 0) { + i = i - 1; + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = GetLastError(); + expect = pos == INVALID_SET_FILE_POINTER && err == ERROR_NEGATIVE_SEEK; + ok(expect, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INVALID_SET_FILE_POINTER, pos, err); + } + + pos = InternetSetFilePointer(hor, INT_MAX, NULL, FILE_BEGIN, 0); + err = GetLastError(); + expect = pos == INT_MAX && err == NO_ERROR; + ok(expect, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INT_MAX, pos, err); + pos = InternetSetFilePointer(hor, 1, NULL, FILE_CURRENT, 0); + err = GetLastError(); + expect = pos == (DWORD)INT_MAX+1 && err == NO_ERROR; + ok(expect, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", (DWORD)INT_MAX+1, pos, err); + + pos = InternetSetFilePointer(hor, INT_MAX, NULL, FILE_BEGIN, 0); + err = GetLastError(); + expect = pos == INT_MAX && err == NO_ERROR; + ok(expect, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INT_MAX, pos, err); + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = GetLastError(); + expect = pos == INVALID_SET_FILE_POINTER && err == ERROR_NEGATIVE_SEEK; + ok(expect, "Expected position %#x. Got %#lx. GetLastError() %lu\n", INVALID_SET_FILE_POINTER, pos, err); + +abort: + if(hor) + InternetCloseHandle(hor); + if(hic) + InternetCloseHandle(hic); + if(hi) + InternetCloseHandle(hi); +} + static void InternetReadFile_test(int flags, const test_data_t *test) { char *post_data = NULL; @@ -7946,6 +8042,7 @@ START_TEST(http) InternetReadFile_chunked_test(); HttpSendRequestEx_test(); InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[3]); + InternetSetFilePointer_test(); test_connection_failure(); test_default_service_port(); test_concurrent_header_access();
From: Jason Kuo j20001970@gmail.com
The function is implemented by setting cache file pointer to fill read_buf. Consequently, when HTTPREQ_ReadFile is called, it will try reading data from cache after read_buf is depleted, before continuing reading from http stream.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26570 --- dlls/wininet/http.c | 12 ++++++++ dlls/wininet/internet.c | 65 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index c9d1c463982..0824fd0e676 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3184,6 +3184,18 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD req->read_pos += read; }
+ if(read < size && SetFilePointer(req->hCacheFile, 0, NULL, FILE_CURRENT) < GetFileSize(req->hCacheFile, NULL)) { + DWORD err = GetLastError(); + if(err != NO_ERROR) + ERR("SetFilePointer return with error %ld\n", err); + while(read < size) { + res = ReadFile(req->hCacheFile, (char*)buf+read, size-read, &cread, NULL); + read += cread; + if(res != ERROR_SUCCESS || !cread) + break; + } + } + if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) { LeaveCriticalSection(&req->read_section); INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 292fd44dd8e..e8947b4b0de 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2154,14 +2154,73 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
/*********************************************************************** * InternetSetFilePointer (WININET.@) + * Sets read position for an open internet file. + * + * RETURNS + * Current position of the file on success + * INVALID_SET_FILE_POINTER on failure */ DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove, PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext) { - FIXME("(%p %ld %p %ld %Ix): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); + DWORD cache_pos, read, cread; + DWORD err = ERROR_INTERNET_INVALID_OPERATION, res = INVALID_SET_FILE_POINTER; + http_request_t *request; + + TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); + + request = (http_request_t*)get_handle_object(hFile); + + if(request->hdr.dwFlags & (INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_CACHE_WRITE)) + goto lend; + + switch (dwMoveContext) { + case FILE_BEGIN: + cache_pos = lDistanceToMove; + break; + case FILE_CURRENT: + if(lDistanceToMove < 0) { + err = ERROR_NEGATIVE_SEEK; + goto lend; + } + cache_pos = SetFilePointer(request->hCacheFile, 0, NULL, FILE_CURRENT); + err = GetLastError(); + if(err != NO_ERROR) + ERR("SetFilePointer return with error %ld\n", err); + cache_pos += lDistanceToMove; + break; + case FILE_END: + default: + FIXME("Unhandled dwMoveContext %ld\n", dwMoveContext); + goto lend; + } + + if(GetFileSize(request->hCacheFile, NULL) < cache_pos) { + BYTE buf[1024]; + while(GetFileSize(request->hCacheFile, NULL) < cache_pos) { + res = InternetReadFile(hFile, buf, 1024, &cread); + if(res != ERROR_SUCCESS || !cread) + break; + } + } + + res = cache_pos; + cache_pos = SetFilePointer(request->hCacheFile, lDistanceToMove, NULL, dwMoveContext); + EnterCriticalSection(&request->read_section); + read = min(READ_BUFFER_SIZE, GetFileSize(request->hCacheFile, NULL)-cache_pos); + if(ReadFile(request->hCacheFile, request->read_buf, read, &cread, NULL)) { + request->read_size = cread; + request->read_pos = 0; + } + LeaveCriticalSection(&request->read_section); + err = NO_ERROR;
- SetLastError(ERROR_INTERNET_INVALID_OPERATION); - return INVALID_SET_FILE_POINTER; +lend: + SetLastError(err); + TRACE("returning %ld\n", res); + if(request) + WININET_Release( &request->hdr ); + return res; }
/***********************************************************************
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125845
Your paranoid android.
=== w10pro64 (32 bit report) ===
wininet: http.c:1699: Test failed: Could not create file: 2 http.c:1713: Test failed: Deleting file returned 0(2) http.c:1719: Test failed: Could not create file: 2 http.c:1823: Test failed: Deleting file returned 0(2) http.c:1828: Test failed: Deleting file returned 0(2)
=== w10pro64_en_AE_u8 (64 bit report) ===
wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 0284:http: unhandled exception c0000005 at 00007FFF69377B6A
=== w10pro64_ar (64 bit report) ===
wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 1dd8:http: unhandled exception c0000005 at 00007FFF69377B6A
=== w10pro64_zh_CN (64 bit report) ===
wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 1cd8:http: unhandled exception c0000005 at 00007FFF69377B6A
=== debian11 (32 bit zh:CN report) ===
wininet: http.c:643: Test failed: Expected position 0x1. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x2. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x3. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x4. Got 0. GetLastError() 0 http.c:660: Test failed: Expected position 0x80000000. Got 0. GetLastError() 0
On Mon Nov 7 13:34:26 2022 +0000, **** wrote:
Marvin replied on the mailing list:
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details: The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125845 Your paranoid android. === w10pro64 (32 bit report) === wininet: http.c:1699: Test failed: Could not create file: 2 http.c:1713: Test failed: Deleting file returned 0(2) http.c:1719: Test failed: Could not create file: 2 http.c:1823: Test failed: Deleting file returned 0(2) http.c:1828: Test failed: Deleting file returned 0(2) === w10pro64_en_AE_u8 (64 bit report) === wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 0284:http: unhandled exception c0000005 at 00007FFF69377B6A === w10pro64_ar (64 bit report) === wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 1dd8:http: unhandled exception c0000005 at 00007FFF69377B6A === w10pro64_zh_CN (64 bit report) === wininet: http.c:1695: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1699: Test failed: Could not create file: 3 http.c:1701: Test failed: file size = 4294967295 http.c:1709: Test failed: file size = 4294967295 http.c:1713: Test failed: Deleting file returned 0(3) http.c:1719: Test failed: Could not create file: 3 http.c:1721: Test failed: WriteFile failed: 0, 0 http.c:1723: Test failed: CommitUrlCacheEntry failed: 12004 http.c:1730: Test failed: HttpSendRequest failed http.c:1735: Test failed: size = 0 http.c:1737: Test failed: incorrect page data: <html><body> http.c:1746: Test failed: GetLastError() = 12004 http.c:1580: Test failed: CreateUrlCacheEntryA failed: 12004 http.c:1583: Test failed: CreateFile failed http.c:1590: Test failed: CommitUrlCacheEntryA failed: 12004 http.c:1618: Test failed: HttpSendRequest failed: 997 http.c:376: Test failed: unexpected status 100 (INTERNET_STATUS_REQUEST_COMPLETE) http.c:1644: Test failed: DeleteUrlCacheEntryA failed: 12004 http.c:1809: Test failed: InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: 12028 http.c:1812: Test failed: InternetLockRequestFile returned: 0(2) http.c:1813: Test failed: lock == NULL http.c:1816: Test failed: InternetLockRequestFile returned: 0(2) 1cd8:http: unhandled exception c0000005 at 00007FFF69377B6A === debian11 (32 bit zh:CN report) === wininet: http.c:643: Test failed: Expected position 0x1. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x2. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x3. Got 0. GetLastError() 0 http.c:643: Test failed: Expected position 0x4. Got 0. GetLastError() 0 http.c:660: Test failed: Expected position 0x80000000. Got 0. GetLastError() 0
It seems the tests on 32-bit debian is failing due to cache file handle being invalid, but I'm unable to reproduce the problem.