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.
From: Jason Kuo j20001970@gmail.com
--- dlls/wininet/tests/http.c | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index 8fcb9df293a..0a1c34ea173 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -581,6 +581,84 @@ static void close_async_handle(HINTERNET handle, int handle_cnt) CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt); }
+static void InternetSetFilePointer_test() +{ + HINTERNET hi = 0, hic = 0, hor = 0; + BOOL res, expect; + INT pos; + DWORD i, 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 %#lx. 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; + } + + InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = GetLastError(); + expect = pos == -1 && err == NO_ERROR; + ok(expect, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", -1, 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 %#lx. 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 %#lx. 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 %#lx. Got %#lx. GetLastError() %lu\n", INT_MAX-1, 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 %#lx. Got %#lx. GetLastError() %lu\n", INT_MAX-2, 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 +8024,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 | 9 ++++++ dlls/wininet/internet.c | 62 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index c9d1c463982..a672ae7fd8f 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3184,6 +3184,15 @@ 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)) { + while(read < size) { + res = ReadFile(req->hCacheFile, 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..136fb34e24c 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2154,14 +2154,70 @@ 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); + INT cache_pos; + DWORD 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; + } + + cache_pos = SetFilePointer(request->hCacheFile, 0, NULL, FILE_CURRENT); + switch (dwMoveContext) { + case FILE_BEGIN: + cache_pos = lDistanceToMove; + break; + case FILE_CURRENT: + if(cache_pos < 0 && lDistanceToMove < 0) { + err = ERROR_NEGATIVE_SEEK; + goto lend; + } + cache_pos += lDistanceToMove; + break; + case FILE_END: + 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) { + if(!InternetReadFile(hFile, buf, 1024, &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=125803
Your paranoid android.
=== debian11 (32 bit report) ===
wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131
=== debian11 (32 bit ar:MA report) ===
wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131
=== debian11 (32 bit de report) ===
wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131
=== debian11 (32 bit zh:CN report) ===
wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131
On Sat Nov 5 09:49:23 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=125803 Your paranoid android. === debian11 (32 bit report) === wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131 === debian11 (32 bit ar:MA report) === wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131 === debian11 (32 bit de report) === wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131 === debian11 (32 bit zh:CN report) === wininet: http.c:634: Test failed: Expected position 0xffffffff. Got 0xffffffff. GetLastError() 131
Should I be concerned with this report? Does that mean the test will pass on actual 32-bit windows, but not on 32-bit debian?
On Sat Nov 5 10:35:53 2022 +0000, Jason Kuo wrote:
Should I be concerned with this report? Does that mean the test will pass on actual 32-bit windows, but not on 32-bit debian?
yes (you should be concerned), one of the tests you created is failing, but I think that's because your test is bad, rather than your code being bad to fix it what you have to do is: on line 633, you are checking for NO_ERROR, when you should be checking for ERROR_NEGATIVE_SEEK
On Sat Nov 5 14:38:38 2022 +0000, Etaash Mathamsetty wrote:
yes (you should be concerned), one of the tests you created is failing, but I think that's because your test is bad, rather than your code being bad to fix it what you have to do is: on line 633, you are checking for NO_ERROR, when you should be checking for ERROR_NEGATIVE_SEEK
I thought the tests must be passed on windows machine, if I change expected error to ERROR_NEGATIVE_SEEK it will fail on my Win10 VM instead.
On Sat Nov 5 16:25:38 2022 +0000, Jason Kuo wrote:
I thought the tests must be passed on windows machine, if I change expected error to ERROR_NEGATIVE_SEEK it will fail on my Win10 VM instead.
interesting, I am not very familiar with wininet, so I don't know what we are supposed to do here
On Sat Nov 5 19:13:36 2022 +0000, Etaash Mathamsetty wrote:
interesting, I am not very familiar with wininet, so I don't know what we are supposed to do here
If the tests are passing on Windows but failing in Wine, that implies your implementation is not completely correct. Depending on the reason for that, you should probably either fix your implementation or mark the test todo_wine.
On Sun Nov 6 18:56:04 2022 +0000, Zebediah Figura wrote:
If the tests are passing on Windows but failing in Wine, that implies your implementation is not completely correct. Depending on the reason for that, you should probably either fix your implementation or mark the test todo_wine.
I set up a 32-bit debian VM trying to reproduce the failing test, but the tests passed without failures. With current implementation, the test that fail on line 634 occur iff returned cache file pointer is 0xffffffff, which I'm not sure if it is intended behavior. Will investigate some more and perhaps mark that test as todo_wine since I'm unable to reproduce the same result.