http.sys: Allow receiving parsed HTTP requests.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2019-08-23 17:36:18 -05:00 committed by Alexandre Julliard
parent 85f5338eff
commit 7a73d01f88
2 changed files with 208 additions and 0 deletions

View File

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <assert.h>
#include "ntstatus.h" #include "ntstatus.h"
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "wine/http.h" #include "wine/http.h"
@ -32,6 +33,108 @@ static DEVICE_OBJECT *device_obj;
WINE_DEFAULT_DEBUG_CHANNEL(http); 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) \ #define DECLARE_CRITICAL_SECTION(cs) \
static CRITICAL_SECTION cs; \ static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = \ static CRITICAL_SECTION_DEBUG cs##_debug = \
@ -161,6 +264,73 @@ static int parse_token(const char *str, const char *end)
return p - str; 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. */ /* 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) 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; 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) static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp)
{ {
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(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: case IOCTL_HTTP_REMOVE_URL:
ret = http_remove_url(queue, irp); ret = http_remove_url(queue, irp);
break; break;
case IOCTL_HTTP_RECEIVE_REQUEST:
ret = http_receive_request(queue, irp);
break;
default: default:
FIXME("Unhandled ioctl %#x.\n", stack->Parameters.DeviceIoControl.IoControlCode); FIXME("Unhandled ioctl %#x.\n", stack->Parameters.DeviceIoControl.IoControlCode);
ret = STATUS_NOT_IMPLEMENTED; ret = STATUS_NOT_IMPLEMENTED;

View File

@ -25,6 +25,7 @@
#define IOCTL_HTTP_ADD_URL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, 0) #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_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 struct http_add_url_params
{ {
@ -32,4 +33,12 @@ struct http_add_url_params
char url[1]; char url[1];
}; };
struct http_receive_request_params
{
ULONGLONG addr; /* user-mode buffer address */
HTTP_REQUEST_ID id;
ULONG flags;
ULONG bits;
};
#endif #endif