-- v15: wininet/tests: Add more InternetSetFilePointer tests. wininet/tests: Add InternetSetFilePointer tests. wininet: Partially implement InternetSetFilePointer
From: Jason Kuo j20001970@gmail.com
The function is implemented by setting the newly added contentPos that keep track of current read position in the content, when InternetReadFile related function is called, data will be read from req_file->file_handle before continuing reading from http stream.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26570 --- dlls/wininet/ftp.c | 3 ++ dlls/wininet/http.c | 112 ++++++++++++++++++++++++++++++++++++++-- dlls/wininet/internet.c | 29 +++++++++-- dlls/wininet/internet.h | 3 ++ 4 files changed, 140 insertions(+), 7 deletions(-)
diff --git a/dlls/wininet/ftp.c b/dlls/wininet/ftp.c index cf6555c63e2..f3f586cd6e1 100644 --- a/dlls/wininet/ftp.c +++ b/dlls/wininet/ftp.c @@ -1293,6 +1293,7 @@ static const object_vtbl_t FTPFILEVtbl = { NULL, FTPFILE_QueryOption, INET_SetOption, + NULL, FTPFILE_ReadFile, FTPFILE_WriteFile, FTPFILE_QueryDataAvailable, @@ -2397,6 +2398,7 @@ static const object_vtbl_t FTPSESSIONVtbl = { NULL, NULL, NULL, + NULL, NULL };
@@ -3525,6 +3527,7 @@ static const object_vtbl_t FTPFINDNEXTVtbl = { NULL, NULL, NULL, + NULL, FTPFINDNEXT_FindNextFileW };
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index b42f823208c..b646ddf5b69 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -329,6 +329,7 @@ static void reset_data_stream(http_request_t *req) destroy_data_stream(req->data_stream); req->data_stream = &req->netconn_stream.data_stream; req->read_pos = req->read_size = req->netconn_stream.content_read = 0; + req->content_pos = 0; req->read_gzip = FALSE; }
@@ -2499,6 +2500,8 @@ static void create_cache_entry(http_request_t *req)
create_req_file(file_name, &req->req_file); req->req_file->url = url; + req->content_pos = 0; + req->cache_size = 0;
req->hCacheFile = CreateFileW(file_name, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -2512,7 +2515,9 @@ static void create_cache_entry(http_request_t *req) DWORD written;
b = WriteFile(req->hCacheFile, req->read_buf+req->read_pos, req->read_size, &written, NULL); - if(!b) + if(b) + req->cache_size += written; + else FIXME("WriteFile failed: %lu\n", GetLastError());
if(req->data_stream->vtbl->end_of_data(req->data_stream, req)) @@ -2621,7 +2626,9 @@ static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD DWORD written;
bres = WriteFile(req->hCacheFile, buf, *read, &written, NULL); - if(!bres) + if(bres) + req->cache_size += written; + else FIXME("WriteFile failed: %lu\n", GetLastError()); }
@@ -3033,6 +3040,35 @@ static void HTTP_ReceiveRequestData(http_request_t *req) send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, 0); }
+static DWORD read_req_file(http_request_t *req, BYTE *buffer, DWORD size, DWORD *read, BOOL allow_blocking) +{ + DWORD ret_read = 0, res; + LARGE_INTEGER off; + BYTE buf[1024]; + + while (req->content_pos > req->cache_size) { + res = read_http_stream(req, (BYTE*)buf, min(sizeof(buf), req->content_pos - req->cache_size), + &ret_read, allow_blocking); + if (res != ERROR_SUCCESS) + return res; + if (!ret_read) { + *read = 0; + return ERROR_SUCCESS; + } + } + + if (req->content_pos < req->cache_size) { + off.QuadPart = req->content_pos; + if (!SetFilePointerEx(req->req_file->file_handle, off, NULL, FILE_BEGIN)) + return GetLastError(); + if (!ReadFile(req->req_file->file_handle, buffer, size, &ret_read, NULL)) + return GetLastError(); + } + + *read = ret_read; + return ERROR_SUCCESS; +} + /* read data from the http connection (the read section must be held) */ static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL allow_blocking) { @@ -3046,13 +3082,16 @@ static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD * memcpy(buffer, req->read_buf+req->read_pos, ret_read); req->read_size -= ret_read; req->read_pos += ret_read; + req->content_pos += ret_read; allow_blocking = FALSE; }
if(ret_read < size) { res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, allow_blocking); - if(res == ERROR_SUCCESS) + if(res == ERROR_SUCCESS) { ret_read += current_read; + req->content_pos += current_read; + } else if(res == WSAEWOULDBLOCK && ret_read) res = ERROR_SUCCESS; } @@ -3106,6 +3145,17 @@ static void async_read_file_proc(task_header_t *hdr)
TRACE("req %p buf %p size %lu read_pos %lu ret_read %p\n", req, task->buf, task->size, task->read_pos, task->ret_read);
+ if(req->req_file && req->req_file->file_handle) { + DWORD ret, ret_read; + BYTE buf[1024]; + 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 != ERROR_SUCCESS || !ret_read) + break; + } + } + if(task->buf) { DWORD read_bytes; while (read < task->size) { @@ -3155,6 +3205,47 @@ static DWORD async_read(http_request_t *req, void *buf, DWORD size, DWORD read_p return ERROR_IO_PENDING; }
+static DWORD HTTPREQ_SetFilePointer(object_header_t *hdr, LONG lDistanceToMove, DWORD dwMoveContext) +{ + http_request_t *req = (http_request_t*)hdr; + DWORD res = INVALID_SET_FILE_POINTER, err = ERROR_SUCCESS; + + if(req->hdr.dwFlags & (INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_CACHE_WRITE)) { + SetLastError(ERROR_INTERNET_INVALID_OPERATION); + return INVALID_SET_FILE_POINTER; + } + + EnterCriticalSection(&req->read_section); + + switch (dwMoveContext) { + case FILE_BEGIN: + res = lDistanceToMove; + break; + case FILE_CURRENT: + if(req->content_pos && lDistanceToMove < 0) { + err = ERROR_NEGATIVE_SEEK; + break; + } + res = req->content_pos + lDistanceToMove; + break; + case FILE_END: + FIXME("dwMoveContext FILE_END not implemented\n"); + /* fallthrough */ + default: + err = ERROR_INTERNET_INVALID_OPERATION; + break; + } + + if(err == ERROR_SUCCESS) { + req->content_pos = res; + req->read_pos = req->read_size = 0; + } + + LeaveCriticalSection(&req->read_section); + SetLastError(err); + return res; +} + static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read, DWORD flags, DWORD_PTR context) { @@ -3182,9 +3273,18 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD memcpy(buf, req->read_buf + req->read_pos, read); req->read_size -= read; req->read_pos += read; + req->content_pos += read; }
- if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) { + if(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; + req->content_pos += cread; + } + } + + if(res == ERROR_SUCCESS && 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); EnterCriticalSection( &req->read_section ); @@ -3265,6 +3365,8 @@ static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
avail = req->read_size; + if(req->cache_size > req->content_pos) + avail = max(avail, req->cache_size - req->content_pos);
if(!avail && !end_of_read_data(req)) { LeaveCriticalSection(&req->read_section); @@ -3318,6 +3420,7 @@ static const object_vtbl_t HTTPREQVtbl = { HTTPREQ_CloseConnection, HTTPREQ_QueryOption, HTTPREQ_SetOption, + HTTPREQ_SetFilePointer, HTTPREQ_ReadFile, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, @@ -5807,6 +5910,7 @@ static const object_vtbl_t HTTPSESSIONVtbl = { NULL, NULL, NULL, + NULL, NULL };
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 2926fbccf9b..6dabb0fc5e3 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -957,6 +957,7 @@ static const object_vtbl_t APPINFOVtbl = { APPINFO_SetOption, NULL, NULL, + NULL, NULL };
@@ -2155,14 +2156,36 @@ 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); + object_header_t *hdr; + DWORD res; + + TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); + + hdr = get_handle_object(hFile); + if(!hdr) { + SetLastError(ERROR_INVALID_HANDLE); + return INVALID_SET_FILE_POINTER; + }
- SetLastError(ERROR_INTERNET_INVALID_OPERATION); - return INVALID_SET_FILE_POINTER; + if(hdr->vtbl->SetFilePointer) { + res = hdr->vtbl->SetFilePointer(hdr, lDistanceToMove, dwMoveContext); + }else { + SetLastError(ERROR_INVALID_HANDLE); + res = INVALID_SET_FILE_POINTER; + } + + WININET_Release(hdr); + return res; }
/*********************************************************************** diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 6756488d5a5..d9598d18eb5 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -225,6 +225,7 @@ typedef struct { void (*CloseConnection)(object_header_t*); DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL); DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD); + DWORD (*SetFilePointer)(object_header_t*,LONG,DWORD); DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*,DWORD,DWORD_PTR); DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*); DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR); @@ -332,6 +333,7 @@ typedef struct
FILETIME last_modified; HANDLE hCacheFile; + ULONGLONG cache_size; /* size of cached data */ req_file_t *req_file; FILETIME expires; struct HttpAuthInfo *authInfo; @@ -339,6 +341,7 @@ typedef struct
CRITICAL_SECTION read_section; /* section to protect the following fields */ ULONGLONG contentLength; /* total number of bytes to be read */ + ULONGLONG content_pos; /* content read position */ BOOL read_gzip; /* are we reading in gzip mode? */ DWORD read_pos; /* current read position in read_buf */ DWORD read_size; /* valid data size in read_buf */
From: Jason Kuo j20001970@gmail.com
--- dlls/wininet/tests/http.c | 272 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+)
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index efa3e5928b6..5d487840771 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -581,6 +581,277 @@ static void close_async_handle(HINTERNET handle, int handle_cnt) CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt); }
+static void InternetSetFilePointer_test(const char *host, const char *path) +{ + BYTE expect_response[8192], buf[8192]; + HINTERNET hi = 0, hic = 0, hor = 0; + BOOL res, expected; + DWORD count, size, i, pos, err; + + hi = InternetOpenA("Winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(hi != 0x0, "InternetOpen failed: %lu\n", GetLastError()); + if(hi == 0x0) goto abort; + + hic = InternetConnectA(hi, host, INTERNET_DEFAULT_HTTP_PORT, + NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(hic != 0x0, "InternetConnect failed: %lu\n", GetLastError()); + if(hic == 0x0) goto abort; + + hor = HttpOpenRequestA(hic, NULL, path, NULL, NULL, NULL, + INTERNET_FLAG_RELOAD, + 0x0); + ok(hor != 0x0, "HttpOpenRequest failed: %lu\n", GetLastError()); + if(hor == 0x0) goto abort; + + res = HttpSendRequestA(hor, NULL, 0, NULL, 0); + ok(res, "HttpSendRequest failed: %lu\n", GetLastError()); + if(!res) goto abort; + + size = 0; + while(size < sizeof(expect_response)) { + res = InternetReadFile(hor, expect_response+size, sizeof(expect_response)-size, &count); + if(!res || !count) + break; + size += count; + } + ok(size, "InternetReadFile returned no content\n"); + if(!size) goto abort; + + InternetCloseHandle(hor); + InternetCloseHandle(hic); + InternetCloseHandle(hi); + + reset_events(); + + hi = InternetOpenA("Winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(hi != 0x0, "InternetOpen failed: %lu\n", GetLastError()); + if(hi == 0x0) goto abort; + + pInternetSetStatusCallbackA(hi, &callback); + + SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); + hic = InternetConnectA(hi, host, INTERNET_DEFAULT_HTTP_PORT, + NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0xdeadbeef); + ok(hic != 0x0, "InternetConnect failed: %lu\n", GetLastError()); + if(hic == 0x0) goto abort; + CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); + + SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); + hor = HttpOpenRequestA(hic, NULL, path, NULL, NULL, NULL, + INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE, + 0xdeadbead); + ok(hor != 0x0, "HttpOpenRequest failed: %lu\n", GetLastError()); + if(hor == 0x0) goto abort; + CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); + + /* NULL handle tests */ + pos = InternetSetFilePointer(NULL, 0, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INVALID_HANDLE; + ok(expected, "Expected ERROR_INVALID_HANDLE. Got %lu\n", err); + pos = InternetSetFilePointer(NULL, 0, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INVALID_HANDLE; + ok(expected, "Expected ERROR_INVALID_HANDLE. Got %lu\n", err); + pos = InternetSetFilePointer(NULL, 0, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INVALID_HANDLE; + ok(expected, "Expected ERROR_INVALID_HANDLE. Got %lu\n", err); + + /* INTERNET_FLAG_DONT_CACHE before sending request */ + 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; + ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; + ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; + ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + + 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); + + /* INTERNET_FLAG_DONT_CACHE after sending request */ + 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; + ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_INTERNET_INVALID_OPERATION; + ok(expected, "Expected ERROR_INTERNET_INVALID_OPERATION. Got %lu\n", err); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + 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_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); + + /* FILE_BEGIN tests */ + i = 0; + while(i < min(size, 4)) { + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_OPTIONAL(INTERNET_STATUS_RESPONSE_RECEIVED); + pos = InternetSetFilePointer(hor, i, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == i && err == NO_ERROR; + ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + res = InternetReadFile(hor, buf, sizeof(buf), &count); + err = !res ? GetLastError() : NO_ERROR; + ok(res, "InternetReadFile failed: %lu\n", err); + ok(count, "InternetReadFile returned no content\n"); + ok(!memcmp(expect_response+i, buf, min(sizeof(buf)-i, count)), + "Unexpected result from InternetReadFile\n"); + i = i + 1; + } + while(i > 0) { + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_OPTIONAL(INTERNET_STATUS_RESPONSE_RECEIVED); + pos = InternetSetFilePointer(hor, i, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == i && err == NO_ERROR; + ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + res = InternetReadFile(hor, buf, sizeof(buf), &count); + err = !res ? GetLastError() : NO_ERROR; + ok(res, "InternetReadFile failed: %lu\n", err); + ok(!memcmp(expect_response+i, buf, min(sizeof(buf)-i, count)), + "Unexpected result from InternetReadFile\n"); + i = i - 1; + } + 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); + pos = InternetSetFilePointer(hor, -1, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == -1 && err == NO_ERROR; + ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", -1, pos, err); + + /* FILE_CURRENT tests */ + i = 0; + while(i < min(size, 4)) { + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_OPTIONAL(INTERNET_STATUS_RESPONSE_RECEIVED); + i = i + 1; + pos = InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == 0 && err == NO_ERROR; + ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + pos = InternetSetFilePointer(hor, i, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == i && err == NO_ERROR; + ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", i, pos, err); + res = InternetReadFile(hor, buf, 1024, &count); + err = !res ? GetLastError() : NO_ERROR; + ok(res, "InternetReadFile failed: %lu\n", err); + ok(!memcmp(expect_response+i, buf, min(sizeof(buf)-i, count)), + "Unexpected result from InternetReadFile\n"); + } + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_NEGATIVE_SEEK; + ok(expected, "Expected ERROR_NEGATIVE_SEEK. Got %lu\n", err); + pos = InternetSetFilePointer(hor, 0, NULL, FILE_BEGIN, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == 0 && err == NO_ERROR; + ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", 0, pos, err); + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == -1 && err == NO_ERROR; + ok(expected, "Expected position %#x. Got %#lx. GetLastError() %lu\n", -1, pos, err); + pos = InternetSetFilePointer(hor, -1, NULL, FILE_CURRENT, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_NEGATIVE_SEEK; + ok(expected, "Expected ERROR_NEGATIVE_SEEK. Got %lu\n", err); + + /* FILE_END tests */ + pos = InternetSetFilePointer(hor, 0, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == size && err == NO_ERROR; + todo_wine ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", size, pos, err); + i = 0; + while(i < min(size, 4)) { + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_OPTIONAL(INTERNET_STATUS_RESPONSE_RECEIVED); + i = i + 1; + pos = InternetSetFilePointer(hor, i, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == size+i && err == NO_ERROR; + todo_wine ok(expected, "Expected position %#lx. Got %#lx. GetLastError() %lu\n", + size+i, pos, err); + } + i = 0; + while(i < min(size, 4)) { + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_OPTIONAL(INTERNET_STATUS_RESPONSE_RECEIVED); + i = i + 1; + pos = InternetSetFilePointer(hor, -i, NULL, FILE_END, 0); + err = pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + expected = pos == INVALID_SET_FILE_POINTER && err == ERROR_NEGATIVE_SEEK; + todo_wine ok(expected, "Expected ERROR_NEGATIVE_SEEK. Got %lu\n", err); + } + + CLEAR_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); + CLEAR_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED); + +abort: + SET_OPTIONAL(INTERNET_STATUS_CLOSING_CONNECTION); + SET_OPTIONAL(INTERNET_STATUS_CONNECTION_CLOSED); + SET_OPTIONAL(INTERNET_STATUS_HANDLE_CLOSING); + if(hor) InternetCloseHandle(hor); + SET_OPTIONAL(INTERNET_STATUS_HANDLE_CLOSING); + 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 +8217,7 @@ START_TEST(http) InternetReadFile_chunked_test(); HttpSendRequestEx_test(); InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[3]); + InternetSetFilePointer_test("test.winehq.org", "/tests/hello.html"); test_connection_failure(); test_default_service_port(); test_concurrent_header_access();
From: Jacek Caban jacek@codeweavers.com
--- dlls/wininet/tests/http.c | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index 5d487840771..eeb4a28da4b 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -6109,6 +6109,80 @@ static void test_http_read(int port) skip_receive_notification_tests = FALSE; }
+static void test_file_pointer(int port) +{ + INTERNET_BUFFERSW ib; + test_request_t req; + char buf[24000]; + DWORD pos, read_size; + + skip_receive_notification_tests = TRUE; + + memset(&ib, 0, sizeof(ib)); + ib.dwStructSize = sizeof(ib); + ib.lpvBuffer = buf; + + open_read_test_request(port, &req, + "HTTP/1.1 200 OK\r\n" + "Server: winetest\r\n" + "Content-Length: 100\r\n" + "\r\n" + "xyz"); + + SET_OPTIONAL(INTERNET_STATUS_RECEIVING_RESPONSE); + readex_expect_sync_data(req.request, IRF_NO_WAIT, &ib, sizeof(buf), "xyz", 0); + CLEAR_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); + + /* jump back to 2nd byte */ + pos = InternetSetFilePointer(req.request, 2, NULL, FILE_BEGIN, 0); + ok(pos == 2, "pos = %ld (gle %lu)\n", pos, GetLastError()); + + expect_data_available(req.request, 1); + readex_expect_sync_data(req.request, IRF_NO_WAIT, &ib, sizeof(buf), "z", 0); + + /* jump forward to 5th byte (not yet available) */ + pos = InternetSetFilePointer(req.request, 5, NULL, FILE_BEGIN, 0); + ok(pos == 5, "pos = %ld (gle %lu)\n", pos, GetLastError()); + + /* querying available data will wait until we have enough data */ + async_query_data_available(req.request, &read_size); + send_response_and_wait("12345", FALSE, NULL, &read_size, NULL, 3, 3, 61); + expect_data_available(req.request, 3); + + /* skip one byte and verify that we're at expected position by reading one byte */ + pos = InternetSetFilePointer(req.request, 1, NULL, FILE_CURRENT, 0); + ok(pos == 6, "pos = %ld (gle %lu)\n", pos, GetLastError()); + readex_expect_sync_data(req.request, IRF_NO_WAIT, &ib, 1, "4", 0); + + /* jump past available bytes, read will wait for available data */ + pos = InternetSetFilePointer(req.request, 2, NULL, FILE_CURRENT, 0); + ok(pos == 9, "pos = %ld (gle %lu)\n", pos, GetLastError()); + + readex_expect_async(req.request, IRF_ASYNC, &ib, 3, ""); + send_response_ex_and_wait("abcde", FALSE, &ib, "bcd", 0, 61); + + /* jump back to the beginning */ + pos = InternetSetFilePointer(req.request, 0, NULL, FILE_BEGIN, 0); + ok(pos == 0, "pos = %ld (gle %lu)\n", pos, GetLastError()); + readex_expect_sync_data(req.request, IRF_NO_WAIT, &ib, 12, "xyz12345abcd", 0); + + /* jump past the available data then send more data and close the connection */ + pos = InternetSetFilePointer(req.request, 3, NULL, FILE_CURRENT, 0); + ok(pos == 15, "pos = %ld (gle %lu)\n", pos, GetLastError()); + readex_expect_async(req.request, IRF_ASYNC, &ib, sizeof(buf), ""); + send_response_ex_and_wait("12345", TRUE, &ib, "345", 0, 61); + + SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); + SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); + close_async_handle(req.session, 2); + todo_wine + CHECK_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION); + todo_wine + CHECK_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED); + + skip_receive_notification_tests = FALSE; +} + static void test_connection_break(int port) { INTERNET_BUFFERSW ib; @@ -6559,6 +6633,7 @@ static void test_http_connection(void) test_basic_auth_credentials_cached_manual(si.port); test_async_read(si.port); test_http_read(si.port); + test_file_pointer(si.port); test_connection_break(si.port); test_long_url(si.port); test_redirect(si.port);
On Fri Feb 3 12:27:15 2023 +0000, Jacek Caban wrote:
You may just push it to your branch, something like:
git fetch git@gitlab.winehq.org:jacek/wine.git wininet-file-pointer git push -f git@gitlab.winehq.org:j20001970/wine.git FETCH_HEAD:wininet
Thanks, I updated the MR, but not sure if the failed tests are related. Can you help checking it?
On Fri Feb 3 14:58:31 2023 +0000, Jason Kuo wrote:
Thanks, I updated the MR, but not sure if the failed tests are related. Can you help checking it?
They are not related.
This merge request was approved by Jacek Caban.