[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