[PATCH] http.sys: Use a separate file and preprocessor directives to avoid duplication.

Zebediah Figura z.figura12 at gmail.com
Thu May 7 18:47:21 CDT 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/http.sys/http.c    | 531 ++--------------------------------------
 dlls/http.sys/request.h | 310 +++++++++++++++++++++++
 2 files changed, 336 insertions(+), 505 deletions(-)
 create mode 100644 dlls/http.sys/request.h

diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c
index 46590f972f..31c7fc0971 100644
--- a/dlls/http.sys/http.c
+++ b/dlls/http.sys/http.c
@@ -33,164 +33,6 @@ 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_unknown_header_32
-{
-    USHORT NameLength;
-    USHORT RawValueLength;
-    ULONG pName; /* char string */
-    ULONG pRawValue; /* char string */
-};
-
-struct http_data_chunk_32
-{
-    HTTP_DATA_CHUNK_TYPE DataChunkType;
-    union
-    {
-        struct
-        {
-            ULONG pBuffer; /* char string */
-            ULONG BufferLength;
-        } FromMemory;
-        /* for the struct size */
-        struct
-        {
-            ULARGE_INTEGER StartingOffset;
-            ULARGE_INTEGER Length;
-            HANDLE FileHandle;
-        } FromFileHandle;
-    };
-};
-
-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_unknown_header_64
-{
-    USHORT NameLength;
-    USHORT RawValueLength;
-    ULONGLONG pName; /* char string */
-    ULONGLONG pRawValue; /* char string */
-};
-
-struct http_data_chunk_64
-{
-    HTTP_DATA_CHUNK_TYPE DataChunkType;
-    union
-    {
-        struct
-        {
-            ULONGLONG pBuffer; /* char string */
-            ULONG BufferLength;
-        } FromMemory;
-        /* for the struct size */
-        struct
-        {
-            ULARGE_INTEGER StartingOffset;
-            ULARGE_INTEGER Length;
-            HANDLE FileHandle;
-        } FromFileHandle;
-    };
-};
-
-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 = \
@@ -405,365 +247,44 @@ static void parse_header(const char *name, int *name_len, const char **value, in
     *value_len = p - *value + 1;
 }
 
+#define http_unknown_header http_unknown_header_64
+#define http_data_chunk http_data_chunk_64
+#define http_request http_request_64
+#define complete_irp complete_irp_64
+#define POINTER ULONGLONG
+#include "request.h"
+#undef http_unknown_header
+#undef http_data_chunk
+#undef http_request
+#undef complete_irp
+#undef POINTER
+
+#define http_unknown_header http_unknown_header_32
+#define http_data_chunk http_data_chunk_32
+#define http_request http_request_32
+#define complete_irp complete_irp_32
+#define POINTER ULONG
+#include "request.h"
+#undef http_unknown_header
+#undef http_data_chunk
+#undef http_request
+#undef complete_irp
+#undef POINTER
+
 static NTSTATUS complete_irp(struct connection *conn, IRP *irp)
 {
-    static const WCHAR httpW[] = {'h','t','t','p',':','/','/'};
     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;
-    const char *p, *name, *value, *host, *abs_path, *query;
-    USHORT unk_headers_count = 0, unk_header_idx;
-    int name_len, value_len, len;
-    struct sockaddr_in addr;
 
     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)
-        irp_size += conn->unk_verb_len + 1;
-    irp_size += conn->url_len + 1;
-
-    /* cooked URL */
-    if (conn->url[0] == '/')
-    {
-        p = host = conn->host;
-        while (isgraph(*p)) ++p;
-        host_len = p - conn->host;
-        abs_path = conn->url;
-        abs_path_len = conn->url_len;
-    }
-    else
-    {
-        host = conn->url + 7;
-        abs_path = strchr(host, '/');
-        host_len = abs_path - host;
-        abs_path_len = (conn->url + conn->url_len) - abs_path;
-    }
-    if ((query = memchr(abs_path, '?', abs_path_len)))
-    {
-        query_len = (abs_path + abs_path_len) - query;
-        abs_path_len = query - abs_path;
-    }
-    else
-        query_len = 0;
-    cooked_len = (7 /* scheme */ + host_len + abs_path_len + query_len) * sizeof(WCHAR);
-    irp_size += cooked_len + sizeof(WCHAR);
-
-    /* addresses */
-    irp_size += 2 * sizeof(addr);
-
-    /* headers */
-    p = strstr(conn->buffer, "\r\n") + 2;
-    while (memcmp(p, "\r\n", 2))
-    {
-        name = p;
-        parse_header(name, &name_len, &value, &value_len);
-        if (parse_header_name(name, name_len) == HttpHeaderRequestMaximum)
-        {
-            irp_size += name_len + 1;
-            ++unk_headers_count;
-        }
-        irp_size += value_len + 1;
-        p = strstr(p, "\r\n") + 2;
-    }
-    p += 2;
-
     if (params.bits == 32)
-        irp_size += unk_headers_count * sizeof(struct http_unknown_header_32);
+        return complete_irp_32(conn, irp);
     else
-        irp_size += unk_headers_count * sizeof(struct http_unknown_header_64);
-
-    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;
-            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;
-    }
-
-    if (params.bits == 32)
-    {
-        struct http_request_32 *req = irp->AssociatedIrp.SystemBuffer;
-        struct http_unknown_header_32 *unk_headers = NULL;
-        char *buffer = irp->AssociatedIrp.SystemBuffer;
-        struct http_data_chunk_32 *chunk = NULL;
-
-        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;
-        req->UnknownVerbLength = conn->unk_verb_len;
-        req->RawUrlLength = conn->url_len;
-
-        if (conn->unk_verb_len)
-        {
-            req->pUnknownVerb = params.addr + offset;
-            memcpy(buffer + offset, conn->buffer, conn->unk_verb_len);
-            offset += conn->unk_verb_len;
-            buffer[offset++] = 0;
-        }
-
-        req->pRawUrl = params.addr + offset;
-        memcpy(buffer + offset, conn->url, conn->url_len);
-        offset += conn->url_len;
-        buffer[offset++] = 0;
-
-        req->CookedUrl.FullUrlLength = cooked_len;
-        req->CookedUrl.HostLength = host_len * sizeof(WCHAR);
-        req->CookedUrl.AbsPathLength = abs_path_len * sizeof(WCHAR);
-        req->CookedUrl.QueryStringLength = query_len * sizeof(WCHAR);
-        req->CookedUrl.pFullUrl = params.addr + offset;
-        req->CookedUrl.pHost = req->CookedUrl.pFullUrl + 7 * sizeof(WCHAR);
-        req->CookedUrl.pAbsPath = req->CookedUrl.pHost + host_len * sizeof(WCHAR);
-        if (query)
-            req->CookedUrl.pQueryString = req->CookedUrl.pAbsPath + abs_path_len * sizeof(WCHAR);
-
-        memcpy(buffer + offset, httpW, sizeof(httpW));
-        offset += 7 * sizeof(WCHAR);
-        MultiByteToWideChar(CP_ACP, 0, host, host_len, (WCHAR *)(buffer + offset), host_len * sizeof(WCHAR));
-        offset += host_len * sizeof(WCHAR);
-        MultiByteToWideChar(CP_ACP, 0, abs_path, abs_path_len + query_len,
-                (WCHAR *)(buffer + offset), (abs_path_len + query_len) * sizeof(WCHAR));
-        offset += (abs_path_len + query_len) * sizeof(WCHAR);
-        buffer[offset++] = 0;
-        buffer[offset++] = 0;
-
-        req->Address.pRemoteAddress = params.addr + offset;
-        len = sizeof(addr);
-        getpeername(conn->socket, (struct sockaddr *)&addr, &len);
-        memcpy(buffer + offset, &addr, sizeof(addr));
-        offset += sizeof(addr);
-
-        req->Address.pLocalAddress = params.addr + offset;
-        len = sizeof(addr);
-        getsockname(conn->socket, (struct sockaddr *)&addr, &len);
-        memcpy(buffer + offset, &addr, sizeof(addr));
-        offset += sizeof(addr);
-
-        req->Headers.UnknownHeaderCount = unk_headers_count;
-        if (unk_headers_count)
-        {
-            req->Headers.pUnknownHeaders = params.addr + offset;
-            unk_headers = (struct http_unknown_header_32 *)(buffer + offset);
-            offset += unk_headers_count * sizeof(*unk_headers);
-        }
-
-        unk_header_idx = 0;
-        p = strstr(conn->buffer, "\r\n") + 2;
-        while (memcmp(p, "\r\n", 2))
-        {
-            HTTP_HEADER_ID id;
-
-            name = p;
-            parse_header(name, &name_len, &value, &value_len);
-            if ((id = parse_header_name(name, name_len)) == HttpHeaderRequestMaximum)
-            {
-                unk_headers[unk_header_idx].NameLength = name_len;
-                unk_headers[unk_header_idx].RawValueLength = value_len;
-                unk_headers[unk_header_idx].pName = params.addr + offset;
-                memcpy(buffer + offset, name, name_len);
-                offset += name_len;
-                buffer[offset++] = 0;
-                unk_headers[unk_header_idx].pRawValue = params.addr + offset;
-                memcpy(buffer + offset, value, value_len);
-                offset += value_len;
-                buffer[offset++] = 0;
-                ++unk_header_idx;
-            }
-            else
-            {
-                req->Headers.KnownHeaders[id].RawValueLength = value_len;
-                req->Headers.KnownHeaders[id].pRawValue = params.addr + offset;
-                memcpy(buffer + offset, value, value_len);
-                offset += value_len;
-                buffer[offset++] = 0;
-            }
-            p = strstr(p, "\r\n") + 2;
-        }
-        p += 2;
-
-        if (irp_size + sizeof(*chunk) < output_len && (params.flags & HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY))
-            chunk_len = min(conn->content_len, output_len - (irp_size + sizeof(*chunk)));
-        if (chunk_len)
-        {
-            req->EntityChunkCount = 1;
-            req->pEntityChunks = params.addr + offset;
-            chunk = (struct http_data_chunk_32 *)(buffer + offset);
-            offset += sizeof(*chunk);
-            chunk->DataChunkType = HttpDataChunkFromMemory;
-            chunk->FromMemory.BufferLength = chunk_len;
-            chunk->FromMemory.pBuffer = params.addr + offset;
-            memcpy(buffer + offset, p, chunk_len);
-            offset += chunk_len;
-
-            irp->IoStatus.Information = irp_size + sizeof(*chunk) + chunk_len;
-        }
-
-        if (chunk_len < conn->content_len)
-            req->Flags |= HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
-
-        req->BytesReceived = conn->req_len;
-    }
-    else
-    {
-        struct http_request_64 *req = irp->AssociatedIrp.SystemBuffer;
-        struct http_unknown_header_64 *unk_headers = NULL;
-        char *buffer = irp->AssociatedIrp.SystemBuffer;
-        struct http_data_chunk_64 *chunk = NULL;
-
-        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;
-        req->UnknownVerbLength = conn->unk_verb_len;
-        req->RawUrlLength = conn->url_len;
-
-        if (conn->unk_verb_len)
-        {
-            req->pUnknownVerb = params.addr + offset;
-            memcpy(buffer + offset, conn->buffer, conn->unk_verb_len);
-            offset += conn->unk_verb_len;
-            buffer[offset++] = 0;
-        }
-
-        req->pRawUrl = params.addr + offset;
-        memcpy(buffer + offset, conn->url, conn->url_len);
-        offset += conn->url_len;
-        buffer[offset++] = 0;
-
-        req->CookedUrl.FullUrlLength = cooked_len;
-        req->CookedUrl.HostLength = host_len * sizeof(WCHAR);
-        req->CookedUrl.AbsPathLength = abs_path_len * sizeof(WCHAR);
-        req->CookedUrl.QueryStringLength = query_len * sizeof(WCHAR);
-        req->CookedUrl.pFullUrl = params.addr + offset;
-        req->CookedUrl.pHost = req->CookedUrl.pFullUrl + 7 * sizeof(WCHAR);
-        req->CookedUrl.pAbsPath = req->CookedUrl.pHost + host_len * sizeof(WCHAR);
-        if (query)
-            req->CookedUrl.pQueryString = req->CookedUrl.pAbsPath + abs_path_len * sizeof(WCHAR);
-
-        memcpy(buffer + offset, httpW, sizeof(httpW));
-        offset += 7 * sizeof(WCHAR);
-        MultiByteToWideChar(CP_ACP, 0, host, host_len, (WCHAR *)(buffer + offset), host_len * sizeof(WCHAR));
-        offset += host_len * sizeof(WCHAR);
-        MultiByteToWideChar(CP_ACP, 0, abs_path, abs_path_len + query_len,
-                (WCHAR *)(buffer + offset), (abs_path_len + query_len) * sizeof(WCHAR));
-        offset += (abs_path_len + query_len) * sizeof(WCHAR);
-        buffer[offset++] = 0;
-        buffer[offset++] = 0;
-
-        req->Address.pRemoteAddress = params.addr + offset;
-        len = sizeof(addr);
-        getpeername(conn->socket, (struct sockaddr *)&addr, &len);
-        memcpy(buffer + offset, &addr, sizeof(addr));
-        offset += sizeof(addr);
-
-        req->Address.pLocalAddress = params.addr + offset;
-        len = sizeof(addr);
-        getsockname(conn->socket, (struct sockaddr *)&addr, &len);
-        memcpy(buffer + offset, &addr, sizeof(addr));
-        offset += sizeof(addr);
-
-        req->Headers.UnknownHeaderCount = unk_headers_count;
-        if (unk_headers_count)
-        {
-            req->Headers.pUnknownHeaders = params.addr + offset;
-            unk_headers = (struct http_unknown_header_64 *)(buffer + offset);
-            offset += unk_headers_count * sizeof(*unk_headers);
-        }
-
-        unk_header_idx = 0;
-        p = strstr(conn->buffer, "\r\n") + 2;
-        while (memcmp(p, "\r\n", 2))
-        {
-            HTTP_HEADER_ID id;
-
-            name = p;
-            parse_header(name, &name_len, &value, &value_len);
-            if ((id = parse_header_name(name, name_len)) == HttpHeaderRequestMaximum)
-            {
-                unk_headers[unk_header_idx].NameLength = name_len;
-                unk_headers[unk_header_idx].RawValueLength = value_len;
-                unk_headers[unk_header_idx].pName = params.addr + offset;
-                memcpy(buffer + offset, name, name_len);
-                offset += name_len;
-                buffer[offset++] = 0;
-                unk_headers[unk_header_idx].pRawValue = params.addr + offset;
-                memcpy(buffer + offset, value, value_len);
-                offset += value_len;
-                buffer[offset++] = 0;
-                ++unk_header_idx;
-            }
-            else
-            {
-                req->Headers.KnownHeaders[id].RawValueLength = value_len;
-                req->Headers.KnownHeaders[id].pRawValue = params.addr + offset;
-                memcpy(buffer + offset, value, value_len);
-                offset += value_len;
-                buffer[offset++] = 0;
-            }
-            p = strstr(p, "\r\n") + 2;
-        }
-        p += 2;
-
-        if (irp_size + sizeof(*chunk) < output_len && (params.flags & HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY))
-            chunk_len = min(conn->content_len, output_len - (irp_size + sizeof(*chunk)));
-        if (chunk_len)
-        {
-            req->EntityChunkCount = 1;
-            req->pEntityChunks = params.addr + offset;
-            chunk = (struct http_data_chunk_64 *)(buffer + offset);
-            offset += sizeof(*chunk);
-            chunk->DataChunkType = HttpDataChunkFromMemory;
-            chunk->FromMemory.BufferLength = chunk_len;
-            chunk->FromMemory.pBuffer = params.addr + offset;
-            memcpy(buffer + offset, p, chunk_len);
-            offset += chunk_len;
-
-            irp->IoStatus.Information = irp_size + sizeof(*chunk) + chunk_len;
-        }
-
-        if (chunk_len < conn->content_len)
-            req->Flags |= HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
-
-        req->BytesReceived = conn->req_len;
-    }
-
-    assert(offset == irp->IoStatus.Information);
-
-    conn->available = FALSE;
-    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;
+        return complete_irp_64(conn, irp);
 }
 
 /* Complete an IOCTL_HTTP_RECEIVE_REQUEST IRP if there is one to complete. */
diff --git a/dlls/http.sys/request.h b/dlls/http.sys/request.h
new file mode 100644
index 0000000000..a1b77b67dc
--- /dev/null
+++ b/dlls/http.sys/request.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2019 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* 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_unknown_header
+{
+    USHORT NameLength;
+    USHORT RawValueLength;
+    POINTER pName; /* char string */
+    POINTER pRawValue; /* char string */
+};
+
+struct http_data_chunk
+{
+    HTTP_DATA_CHUNK_TYPE DataChunkType;
+    union
+    {
+        struct
+        {
+            POINTER pBuffer; /* char string */
+            ULONG BufferLength;
+        } FromMemory;
+        /* for the struct size */
+        struct
+        {
+            ULARGE_INTEGER StartingOffset;
+            ULARGE_INTEGER Length;
+            POINTER FileHandle;
+        } FromFileHandle;
+    };
+};
+
+struct http_request
+{
+    ULONG Flags;
+    HTTP_CONNECTION_ID ConnectionId;
+    HTTP_REQUEST_ID RequestId;
+    HTTP_URL_CONTEXT UrlContext;
+    HTTP_VERSION Version;
+    HTTP_VERB Verb;
+    USHORT UnknownVerbLength;
+    USHORT RawUrlLength;
+    POINTER pUnknownVerb; /* char string */
+    POINTER pRawUrl; /* char string */
+    struct
+    {
+        USHORT FullUrlLength;
+        USHORT HostLength;
+        USHORT AbsPathLength;
+        USHORT QueryStringLength;
+        POINTER pFullUrl; /* WCHAR string */
+        POINTER pHost; /* pointer to above */
+        POINTER pAbsPath; /* pointer to above */
+        POINTER pQueryString; /* pointer to above */
+    } CookedUrl;
+    struct
+    {
+        POINTER pRemoteAddress; /* SOCKADDR */
+        POINTER pLocalAddress; /* SOCKADDR */
+    } Address;
+    struct
+    {
+        USHORT UnknownHeaderCount;
+        POINTER pUnknownHeaders; /* struct http_unknown_header */
+        USHORT TrailerCount;
+        POINTER pTrailers; /* NULL */
+        struct
+        {
+            USHORT RawValueLength;
+            POINTER pRawValue; /* char string */
+        } KnownHeaders[HttpHeaderRequestMaximum];
+    } Headers;
+    ULONGLONG BytesReceived;
+    USHORT EntityChunkCount;
+    POINTER pEntityChunks; /* struct http_data_chunk */
+    HTTP_RAW_CONNECTION_ID RawConnectionId;
+    POINTER pSslInfo; /* NULL (FIXME) */
+    USHORT RequestInfoCount;
+    POINTER pRequestInfo; /* NULL (FIXME) */
+};
+
+static NTSTATUS complete_irp(struct connection *conn, IRP *irp)
+{
+    const struct http_receive_request_params params
+            = *(struct http_receive_request_params *)irp->AssociatedIrp.SystemBuffer;
+    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;
+    struct http_request *req = irp->AssociatedIrp.SystemBuffer;
+    const char *p, *name, *value, *host, *abs_path, *query;
+    struct http_unknown_header *unk_headers = NULL;
+    char *buffer = irp->AssociatedIrp.SystemBuffer;
+    DWORD irp_size = sizeof(struct http_request);
+    USHORT unk_headers_count = 0, unk_header_idx;
+    struct http_data_chunk *chunk = NULL;
+    int name_len, value_len, len;
+    struct sockaddr_in addr;
+
+    /* First calculate the total buffer size needed for this IRP. */
+
+    if (conn->unk_verb_len)
+        irp_size += conn->unk_verb_len + 1;
+    irp_size += conn->url_len + 1;
+
+    /* cooked URL */
+    if (conn->url[0] == '/')
+    {
+        p = host = conn->host;
+        while (isgraph(*p)) ++p;
+        host_len = p - conn->host;
+        abs_path = conn->url;
+        abs_path_len = conn->url_len;
+    }
+    else
+    {
+        host = conn->url + 7;
+        abs_path = strchr(host, '/');
+        host_len = abs_path - host;
+        abs_path_len = (conn->url + conn->url_len) - abs_path;
+    }
+    if ((query = memchr(abs_path, '?', abs_path_len)))
+    {
+        query_len = (abs_path + abs_path_len) - query;
+        abs_path_len = query - abs_path;
+    }
+    else
+        query_len = 0;
+    cooked_len = (7 /* scheme */ + host_len + abs_path_len + query_len) * sizeof(WCHAR);
+    irp_size += cooked_len + sizeof(WCHAR);
+
+    /* addresses */
+    irp_size += 2 * sizeof(addr);
+
+    /* headers */
+    p = strstr(conn->buffer, "\r\n") + 2;
+    while (memcmp(p, "\r\n", 2))
+    {
+        name = p;
+        parse_header(name, &name_len, &value, &value_len);
+        if (parse_header_name(name, name_len) == HttpHeaderRequestMaximum)
+        {
+            irp_size += name_len + 1;
+            ++unk_headers_count;
+        }
+        irp_size += value_len + 1;
+        p = strstr(p, "\r\n") + 2;
+    }
+    p += 2;
+
+    irp_size += unk_headers_count * sizeof(struct http_unknown_header);
+
+    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)
+    {
+        req->ConnectionId = (ULONG_PTR)conn;
+        req->RequestId = conn->req_id;
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    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;
+    req->UnknownVerbLength = conn->unk_verb_len;
+    req->RawUrlLength = conn->url_len;
+
+    if (conn->unk_verb_len)
+    {
+        req->pUnknownVerb = params.addr + offset;
+        memcpy(buffer + offset, conn->buffer, conn->unk_verb_len);
+        offset += conn->unk_verb_len;
+        buffer[offset++] = 0;
+    }
+
+    req->pRawUrl = params.addr + offset;
+    memcpy(buffer + offset, conn->url, conn->url_len);
+    offset += conn->url_len;
+    buffer[offset++] = 0;
+
+    req->CookedUrl.FullUrlLength = cooked_len;
+    req->CookedUrl.HostLength = host_len * sizeof(WCHAR);
+    req->CookedUrl.AbsPathLength = abs_path_len * sizeof(WCHAR);
+    req->CookedUrl.QueryStringLength = query_len * sizeof(WCHAR);
+    req->CookedUrl.pFullUrl = params.addr + offset;
+    req->CookedUrl.pHost = req->CookedUrl.pFullUrl + 7 * sizeof(WCHAR);
+    req->CookedUrl.pAbsPath = req->CookedUrl.pHost + host_len * sizeof(WCHAR);
+    if (query)
+        req->CookedUrl.pQueryString = req->CookedUrl.pAbsPath + abs_path_len * sizeof(WCHAR);
+
+    memcpy(buffer + offset, L"http://", sizeof(L"http://"));
+    offset += 7 * sizeof(WCHAR);
+    MultiByteToWideChar(CP_ACP, 0, host, host_len, (WCHAR *)(buffer + offset), host_len * sizeof(WCHAR));
+    offset += host_len * sizeof(WCHAR);
+    MultiByteToWideChar(CP_ACP, 0, abs_path, abs_path_len + query_len,
+            (WCHAR *)(buffer + offset), (abs_path_len + query_len) * sizeof(WCHAR));
+    offset += (abs_path_len + query_len) * sizeof(WCHAR);
+    buffer[offset++] = 0;
+    buffer[offset++] = 0;
+
+    req->Address.pRemoteAddress = params.addr + offset;
+    len = sizeof(addr);
+    getpeername(conn->socket, (struct sockaddr *)&addr, &len);
+    memcpy(buffer + offset, &addr, sizeof(addr));
+    offset += sizeof(addr);
+
+    req->Address.pLocalAddress = params.addr + offset;
+    len = sizeof(addr);
+    getsockname(conn->socket, (struct sockaddr *)&addr, &len);
+    memcpy(buffer + offset, &addr, sizeof(addr));
+    offset += sizeof(addr);
+
+    req->Headers.UnknownHeaderCount = unk_headers_count;
+    if (unk_headers_count)
+    {
+        req->Headers.pUnknownHeaders = params.addr + offset;
+        unk_headers = (struct http_unknown_header *)(buffer + offset);
+        offset += unk_headers_count * sizeof(*unk_headers);
+    }
+
+    unk_header_idx = 0;
+    p = strstr(conn->buffer, "\r\n") + 2;
+    while (memcmp(p, "\r\n", 2))
+    {
+        HTTP_HEADER_ID id;
+
+        name = p;
+        parse_header(name, &name_len, &value, &value_len);
+        if ((id = parse_header_name(name, name_len)) == HttpHeaderRequestMaximum)
+        {
+            unk_headers[unk_header_idx].NameLength = name_len;
+            unk_headers[unk_header_idx].RawValueLength = value_len;
+            unk_headers[unk_header_idx].pName = params.addr + offset;
+            memcpy(buffer + offset, name, name_len);
+            offset += name_len;
+            buffer[offset++] = 0;
+            unk_headers[unk_header_idx].pRawValue = params.addr + offset;
+            memcpy(buffer + offset, value, value_len);
+            offset += value_len;
+            buffer[offset++] = 0;
+            ++unk_header_idx;
+        }
+        else
+        {
+            req->Headers.KnownHeaders[id].RawValueLength = value_len;
+            req->Headers.KnownHeaders[id].pRawValue = params.addr + offset;
+            memcpy(buffer + offset, value, value_len);
+            offset += value_len;
+            buffer[offset++] = 0;
+        }
+        p = strstr(p, "\r\n") + 2;
+    }
+    p += 2;
+
+    if (irp_size + sizeof(*chunk) < output_len && (params.flags & HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY))
+        chunk_len = min(conn->content_len, output_len - (irp_size + sizeof(*chunk)));
+    if (chunk_len)
+    {
+        req->EntityChunkCount = 1;
+        req->pEntityChunks = params.addr + offset;
+        chunk = (struct http_data_chunk *)(buffer + offset);
+        offset += sizeof(*chunk);
+        chunk->DataChunkType = HttpDataChunkFromMemory;
+        chunk->FromMemory.BufferLength = chunk_len;
+        chunk->FromMemory.pBuffer = params.addr + offset;
+        memcpy(buffer + offset, p, chunk_len);
+        offset += chunk_len;
+
+        irp->IoStatus.Information = irp_size + sizeof(*chunk) + chunk_len;
+    }
+
+    if (chunk_len < conn->content_len)
+        req->Flags |= HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
+
+    req->BytesReceived = conn->req_len;
+
+    assert(offset == irp->IoStatus.Information);
+
+    conn->available = FALSE;
+    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;
+}
-- 
2.26.2




More information about the wine-devel mailing list