Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 3 --- dlls/ntoskrnl.exe/tests/driver.c | 9 +++------ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 9 ++++++++- 3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 8e6b60e2c4..f7a3f8aced 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -721,10 +721,7 @@ static NTSTATUS dispatch_ioctl( struct dispatch_context *context ) context->in_buff = out_buff; } else - { out_buff = context->in_buff; - out_size = context->in_size; - } }
irp = IoBuildDeviceIoControlRequest( context->params.ioctl.code, device, context->in_buff, diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index 0506011ce5..67f22a4b2b 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -1777,17 +1777,14 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
static NTSTATUS test_basic_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) { - ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; + ULONG length = min(stack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(teststr)); char *buffer = irp->AssociatedIrp.SystemBuffer;
if (!buffer) return STATUS_ACCESS_VIOLATION;
- if (length < sizeof(teststr)) - return STATUS_BUFFER_TOO_SMALL; - - memcpy(buffer, teststr, sizeof(teststr)); - *info = sizeof(teststr); + memcpy(buffer, teststr, length); + *info = length;
return STATUS_SUCCESS; } diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index eb58878cec..76bcf0d0ce 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -190,8 +190,8 @@ static void main_test(void)
static void test_basic_ioctl(void) { + char inbuf[64], buf[32]; DWORD written; - char buf[32]; BOOL res;
res = DeviceIoControl(device, IOCTL_WINETEST_BASIC_IOCTL, NULL, 0, buf, @@ -199,6 +199,13 @@ static void test_basic_ioctl(void) ok(res, "DeviceIoControl failed: %u\n", GetLastError()); ok(written == sizeof(teststr), "got size %d\n", written); ok(!strcmp(buf, teststr), "got '%s'\n", buf); + + memset(buf, 0, sizeof(buf)); + res = DeviceIoControl(device, IOCTL_WINETEST_BASIC_IOCTL, inbuf, + sizeof(inbuf), buf, 10, &written, NULL); + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + ok(written == 10, "got size %d\n", written); + ok(!strcmp(buf, "Wine is no"), "got '%s'\n", buf); }
static void test_overlapped(void)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 62 ++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index c51ca8a350..41f9f15bba 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -1159,6 +1159,18 @@ static NTSTATUS http_remove_url(struct request_queue *queue, IRP *irp) return STATUS_SUCCESS; }
+static struct connection *get_connection(HTTP_REQUEST_ID req_id) +{ + struct connection *conn; + + LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) + { + if (conn->req_id == req_id) + return conn; + } + return NULL; +} + static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp) { const struct http_receive_request_params *params = irp->AssociatedIrp.SystemBuffer; @@ -1170,14 +1182,11 @@ static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp)
EnterCriticalSection(&http_cs);
- LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) + if ((conn = get_connection(params->id)) && conn->available && conn->queue == queue) { - if (conn->available && conn->queue == queue && params->id == conn->req_id) - { - ret = complete_irp(conn, irp); - LeaveCriticalSection(&http_cs); - return ret; - } + ret = complete_irp(conn, irp); + LeaveCriticalSection(&http_cs); + return ret; }
if (params->id == HTTP_NULL_ID) @@ -1203,33 +1212,30 @@ static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp)
EnterCriticalSection(&http_cs);
- LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) + if ((conn = get_connection(response->id))) { - if (conn->req_id == response->id) + if (send(conn->socket, response->buffer, response->len, 0) >= 0) { - if (send(conn->socket, response->buffer, response->len, 0) >= 0) - { - conn->queue = NULL; - conn->req_id = HTTP_NULL_ID; - WSAEventSelect(conn->socket, request_event, FD_READ | FD_CLOSE); - irp->IoStatus.Information = response->len; - /* We might have another request already in the buffer. */ - if (parse_request(conn) < 0) - { - WARN("Failed to parse request; shutting down connection.\n"); - send_400(conn); - close_connection(conn); - } - } - else + conn->queue = NULL; + conn->req_id = HTTP_NULL_ID; + WSAEventSelect(conn->socket, request_event, FD_READ | FD_CLOSE); + irp->IoStatus.Information = response->len; + /* We might have another request already in the buffer. */ + if (parse_request(conn) < 0) { - ERR("Got error %u; shutting down connection.\n", WSAGetLastError()); + WARN("Failed to parse request; shutting down connection.\n"); + send_400(conn); close_connection(conn); } - - LeaveCriticalSection(&http_cs); - return STATUS_SUCCESS; } + else + { + ERR("Got error %u; shutting down connection.\n", WSAGetLastError()); + close_connection(conn); + } + + LeaveCriticalSection(&http_cs); + return STATUS_SUCCESS; }
LeaveCriticalSection(&http_cs);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 56 +++++++++++++++++++++++++++++++++++++++++--- include/wine/http.h | 7 ++++++ 2 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index 41f9f15bba..91d81400e6 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -411,9 +411,9 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) const struct http_receive_request_params params = *(struct http_receive_request_params *)irp->AssociatedIrp.SystemBuffer; DWORD irp_size = (params.bits == 32) ? sizeof(struct http_request_32) : sizeof(struct http_request_64); + ULONG cooked_len, host_len, abs_path_len, query_len, chunk_len = 0, offset, processed; IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); const DWORD output_len = stack->Parameters.DeviceIoControl.OutputBufferLength; - ULONG cooked_len, host_len, abs_path_len, query_len, chunk_len = 0, offset; const char *p, *name, *value, *host, *abs_path, *query; USHORT unk_headers_count = 0, unk_header_idx; int name_len, value_len, len; @@ -758,8 +758,10 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) assert(offset == irp->IoStatus.Information);
conn->available = FALSE; - memmove(conn->buffer, conn->buffer + conn->req_len, conn->len - conn->req_len); - conn->len -= conn->req_len; + processed = conn->req_len - (conn->content_len - chunk_len); + memmove(conn->buffer, conn->buffer + processed, conn->len - processed); + conn->content_len -= chunk_len; + conn->len -= processed;
return STATUS_SUCCESS; } @@ -1216,6 +1218,13 @@ static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp) { if (send(conn->socket, response->buffer, response->len, 0) >= 0) { + if (conn->content_len) + { + /* Discard whatever entity body is left. */ + memmove(conn->buffer, conn->buffer + conn->content_len, conn->len - conn->content_len); + conn->len -= conn->content_len; + } + conn->queue = NULL; conn->req_id = HTTP_NULL_ID; WSAEventSelect(conn->socket, request_event, FD_READ | FD_CLOSE); @@ -1242,6 +1251,44 @@ static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp) return STATUS_CONNECTION_INVALID; }
+static NTSTATUS http_receive_body(struct request_queue *queue, IRP *irp) +{ + const struct http_receive_body_params *params = irp->AssociatedIrp.SystemBuffer; + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + const DWORD output_len = stack->Parameters.DeviceIoControl.OutputBufferLength; + struct connection *conn; + NTSTATUS ret; + + TRACE("id %s, bits %u.\n", wine_dbgstr_longlong(params->id), params->bits); + + EnterCriticalSection(&http_cs); + + if ((conn = get_connection(params->id))) + { + TRACE("%u bits remaining.\n", conn->content_len); + + if (conn->content_len) + { + ULONG len = min(conn->content_len, output_len); + memcpy(irp->AssociatedIrp.SystemBuffer, conn->buffer, len); + memmove(conn->buffer, conn->buffer + len, conn->len - len); + conn->content_len -= len; + conn->len -= len; + + irp->IoStatus.Information = len; + ret = STATUS_SUCCESS; + } + else + ret = STATUS_END_OF_FILE; + } + else + ret = STATUS_CONNECTION_INVALID; + + LeaveCriticalSection(&http_cs); + + return ret; +} + static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -1262,6 +1309,9 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_HTTP_SEND_RESPONSE: ret = http_send_response(queue, irp); break; + case IOCTL_HTTP_RECEIVE_BODY: + ret = http_receive_body(queue, irp); + break; default: FIXME("Unhandled ioctl %#x.\n", stack->Parameters.DeviceIoControl.IoControlCode); ret = STATUS_NOT_IMPLEMENTED; diff --git a/include/wine/http.h b/include/wine/http.h index eb75d8f60e..d8039dea07 100644 --- a/include/wine/http.h +++ b/include/wine/http.h @@ -27,6 +27,7 @@ #define IOCTL_HTTP_REMOVE_URL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, 0) #define IOCTL_HTTP_RECEIVE_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, 0) #define IOCTL_HTTP_SEND_RESPONSE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, 0) +#define IOCTL_HTTP_RECEIVE_BODY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, 0)
struct http_add_url_params { @@ -49,4 +50,10 @@ struct http_response char buffer[1]; };
+struct http_receive_body_params +{ + HTTP_REQUEST_ID id; + ULONG bits; +}; + #endif
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48017 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v3: fix more test failures
dlls/httpapi/httpapi_main.c | 31 ++++++++- dlls/httpapi/tests/httpapi.c | 118 ++++++++++++++++++++++++++++++++++- include/http.h | 2 + 3 files changed, 147 insertions(+), 4 deletions(-)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index 47b5d8a2bb..0449d53045 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -284,12 +284,37 @@ ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *url) ULONG WINAPI HttpReceiveRequestEntityBody(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, void *buffer, ULONG size, ULONG *ret_size, OVERLAPPED *ovl) { - *ret_size = 0; + struct http_receive_body_params params = + { + .id = id, + .bits = sizeof(void *) * 8, + }; + ULONG ret = ERROR_SUCCESS; + OVERLAPPED sync_ovl;
- FIXME("stub: queue %p, id %s, flags %#x, buffer %p, size %#x, ret_size %p, ovl %p.\n", + TRACE("queue %p, id %s, flags %#x, buffer %p, size %#x, ret_size %p, ovl %p.\n", queue, wine_dbgstr_longlong(id), flags, buffer, size, ret_size, ovl);
- return ERROR_HANDLE_EOF; + if (flags) + FIXME("Ignoring flags %#x.\n", flags); + + if (!ovl) + { + sync_ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ovl = &sync_ovl; + } + + if (!DeviceIoControl(queue, IOCTL_HTTP_RECEIVE_BODY, ¶ms, sizeof(params), buffer, size, NULL, ovl)) + ret = GetLastError(); + + if (ovl == &sync_ovl) + { + if (!GetOverlappedResult(queue, ovl, ret_size, TRUE)) + ret = GetLastError(); + CloseHandle(sync_ovl.hEvent); + } + + return ret; }
/*********************************************************************** diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c index 5c3b4ec13c..c506023ee7 100644 --- a/dlls/httpapi/tests/httpapi.c +++ b/dlls/httpapi/tests/httpapi.c @@ -546,12 +546,13 @@ static void test_v1_short_buffer(void)
static void test_v1_entity_body(void) { - char DECLSPEC_ALIGN(8) req_buffer[4096], response_buffer[2048], req_body[2048]; + char DECLSPEC_ALIGN(8) req_buffer[4096], response_buffer[2048], req_body[2048], recv_body[2000]; HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer; HTTP_RESPONSE_V1 response = {}; HTTP_DATA_CHUNK chunks[2] = {}; ULONG ret, chunk_size; unsigned int i; + OVERLAPPED ovl; DWORD ret_size; HANDLE queue; SOCKET s; @@ -571,6 +572,8 @@ static void test_v1_entity_body(void) "Content-Length: 2048\r\n" "\r\n";
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + for (i = 0; i < sizeof(req_body); ++i) req_body[i] = i / 111;
@@ -708,6 +711,119 @@ static void test_v1_entity_body(void)
send_response_v1(queue, req->RequestId, s);
+ /* Test HttpReceiveRequestEntityBody(). */ + + ret = send(s, post_req, sizeof(post_req), 0); + ok(ret == sizeof(post_req), "send() returned %d.\n", ret); + Sleep(100); + + ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + + ret = HttpReceiveRequestEntityBody(queue, HTTP_NULL_ID, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret); + + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + ok(ret_size == 5, "Got size %u.\n", ret_size); + ok(!memcmp(recv_body, "ping", 5), "Entity body didn't match.\n"); + + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(ret == ERROR_HANDLE_EOF, "Got error %u.\n", ret); + ok(ret_size == 0xdeadbeef || !ret_size /* Win10+ */, "Got size %u.\n", ret_size); + + send_response_v1(queue, req->RequestId, s); + + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret); + + ret = send(s, post_req, sizeof(post_req), 0); + ok(ret == sizeof(post_req), "send() returned %d.\n", ret); + Sleep(100); + + ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + + memset(recv_body, 0xcc, sizeof(recv_body)); + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, 2, &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + ok(ret_size == 2, "Got size %u.\n", ret_size); + ok(!memcmp(recv_body, "pi", 2), "Entity body didn't match.\n"); + + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, 4, &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + ok(ret_size == 3, "Got size %u.\n", ret_size); + ok(!memcmp(recv_body, "ng", 3), "Entity body didn't match.\n"); + + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(ret == ERROR_HANDLE_EOF, "Got error %u.\n", ret); + ok(ret_size == 0xdeadbeef || !ret_size /* Win10+ */, "Got size %u.\n", ret_size); + + send_response_v1(queue, req->RequestId, s); + + ret = send(s, post_req, sizeof(post_req), 0); + ok(ret == sizeof(post_req), "send() returned %d.\n", ret); + Sleep(100); + + ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + + memset(recv_body, 0xcc, sizeof(recv_body)); + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), NULL, &ovl); + ok(!ret || ret == ERROR_IO_PENDING, "Got error %u.\n", ret); + ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE); + ok(ret, "Got error %u.\n", GetLastError()); + ok(ret_size == 5, "Got size %u.\n", ret_size); + ok(!memcmp(recv_body, "ping", 5), "Entity body didn't match.\n"); + + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), NULL, &ovl); + ok(ret == ERROR_HANDLE_EOF, "Got error %u.\n", ret); + + send_response_v1(queue, req->RequestId, s); + + ret = send(s, post_req, sizeof(post_req), 0); + ok(ret == sizeof(post_req), "send() returned %d.\n", ret); + Sleep(100); + + ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), NULL, &ovl); + ok(ret == ERROR_HANDLE_EOF, "Got error %u.\n", ret); + + send_response_v1(queue, req->RequestId, s); + + ret = send(s, post_req2, strlen(post_req2), 0); + ok(ret == strlen(post_req2), "send() returned %d.\n", ret); + ret = send(s, req_body, sizeof(req_body), 0); + ok(ret == sizeof(req_body), "send() returned %d.\n", ret); + + Sleep(100); + + ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + (HTTP_REQUEST *)req, 2000, &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + ok(ret_size == 2000, "Got size %u.\n", ret_size); + ok(req->Flags == HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS, "Got flags %#x.\n", req->Flags); + chunk_size = req->pEntityChunks[0].FromMemory.BufferLength; + + memset(recv_body, 0xcc, sizeof(recv_body)); + ret_size = 0xdeadbeef; + ret = HttpReceiveRequestEntityBody(queue, req->RequestId, 0, recv_body, sizeof(recv_body), &ret_size, NULL); + ok(!ret, "Got error %u.\n", ret); + ok(ret_size == 2048 - chunk_size, "Got size %u.\n", ret_size); + ok(!memcmp(recv_body, req_body + chunk_size, ret_size), "Entity body didn't match.\n"); + + send_response_v1(queue, req->RequestId, s); + + CloseHandle(ovl.hEvent); ret = HttpRemoveUrl(queue, localhost_urlW); ok(!ret, "Got error %u.\n", ret); closesocket(s); diff --git a/include/http.h b/include/http.h index 49eb557fae..394167fd68 100644 --- a/include/http.h +++ b/include/http.h @@ -46,6 +46,8 @@ typedef struct _HTTPAPI_VERSION #define HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY 0x00000001 #define HTTP_RECEIVE_REQUEST_FLAG_FLUSH_BODY 0x00000002
+#define HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER 0x00000001 + #define HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS 0x00000001 #define HTTP_REQUEST_FLAG_IP_ROUTED 0x00000002 #define HTTP_REQUEST_FLAG_HTTP2 0x00000004