Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index fe5363895f6..f4b9782aa60 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -203,6 +203,8 @@ DECLARE_CRITICAL_SECTION(http_cs); static HANDLE request_thread, request_event; static BOOL thread_stop;
+static HTTP_REQUEST_ID req_id_counter; + struct connection { struct list entry; /* in "connections" below */ @@ -212,8 +214,20 @@ struct connection char *buffer; unsigned int len, size;
+ /* If there is a request fully received and waiting to be read, the + * "available" parameter will be TRUE. Either there is no queue matching + * the URL of this request yet ("queue" is NULL), there is a queue but no + * IRPs have arrived for this request yet ("queue" is non-NULL and "req_id" + * is HTTP_NULL_ID), or an IRP has arrived but did not provide a large + * enough buffer to read the whole request ("queue" is non-NULL and + * "req_id" is not HTTP_NULL_ID). + * + * If "available" is FALSE, either we are waiting for a new request + * ("req_id" is HTTP_NULL_ID), or we are waiting for the user to send a + * response ("req_id" is not HTTP_NULL_ID). */ BOOL available; struct request_queue *queue; + HTTP_REQUEST_ID req_id;
/* Things we already parsed out of the request header in parse_request(). * These are valid only if "available" is TRUE. */ @@ -406,6 +420,9 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp)
TRACE("Completing IRP %p.\n", irp);
+ if (!conn->req_id) + conn->req_id = ++req_id_counter; + /* First calculate the total buffer size needed for this IRP. */
if (conn->unk_verb_len) @@ -473,11 +490,13 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) { struct http_request_32 *req = irp->AssociatedIrp.SystemBuffer; req->ConnectionId = (ULONG_PTR)conn; + req->RequestId = conn->req_id; } else { struct http_request_64 *req = irp->AssociatedIrp.SystemBuffer; req->ConnectionId = (ULONG_PTR)conn; + req->RequestId = conn->req_id; } return STATUS_BUFFER_OVERFLOW; } @@ -492,6 +511,7 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) offset = sizeof(*req);
req->ConnectionId = (ULONG_PTR)conn; + req->RequestId = conn->req_id; req->UrlContext = conn->queue->context; req->Version = conn->version; req->Verb = conn->verb; @@ -617,6 +637,7 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) offset = sizeof(*req);
req->ConnectionId = (ULONG_PTR)conn; + req->RequestId = conn->req_id; req->UrlContext = conn->queue->context; req->Version = conn->version; req->Verb = conn->verb; @@ -906,6 +927,8 @@ static void receive_data(struct connection *conn)
if (conn->available) return; /* waiting for an HttpReceiveHttpRequest() call */ + if (conn->req_id != HTTP_NULL_ID) + return; /* waiting for an HttpSendHttpResponse() call */
TRACE("Received %u bytes of data.\n", len);
@@ -1101,7 +1124,7 @@ static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp)
LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) { - if (conn->available && conn->queue == queue) + if (conn->available && conn->queue == queue && params->id == conn->req_id) { ret = complete_irp(conn, irp); LeaveCriticalSection(&http_cs); @@ -1109,9 +1132,14 @@ static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp) } }
+ if (params->id == HTTP_NULL_ID) + ret = STATUS_PENDING; + else + ret = STATUS_CONNECTION_INVALID; + LeaveCriticalSection(&http_cs);
- return STATUS_PENDING; + return ret; }
static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index f4b9782aa60..51881ddcd59 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -243,6 +243,7 @@ static struct list connections = LIST_INIT(connections); struct request_queue { struct list entry; + LIST_ENTRY irp_queue; HTTP_URL_CONTEXT context; char *url; int socket; @@ -763,6 +764,18 @@ static NTSTATUS complete_irp(struct connection *conn, IRP *irp) return STATUS_SUCCESS; }
+/* Complete an IOCTL_HTTP_RECEIVE_REQUEST IRP if there is one to complete. */ +static void try_complete_irp(struct connection *conn) +{ + LIST_ENTRY *entry; + if (conn->queue && (entry = RemoveHeadList(&conn->queue->irp_queue)) != &conn->queue->irp_queue) + { + IRP *irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); + irp->IoStatus.Status = complete_irp(conn, irp); + IoCompleteRequest(irp, IO_NO_INCREMENT); + } +} + /* Return 1 if str matches expect, 0 if str is incomplete, -1 if they don't match. */ static int compare_exact(const char *str, const char *expect, const char *end) { @@ -902,6 +915,7 @@ static int parse_request(struct connection *conn) WSAEventSelect(conn->socket, request_event, FD_CLOSE);
conn->available = TRUE; + try_complete_irp(conn);
return 1; } @@ -1083,7 +1097,10 @@ static NTSTATUS http_add_url(struct request_queue *queue, IRP *irp) LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) { if (conn->available && !conn->queue && host_matches(conn, queue)) + { conn->queue = queue; + try_complete_irp(conn); + } }
LeaveCriticalSection(&http_cs); @@ -1133,7 +1150,11 @@ static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp) }
if (params->id == HTTP_NULL_ID) + { + TRACE("Queuing IRP %p.\n", irp); + InsertTailList(&queue->irp_queue, &irp->Tail.Overlay.ListEntry); ret = STATUS_PENDING; + } else ret = STATUS_CONNECTION_INVALID;
@@ -1182,6 +1203,7 @@ static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) if (!(queue = heap_alloc_zero(sizeof(*queue)))) return STATUS_NO_MEMORY; stack->FileObject->FsContext = queue; + InitializeListHead(&queue->irp_queue);
EnterCriticalSection(&http_cs); list_add_head(&request_queues, &queue->entry);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index 51881ddcd59..4115afc8672 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -920,6 +920,35 @@ static int parse_request(struct connection *conn) return 1; }
+static void format_date(char *buffer) +{ + static const char day_names[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + static const char month_names[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + SYSTEMTIME date; + GetSystemTime(&date); + sprintf(buffer + strlen(buffer), "Date: %s, %02u %s %u %02u:%02u:%02u GMT\r\n", + day_names[date.wDayOfWeek], date.wDay, month_names[date.wMonth - 1], + date.wYear, date.wHour, date.wMinute, date.wSecond); +} + +/* Send a 400 Bad Request response. */ +static void send_400(struct connection *conn) +{ + static const char response_header[] = "HTTP/1.1 400 Bad Request\r\n"; + static const char response_body[] = + "Content-Type: text/html; charset=utf-8\r\n" + "Content-Language: en\r\n" + "Connection: close\r\n"; + char buffer[sizeof(response_header) + sizeof(response_body) + 37]; + + strcpy(buffer, response_header); + format_date(buffer + strlen(buffer)); + strcat(buffer, response_body); + if (send(conn->socket, buffer, strlen(buffer), 0) < 0) + ERR("Failed to send 400 response, error %u.\n", WSAGetLastError()); +} + static void receive_data(struct connection *conn) { int len, ret; @@ -977,6 +1006,7 @@ static void receive_data(struct connection *conn) else if (ret < 0) { WARN("Failed to parse request; shutting down connection.\n"); + send_400(conn); close_connection(conn); } }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/httpapi/httpapi_main.c | 40 ++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index 5f2a3079341..08fbe4df65f 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -250,9 +250,43 @@ ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *urlW) ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, HTTP_REQUEST *request, ULONG size, ULONG *ret_size, OVERLAPPED *ovl) { - FIXME("queue %p, id %s, flags %#x, request %p, size %#x, ret_size %p, ovl %p, stub!\n", - queue, wine_dbgstr_longlong(id), flags, request, size, ret_size, ovl); - return ERROR_CALL_NOT_IMPLEMENTED; + struct http_receive_request_params params = + { + .addr = (ULONG_PTR)request, + .id = id, + .flags = flags, + .bits = sizeof(void *) * 8, + }; + ULONG ret = ERROR_SUCCESS; + OVERLAPPED sync_ovl; + + TRACE("queue %p, id %s, flags %#x, request %p, size %#x, ret_size %p, ovl %p.\n", + queue, wine_dbgstr_longlong(id), flags, request, size, ret_size, ovl); + + if (flags & ~HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY) + FIXME("Ignoring flags %#x.\n", flags & ~HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY); + + if (size < sizeof(HTTP_REQUEST_V1)) + return ERROR_INSUFFICIENT_BUFFER; + + if (!ovl) + { + sync_ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ovl = &sync_ovl; + } + + if (!DeviceIoControl(queue, IOCTL_HTTP_RECEIVE_REQUEST, ¶ms, sizeof(params), request, size, NULL, ovl)) + ret = GetLastError(); + + if (ovl == &sync_ovl) + { + ret = ERROR_SUCCESS; + if (!GetOverlappedResult(queue, ovl, ret_size, TRUE)) + ret = GetLastError(); + CloseHandle(sync_ovl.hEvent); + } + + return ret; }
/***********************************************************************
Zebediah Figura z.figura12@gmail.com wrote:
- struct http_receive_request_params params =
- {
.addr = (ULONG_PTR)request,
.id = id,
.flags = flags,
.bits = sizeof(void *) * 8,
- };
Please don't do this, it won't build with some compilers.
On 8/27/19 8:54 PM, Dmitry Timoshkov wrote:
Zebediah Figura z.figura12@gmail.com wrote:
- struct http_receive_request_params params =
- {
.addr = (ULONG_PTR)request,
.id = id,
.flags = flags,
.bits = sizeof(void *) * 8,
- };
Please don't do this, it won't build with some compilers.
Do you mean the use of designated initializers? We've had those in the code base for over 6 years:
https://source.winehq.org/git/wine.git/commitdiff/cf0334b6542 https://source.winehq.org/git/wine.git/commitdiff/0fa08f47937e
Do you have a concrete example of a compiler that doesn't recognize these?
Zebediah Figura z.figura12@gmail.com wrote:
- struct http_receive_request_params params =
- {
.addr = (ULONG_PTR)request,
.id = id,
.flags = flags,
.bits = sizeof(void *) * 8,
- };
Please don't do this, it won't build with some compilers.
Do you mean the use of designated initializers?
Yes. It's pretty easy to avoid it, and there's no any real need to abuse this kind of strange syntax.
We've had those in the code base for over 6 years:
https://source.winehq.org/git/wine.git/commitdiff/cf0334b6542 https://source.winehq.org/git/wine.git/commitdiff/0fa08f47937e
Looks like this slipped through somehow.
Do you have a concrete example of a compiler that doesn't recognize these?
PSDK compiler chokes on it, and I already had to patch locally that windowscodecs test in order to build it.
On 8/28/19 5:00 AM, Dmitry Timoshkov wrote:
Zebediah Figura z.figura12@gmail.com wrote:
- struct http_receive_request_params params =
- {
.addr = (ULONG_PTR)request,
.id = id,
.flags = flags,
.bits = sizeof(void *) * 8,
- };
Please don't do this, it won't build with some compilers.
Do you mean the use of designated initializers?
Yes. It's pretty easy to avoid it, and there's no any real need to abuse this kind of strange syntax.
We've had those in the code base for over 6 years:
https://source.winehq.org/git/wine.git/commitdiff/cf0334b6542 https://source.winehq.org/git/wine.git/commitdiff/0fa08f47937e
Looks like this slipped through somehow.
Do you have a concrete example of a compiler that doesn't recognize these?
PSDK compiler chokes on it, and I already had to patch locally that windowscodecs test in order to build it.
It would have been nice to mention it before, then, because I've been using it rather extensively in quartz. In this instance I suppose one could just as easily use a series of decalarations, but I find designated initializers to be much easier to work with than non-designated initializers, as one does not need to remember the order of the fields, or change its users when the structure declaration changes, or add a large number of 0/NULL entries for sparsely initialized structures.
For what it's worth, support for designated initializers was introduced in Visual Studio 2013, and the cl.exe shipped with the Windows 10 SDK supports them.