[PATCH 4/5] http.sys: Allow receiving parsed HTTP requests.

Zebediah Figura z.figura12 at gmail.com
Fri Aug 23 17:36:18 CDT 2019


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/http.sys/http.c | 199 +++++++++++++++++++++++++++++++++++++++++++
 include/wine/http.h  |   9 ++
 2 files changed, 208 insertions(+)

diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c
index 4b83cc68d3..a41b464a72 100644
--- a/dlls/http.sys/http.c
+++ b/dlls/http.sys/http.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <assert.h>
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "wine/http.h"
@@ -32,6 +33,108 @@ static DEVICE_OBJECT *device_obj;
 
 WINE_DEFAULT_DEBUG_CHANNEL(http);
 
+/* We have to return the HTTP_REQUEST structure to userspace exactly as it will
+ * be consumed; httpapi has no opportunity to massage it. Since it contains
+ * pointers, this is somewhat nontrivial. */
+
+struct http_request_32
+{
+    ULONG Flags;
+    HTTP_CONNECTION_ID ConnectionId;
+    HTTP_REQUEST_ID RequestId;
+    HTTP_URL_CONTEXT UrlContext;
+    HTTP_VERSION Version;
+    HTTP_VERB Verb;
+    USHORT UnknownVerbLength;
+    USHORT RawUrlLength;
+    ULONG pUnknownVerb; /* char string */
+    ULONG pRawUrl; /* char string */
+    struct
+    {
+        USHORT FullUrlLength;
+        USHORT HostLength;
+        USHORT AbsPathLength;
+        USHORT QueryStringLength;
+        ULONG pFullUrl; /* WCHAR string */
+        ULONG pHost; /* pointer to above */
+        ULONG pAbsPath; /* pointer to above */
+        ULONG pQueryString; /* pointer to above */
+    } CookedUrl;
+    struct
+    {
+        ULONG pRemoteAddress; /* SOCKADDR */
+        ULONG pLocalAddress; /* SOCKADDR */
+    } Address;
+    struct
+    {
+        USHORT UnknownHeaderCount;
+        ULONG pUnknownHeaders; /* struct http_unknown_header_32 */
+        USHORT TrailerCount;
+        ULONG pTrailers; /* NULL */
+        struct
+        {
+            USHORT RawValueLength;
+            ULONG pRawValue; /* char string */
+        } KnownHeaders[HttpHeaderRequestMaximum];
+    } Headers;
+    ULONGLONG BytesReceived;
+    USHORT EntityChunkCount;
+    ULONG pEntityChunks; /* struct http_data_chunk_32 */
+    HTTP_RAW_CONNECTION_ID RawConnectionId;
+    ULONG pSslInfo; /* NULL (FIXME) */
+    USHORT RequestInfoCount;
+    ULONG pRequestInfo; /* NULL (FIXME) */
+};
+
+struct http_request_64
+{
+    ULONG Flags;
+    HTTP_CONNECTION_ID ConnectionId;
+    HTTP_REQUEST_ID RequestId;
+    HTTP_URL_CONTEXT UrlContext;
+    HTTP_VERSION Version;
+    HTTP_VERB Verb;
+    USHORT UnknownVerbLength;
+    USHORT RawUrlLength;
+    ULONGLONG pUnknownVerb; /* char string */
+    ULONGLONG pRawUrl; /* char string */
+    struct
+    {
+        USHORT FullUrlLength;
+        USHORT HostLength;
+        USHORT AbsPathLength;
+        USHORT QueryStringLength;
+        ULONGLONG pFullUrl; /* WCHAR string */
+        ULONGLONG pHost; /* pointer to above */
+        ULONGLONG pAbsPath; /* pointer to above */
+        ULONGLONG pQueryString; /* pointer to above */
+    } CookedUrl;
+    struct
+    {
+        ULONGLONG pRemoteAddress; /* SOCKADDR */
+        ULONGLONG pLocalAddress; /* SOCKADDR */
+    } Address;
+    struct
+    {
+        USHORT UnknownHeaderCount;
+        ULONGLONG pUnknownHeaders; /* struct http_unknown_header_32 */
+        USHORT TrailerCount;
+        ULONGLONG pTrailers; /* NULL */
+        struct
+        {
+            USHORT RawValueLength;
+            ULONGLONG pRawValue; /* char string */
+        } KnownHeaders[HttpHeaderRequestMaximum];
+    } Headers;
+    ULONGLONG BytesReceived;
+    USHORT EntityChunkCount;
+    ULONGLONG pEntityChunks; /* struct http_data_chunk_32 */
+    HTTP_RAW_CONNECTION_ID RawConnectionId;
+    ULONGLONG pSslInfo; /* NULL (FIXME) */
+    USHORT RequestInfoCount;
+    ULONGLONG pRequestInfo; /* NULL (FIXME) */
+};
+
 #define DECLARE_CRITICAL_SECTION(cs) \
     static CRITICAL_SECTION cs; \
     static CRITICAL_SECTION_DEBUG cs##_debug = \
@@ -161,6 +264,73 @@ static int parse_token(const char *str, const char *end)
     return p - str;
 }
 
+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);
+    IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
+    const DWORD output_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
+    ULONG offset;
+
+    TRACE("Completing IRP %p.\n", irp);
+
+    /* First calculate the total buffer size needed for this IRP. */
+
+    TRACE("Need %u bytes, have %u.\n", irp_size, output_len);
+    irp->IoStatus.Information = irp_size;
+
+    memset(irp->AssociatedIrp.SystemBuffer, 0, output_len);
+
+    if (output_len < irp_size)
+    {
+        if (params.bits == 32)
+        {
+            struct http_request_32 *req = irp->AssociatedIrp.SystemBuffer;
+            req->ConnectionId = (ULONG_PTR)conn;
+        }
+        else
+        {
+            struct http_request_64 *req = irp->AssociatedIrp.SystemBuffer;
+            req->ConnectionId = (ULONG_PTR)conn;
+        }
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    if (params.bits == 32)
+    {
+        struct http_request_32 *req = irp->AssociatedIrp.SystemBuffer;
+
+        offset = sizeof(*req);
+
+        req->ConnectionId = (ULONG_PTR)conn;
+        req->UrlContext = conn->queue->context;
+        req->Version = conn->version;
+        req->Verb = conn->verb;
+        req->BytesReceived = conn->req_len;
+    }
+    else
+    {
+        struct http_request_64 *req = irp->AssociatedIrp.SystemBuffer;
+
+        offset = sizeof(*req);
+
+        req->ConnectionId = (ULONG_PTR)conn;
+        req->UrlContext = conn->queue->context;
+        req->Version = conn->version;
+        req->Verb = conn->verb;
+        req->BytesReceived = conn->req_len;
+    }
+
+    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;
+
+    return STATUS_SUCCESS;
+}
+
 /* 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)
 {
@@ -507,6 +677,32 @@ static NTSTATUS http_remove_url(struct request_queue *queue, IRP *irp)
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp)
+{
+    const struct http_receive_request_params *params = irp->AssociatedIrp.SystemBuffer;
+    struct connection *conn;
+    NTSTATUS ret;
+
+    TRACE("addr %s, id %s, flags %#x, bits %u.\n", wine_dbgstr_longlong(params->addr),
+            wine_dbgstr_longlong(params->id), params->flags, params->bits);
+
+    EnterCriticalSection(&http_cs);
+
+    LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry)
+    {
+        if (conn->available && conn->queue == queue)
+        {
+            ret = complete_irp(conn, irp);
+            LeaveCriticalSection(&http_cs);
+            return ret;
+        }
+    }
+
+    LeaveCriticalSection(&http_cs);
+
+    return STATUS_PENDING;
+}
+
 static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp)
 {
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
@@ -521,6 +717,9 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp)
     case IOCTL_HTTP_REMOVE_URL:
         ret = http_remove_url(queue, irp);
         break;
+    case IOCTL_HTTP_RECEIVE_REQUEST:
+        ret = http_receive_request(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 354c289387..1145cab71a 100644
--- a/include/wine/http.h
+++ b/include/wine/http.h
@@ -25,6 +25,7 @@
 
 #define IOCTL_HTTP_ADD_URL          CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, 0)
 #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)
 
 struct http_add_url_params
 {
@@ -32,4 +33,12 @@ struct http_add_url_params
     char url[1];
 };
 
+struct http_receive_request_params
+{
+    ULONGLONG addr; /* user-mode buffer address */
+    HTTP_REQUEST_ID id;
+    ULONG flags;
+    ULONG bits;
+};
+
 #endif
-- 
2.22.0




More information about the wine-devel mailing list