Signed-off-by: Daniel Lehman dlehman25@gmail.com
--- not sure how to add a permanent standalone test for this because of how long it runs, but i tested it locally:
1) create a file > 4GB: sudo dd if=/dev/zero of=/var/lib/tomcat8/webapps/ROOT/6GBFILE bs=1G count=6
2) add wininet test (run on Ubuntu 18.04.3 and Win10 1903): - wine/dlls/wininet/tests/http.c
static void test_large_file(void) { BOOL res; DWORD nread; DWORD64 sum; HINTERNET session; HINTERNET request; HINTERNET connection; const char *types[2] = { "*", NULL }; char buffer[65536] = {0};
session = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); ok(!!session, "failed gle %d\n", GetLastError());
connection = InternetConnectA(session, "192.168.2.242", 8080, NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef); ok(!!connection, "failed gle %d\n", GetLastError());
request = HttpOpenRequestA(connection, "GET", "/6GBFILE", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD, 0xdeadbead); ok(!!request, "failed gle %d\n", GetLastError());
res = HttpSendRequestA(request, "", -1, NULL, 0); ok(res, "failed gle %d\n", GetLastError());
sum = 0; nread = 0; do { res = InternetReadFile(request, buffer, sizeof(buffer), &nread); ok(res, "failed gle %d\n", GetLastError()); sum += nread; } while (nread > 0); ok(sum == (DWORD64)0x180000000, "failed to read all bytes: %x%08x\n", (DWORD)(sum >> 32), (DWORD)sum);
InternetCloseHandle(request); InternetCloseHandle(connection); InternetCloseHandle(session); }
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/wininet/http.c | 28 ++++++++++++++++++---------- dlls/wininet/internet.h | 6 +++--- 2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 538fc2bf6b..871418e2e3 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -2440,7 +2440,7 @@ static void create_cache_entry(http_request_t *req) return; }
- b = CreateUrlCacheEntryW(url, req->contentLength == ~0u ? 0 : req->contentLength, NULL, file_name, 0); + b = CreateUrlCacheEntryW(url, req->contentLength == ~0 ? 0 : req->contentLength, NULL, file_name, 0); if(!b) { WARN("Could not create cache entry: %08x\n", GetLastError()); return; @@ -2644,7 +2644,7 @@ static DWORD netconn_drain_content(data_stream_t *stream, http_request_t *req, B int len, res; size_t size;
- if(netconn_stream->content_length == ~0u) + if(netconn_stream->content_length == ~0) return WSAEISCONN;
while(netconn_stream->content_read < netconn_stream->content_length) { @@ -2750,7 +2750,7 @@ static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, TRACE("reading %u byte chunk\n", chunked_stream->chunk_size); chunked_stream->buf_size++; chunked_stream->buf_pos--; - if(req->contentLength == ~0u) req->contentLength = chunked_stream->chunk_size; + if(req->contentLength == ~0) req->contentLength = chunked_stream->chunk_size; else req->contentLength += chunked_stream->chunk_size; chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE; } @@ -2883,7 +2883,7 @@ static DWORD set_content_length(http_request_t *request) size = sizeof(request->contentLength); if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &request->contentLength, &size, NULL) != ERROR_SUCCESS) - request->contentLength = ~0u; + request->contentLength = ~0; request->netconn_stream.content_length = request->contentLength; request->netconn_stream.content_read = request->read_size;
@@ -2909,7 +2909,7 @@ static DWORD set_content_length(http_request_t *request) }
request->data_stream = &chunked_stream->data_stream; - request->contentLength = ~0u; + request->contentLength = ~0; }
if(request->hdr.decoding) { @@ -3299,7 +3299,7 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session, request->hdr.dwFlags = dwFlags; request->hdr.dwContext = dwContext; request->hdr.decoding = session->hdr.decoding; - request->contentLength = ~0u; + request->contentLength = ~0;
request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl; request->data_stream = &request->netconn_stream.data_stream; @@ -3724,9 +3724,17 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, /* coalesce value to requested type */ if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) { - *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); - TRACE(" returning number: %d\n", *(int *)lpBuffer); - } + if (*lpdwBufferLength == sizeof(ULONGLONG)) + { + *(ULONGLONG *)lpBuffer = strtoulW(lphttpHdr->lpszValue, NULL, 10); + TRACE(" returning number: %s\n", wine_dbgstr_longlong(*(ULONGLONG *)lpBuffer)); + } + else + { + *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); + TRACE(" returning number: %d\n", *(int *)lpBuffer); + } + } else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) { time_t tmpTime; @@ -4907,7 +4915,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, loop_next = FALSE;
if(redirected) { - request->contentLength = ~0u; + request->contentLength = ~0; request->bytesToWrite = 0; }
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index f712fb6b64..40e51bec32 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -335,8 +335,8 @@ typedef struct {
typedef struct { data_stream_t data_stream; - DWORD content_length; - DWORD content_read; + ULONGLONG content_length; + ULONGLONG content_read; } netconn_stream_t;
#define READ_BUFFER_SIZE 8192 @@ -372,7 +372,7 @@ typedef struct struct HttpAuthInfo *proxyAuthInfo;
CRITICAL_SECTION read_section; /* section to protect the following fields */ - DWORD contentLength; /* total number of bytes to be read */ + ULONGLONG contentLength; /* total number of bytes to be read */ 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 */
Daniel Lehman dlehman25@gmail.com writes:
@@ -3724,9 +3724,17 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, /* coalesce value to requested type */ if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) {
*(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
TRACE(" returning number: %d\n", *(int *)lpBuffer);
}
if (*lpdwBufferLength == sizeof(ULONGLONG))
{
*(ULONGLONG *)lpBuffer = strtoulW(lphttpHdr->lpszValue, NULL, 10);
TRACE(" returning number: %s\n", wine_dbgstr_longlong(*(ULONGLONG *)lpBuffer));
strtoulW won't do what you want on 32-bit platforms.
strtoulW won't do what you want on 32-bit platforms.
looks like even 64-bit windows (at least win10) errors if anything but DWORD-size is passed in. and it fails on overflow if Content-Length exceeds sizeof(DWORD). i'll update and resend
thanks daniel
Hi Daniel,
On 8/20/19 6:26 AM, Daniel Lehman wrote:
Signed-off-by: Daniel Lehman dlehman25@gmail.com
not sure how to add a permanent standalone test for this because of how long it runs, but i tested it locally:
Note that you don't need to send actual 4 GB to test it. If you sent http headers (and maybe a chunk of data), it should be enough. We have an emulated server in tests that you could use. open_socket_request() will probably be useful.
Thanks,
Jacek
Note that you don't need to send actual 4 GB to test it. If you sent http headers (and maybe a chunk of data), it should be enough. We have an emulated server in tests that you could use. open_socket_request() will probably be useful.
the return from HttpQueryInfo is separate from being able to download a huge file. i'll separate them
thanks daniel