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
-- v4: wininet: Partially 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..8e30b220c10 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expect = pos == i && err == NO_ERROR; + todo_wine 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expect = pos == (DWORD)INT_MAX+1 && err == NO_ERROR; + todo_wine 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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 | 16 +++++++++++ dlls/wininet/internet.c | 60 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index c9d1c463982..a0e44b50639 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3184,6 +3184,22 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD req->read_pos += read; }
+ if(read < size && req->hCacheFile) { + DWORD cache_pos, err; + while(read < size) { + cache_pos = SetFilePointer(req->hCacheFile, 0, NULL, FILE_CURRENT); + err = cache_pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + if(err != NO_ERROR) + ERR("SetFilePointer return with error %ld\n", err); + if(cache_pos <= GetFileSize(req->hCacheFile, NULL)) + break; + 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..baa0cd5313d 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2154,14 +2154,68 @@ 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: + FIXME("dwMoveContext %ld not implemented\n", dwMoveContext); + err = ERROR_NEGATIVE_SEEK; + goto lend; + case FILE_END: + default: + FIXME("Unhandled dwMoveContext %ld\n", dwMoveContext); + goto lend; + }
- SetLastError(ERROR_INTERNET_INVALID_OPERATION); - return INVALID_SET_FILE_POINTER; + 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 = SetFilePointer(request->hCacheFile, lDistanceToMove, NULL, dwMoveContext); + err = cache_pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + if(err != NO_ERROR) + goto lend; + 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); + +lend: + if(res == INVALID_SET_FILE_POINTER) + 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=125881
Your paranoid android.
=== debian11 (32 bit ar:MA report) ===
wininet: http.c:625: Test failed: Expected position 0. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x1. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x2. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x3. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x4. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x3. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x2. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x1. Got 0xffffffff. GetLastError() 6 http.c:656: Test failed: Expected position 0x7fffffff. Got 0xffffffff. GetLastError() 6 http.c:665: Test failed: Expected position 0x7fffffff. Got 0xffffffff. GetLastError() 6
=== debian11 (32 bit hi:IN report) ===
wininet: http.c:625: Test failed: Expected position 0. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x1. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x2. Got 0xffffffff. GetLastError() 6 http.c:625: Test failed: Expected position 0x3. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x4. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x3. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x2. Got 0xffffffff. GetLastError() 6 http.c:632: Test failed: Expected position 0x1. Got 0xffffffff. GetLastError() 6 http.c:656: Test failed: Expected position 0x7fffffff. Got 0xffffffff. GetLastError() 6 http.c:665: Test failed: Expected position 0x7fffffff. Got 0xffffffff. GetLastError() 6