Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/http.sys/http.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ include/wine/http.h | 8 ++++++++ 2 files changed, 53 insertions(+)
diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index 4115afc8672..b2400a26b7c 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -1193,6 +1193,48 @@ static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp) return ret; }
+static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp) +{ + const struct http_response *response = irp->AssociatedIrp.SystemBuffer; + struct connection *conn; + + TRACE("id %s, len %d.\n", wine_dbgstr_longlong(response->id), response->len); + + EnterCriticalSection(&http_cs); + + LIST_FOR_EACH_ENTRY(conn, &connections, struct connection, entry) + { + if (conn->req_id == response->id) + { + if (send(conn->socket, response->buffer, response->len, 0) >= 0) + { + conn->queue = NULL; + conn->req_id = HTTP_NULL_ID; + WSAEventSelect(conn->socket, request_event, FD_READ | FD_CLOSE); + irp->IoStatus.Information = response->len; + /* We might have another request already in the buffer. */ + if (parse_request(conn) < 0) + { + WARN("Failed to parse request; shutting down connection.\n"); + send_400(conn); + close_connection(conn); + } + } + else + { + ERR("Got error %u; shutting down connection.\n", WSAGetLastError()); + close_connection(conn); + } + + LeaveCriticalSection(&http_cs); + return STATUS_SUCCESS; + } + } + + LeaveCriticalSection(&http_cs); + return STATUS_CONNECTION_INVALID; +} + static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -1210,6 +1252,9 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_HTTP_RECEIVE_REQUEST: ret = http_receive_request(queue, irp); break; + case IOCTL_HTTP_SEND_RESPONSE: + ret = http_send_response(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 1145cab71a7..eb75d8f60ef 100644 --- a/include/wine/http.h +++ b/include/wine/http.h @@ -26,6 +26,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) +#define IOCTL_HTTP_SEND_RESPONSE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, 0)
struct http_add_url_params { @@ -41,4 +42,11 @@ struct http_receive_request_params ULONG bits; };
+struct http_response +{ + HTTP_REQUEST_ID id; + int len; + char buffer[1]; +}; + #endif
While it's a little architecturally weird to have this part uniquely implemented in httpapi, it's far easier to handle building the response string here than having to marshal everything into an ioctl buffer first.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/httpapi/httpapi_main.c | 145 +++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 4 deletions(-)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index 08fbe4df65f..8a970a05777 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -289,6 +289,18 @@ ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flag return ret; }
+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); +} + /*********************************************************************** * HttpSendHttpResponse (HTTPAPI.@) */ @@ -296,10 +308,135 @@ ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, HTTP_RESPONSE *response, HTTP_CACHE_POLICY *cache_policy, ULONG *ret_size, void *reserved1, ULONG reserved2, OVERLAPPED *ovl, HTTP_LOG_DATA *log_data) { - FIXME("queue %p, id %s, flags %#x, response %p, cache_policy %p, " - "ret_size %p, reserved1 %p, reserved2 %#x, ovl %p, log_data %p, stub!\n", - queue, wine_dbgstr_longlong(id), flags, response, cache_policy, ret_size, reserved1, reserved2, ovl, log_data); - return ERROR_CALL_NOT_IMPLEMENTED; + static const char *const header_names[] = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + "Accept-Ranges", + "Age", + "ETag", + "Location", + "Proxy-Authenticate", + "Retry-After", + "Server", + "Set-Cookie", + "Vary", + "WWW-Authenticate", + }; + + struct http_response *buffer; + OVERLAPPED dummy_ovl = {}; + ULONG ret = ERROR_SUCCESS; + int len, body_len = 0; + char *p, dummy[12]; + USHORT i; + + TRACE("queue %p, id %s, flags %#x, response %p, cache_policy %p, " + "ret_size %p, reserved1 %p, reserved2 %#x, ovl %p, log_data %p.\n", + queue, wine_dbgstr_longlong(id), flags, response, cache_policy, + ret_size, reserved1, reserved2, ovl, log_data); + + if (flags) + FIXME("Unhandled flags %#x.\n", flags); + if (response->s.Flags) + FIXME("Unhandled response flags %#x.\n", response->s.Flags); + if (cache_policy) + WARN("Ignoring cache_policy.\n"); + if (log_data) + WARN("Ignoring log_data.\n"); + + len = 12 + sprintf(dummy, "%hu", response->s.StatusCode) + response->s.ReasonLength; + for (i = 0; i < response->s.EntityChunkCount; ++i) + { + if (response->s.pEntityChunks[i].DataChunkType != HttpDataChunkFromMemory) + { + FIXME("Unhandled data chunk type %u.\n", response->s.pEntityChunks[i].DataChunkType); + return ERROR_CALL_NOT_IMPLEMENTED; + } + body_len += response->s.pEntityChunks[i].FromMemory.BufferLength; + } + len += body_len; + for (i = 0; i < HttpHeaderResponseMaximum; ++i) + { + if (i == HttpHeaderDate) + len += 37; + else if (response->s.Headers.KnownHeaders[i].RawValueLength) + len += strlen(header_names[i]) + 2 + response->s.Headers.KnownHeaders[i].RawValueLength + 2; + else if (i == HttpHeaderContentLength) + { + char dummy[12]; + len += strlen(header_names[i]) + 2 + sprintf(dummy, "%d", body_len) + 2; + } + } + for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i) + { + len += response->s.Headers.pUnknownHeaders[i].NameLength + 2; + len += response->s.Headers.pUnknownHeaders[i].RawValueLength + 2; + } + len += 2; + + if (!(buffer = heap_alloc(offsetof(struct http_response, buffer[len])))) + return ERROR_OUTOFMEMORY; + buffer->id = id; + buffer->len = len; + sprintf(buffer->buffer, "HTTP/1.1 %u %.*s\r\n", response->s.StatusCode, + response->s.ReasonLength, response->s.pReason); + + for (i = 0; i < HttpHeaderResponseMaximum; ++i) + { + const HTTP_KNOWN_HEADER *header = &response->s.Headers.KnownHeaders[i]; + if (i == HttpHeaderDate) + format_date(buffer->buffer); + else if (header->RawValueLength) + sprintf(buffer->buffer + strlen(buffer->buffer), "%s: %.*s\r\n", + header_names[i], header->RawValueLength, header->pRawValue); + else if (i == HttpHeaderContentLength) + sprintf(buffer->buffer + strlen(buffer->buffer), "Content-Length: %d\r\n", body_len); + } + for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i) + { + const HTTP_UNKNOWN_HEADER *header = &response->s.Headers.pUnknownHeaders[i]; + sprintf(buffer->buffer + strlen(buffer->buffer), "%.*s: %.*s\r\n", header->NameLength, + header->pName, header->RawValueLength, header->pRawValue); + } + p = buffer->buffer + strlen(buffer->buffer); + /* Don't use strcat, because this might be the end of the buffer. */ + memcpy(p, "\r\n", 2); + p += 2; + for (i = 0; i < response->s.EntityChunkCount; ++i) + { + const HTTP_DATA_CHUNK *chunk = &response->s.pEntityChunks[i]; + memcpy(p, chunk->FromMemory.pBuffer, chunk->FromMemory.BufferLength); + p += chunk->FromMemory.BufferLength; + } + + if (!ovl) + ovl = &dummy_ovl; + + if (!DeviceIoControl(queue, IOCTL_HTTP_SEND_RESPONSE, buffer, + offsetof(struct http_response, buffer[len]), NULL, 0, NULL, ovl)) + ret = GetLastError(); + + heap_free(buffer); + return ret; }
/***********************************************************************
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38245 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/httpapi/Makefile.in | 1 + dlls/httpapi/httpapi_main.c | 39 ++++++++++++++++++++++++++++++++---- dlls/httpapi/tests/httpapi.c | 24 ++++++++-------------- 3 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/dlls/httpapi/Makefile.in b/dlls/httpapi/Makefile.in index b3af7dae93f..6a55f84258b 100644 --- a/dlls/httpapi/Makefile.in +++ b/dlls/httpapi/Makefile.in @@ -1,5 +1,6 @@ MODULE = httpapi.dll IMPORTLIB = httpapi +IMPORTS = advapi32
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index 8a970a05777..c970c68ccad 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -19,6 +19,7 @@ */
#include "wine/http.h" +#include "winsvc.h" #include "winternl.h" #include "wine/debug.h" #include "wine/heap.h" @@ -52,11 +53,41 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID lpv ) * NO_ERROR if function succeeds, or error code if function fails * */ -ULONG WINAPI HttpInitialize( HTTPAPI_VERSION version, ULONG flags, PVOID reserved ) +ULONG WINAPI HttpInitialize(HTTPAPI_VERSION version, ULONG flags, void *reserved) { - FIXME( "({%d,%d}, 0x%x, %p): stub!\n", version.HttpApiMajorVersion, - version.HttpApiMinorVersion, flags, reserved ); - return NO_ERROR; + static const WCHAR httpW[] = {'h','t','t','p',0}; + SC_HANDLE manager, service; + + TRACE("version %u.%u, flags %#x, reserved %p.\n", version.HttpApiMajorVersion, + version.HttpApiMinorVersion, flags, reserved); + + if (flags & ~HTTP_INITIALIZE_SERVER) + { + FIXME("Unhandled flags %#x.\n", flags); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT))) + return GetLastError(); + + if (!(service = OpenServiceW(manager, httpW, SERVICE_START))) + { + ERR("Failed to open HTTP service, error %u.\n", GetLastError()); + CloseServiceHandle(manager); + return GetLastError(); + } + + if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) + { + ERR("Failed to start HTTP service, error %u.\n", GetLastError()); + CloseServiceHandle(service); + CloseServiceHandle(manager); + return GetLastError(); + } + + CloseServiceHandle(service); + CloseServiceHandle(manager); + return ERROR_SUCCESS; }
/*********************************************************************** diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c index c30c3808992..94804a9904d 100644 --- a/dlls/httpapi/tests/httpapi.c +++ b/dlls/httpapi/tests/httpapi.c @@ -122,8 +122,7 @@ static void test_v1_server(void) /* Non-zero reserved parameter is accepted on XP/2k3. */ queue = NULL; ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Unexpected ret value %u.\n", ret); - if (ret) return; + ok(!ret, "Unexpected ret value %u.\n", ret); ok(!!queue, "Unexpected handle value %p.\n", queue);
queue2 = NULL; @@ -314,8 +313,7 @@ static void test_v1_completion_port(void) ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret);
port = CreateIoCompletionPort(queue, NULL, 123, 0); ok(!!port, "Failed to create completion port, error %u.\n", GetLastError()); @@ -391,8 +389,7 @@ static void test_v1_multiple_requests(void) ovl2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
@@ -493,8 +490,7 @@ static void test_v1_short_buffer(void) ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
@@ -569,8 +565,7 @@ static void test_v1_entity_body(void) req_body[i] = i / 111;
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
@@ -716,8 +711,7 @@ static void test_v1_bad_request(void) SOCKET s;
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
@@ -774,8 +768,7 @@ static void test_v1_cooked_url(void) "\r\n";
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
@@ -849,8 +842,7 @@ static void test_v1_unknown_tokens(void) "\r\n";
ret = HttpCreateHttpHandle(&queue, 0); - todo_wine ok(!ret, "Got error %u.\n", ret); - if (ret) return; + ok(!ret, "Got error %u.\n", ret); ret = HttpAddUrl(queue, localhost_urlW, NULL); ok(!ret, "Got error %u.\n", ret);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/httpapi/httpapi_main.c | 56 ++++++++++++++++++++++++++++++++---- dlls/httpapi/tests/httpapi.c | 7 ----- include/http.h | 2 +- 3 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index c970c68ccad..a71dcc5ce83 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -23,6 +23,7 @@ #include "winternl.h" #include "wine/debug.h" #include "wine/heap.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(httpapi);
@@ -470,20 +471,63 @@ ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, return ret; }
+struct server_session +{ + struct list entry; +}; + +static struct list server_sessions = LIST_INIT(server_sessions); + +static struct server_session *get_server_session(HTTP_SERVER_SESSION_ID id) +{ + struct server_session *session; + LIST_FOR_EACH_ENTRY(session, &server_sessions, struct server_session, entry) + { + if ((HTTP_SERVER_SESSION_ID)(ULONG_PTR)session == id) + return session; + } + return NULL; +} + /*********************************************************************** * HttpCreateServerSession (HTTPAPI.@) */ -ULONG WINAPI HttpCreateServerSession( HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *id, ULONG reserved ) +ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *id, ULONG reserved) { - FIXME( "({%d,%d}, %p, %d): stub!\n", version.HttpApiMajorVersion, version.HttpApiMinorVersion, id, reserved ); - return ERROR_ACCESS_DENIED; + struct server_session *session; + + TRACE("version %u.%u, id %p, reserved %u.\n", version.HttpApiMajorVersion, + version.HttpApiMinorVersion, id, reserved); + + if (!id) + return ERROR_INVALID_PARAMETER; + + if ((version.HttpApiMajorVersion != 1 && version.HttpApiMajorVersion != 2) + || version.HttpApiMinorVersion) + return ERROR_REVISION_MISMATCH; + + if (!(session = heap_alloc(sizeof(*session)))) + return ERROR_OUTOFMEMORY; + + list_add_tail(&server_sessions, &session->entry); + + *id = (ULONG_PTR)session; + return ERROR_SUCCESS; }
/*********************************************************************** * HttpCloseServerSession (HTTPAPI.@) */ -ULONG WINAPI HttpCloseServerSession( HTTP_SERVER_SESSION_ID id ) +ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id) { - FIXME( "(%s): stub!\n", wine_dbgstr_longlong(id)); - return ERROR_INVALID_PARAMETER; + struct server_session *session; + + TRACE("id %s.\n", wine_dbgstr_longlong(id)); + + if (!(session = get_server_session(id))) + return ERROR_INVALID_PARAMETER; + + list_remove(&session->entry); + heap_free(session); + return ERROR_SUCCESS; } diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c index 94804a9904d..2153361c59c 100644 --- a/dlls/httpapi/tests/httpapi.c +++ b/dlls/httpapi/tests/httpapi.c @@ -888,37 +888,30 @@ static void test_HttpCreateServerSession(void) version.HttpApiMajorVersion = 1; version.HttpApiMinorVersion = 0; ret = pHttpCreateServerSession(version, NULL, 0); -todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Unexpected return value %u.\n", ret);
version.HttpApiMajorVersion = 1; version.HttpApiMinorVersion = 1; ret = pHttpCreateServerSession(version, &session, 0); -todo_wine ok(ret == ERROR_REVISION_MISMATCH, "Unexpected return value %u.\n", ret);
version.HttpApiMajorVersion = 3; version.HttpApiMinorVersion = 0; ret = pHttpCreateServerSession(version, &session, 0); -todo_wine ok(ret == ERROR_REVISION_MISMATCH, "Unexpected return value %u.\n", ret);
version.HttpApiMajorVersion = 2; version.HttpApiMinorVersion = 0; ret = pHttpCreateServerSession(version, &session, 0); -todo_wine ok(!ret, "Unexpected return value %u.\n", ret); ret = pHttpCloseServerSession(session); -todo_wine ok(!ret, "Unexpected return value %u.\n", ret);
version.HttpApiMajorVersion = 1; version.HttpApiMinorVersion = 0; ret = pHttpCreateServerSession(version, &session, 0); -todo_wine ok(!ret, "Unexpected return value %u.\n", ret); ret = pHttpCloseServerSession(session); -todo_wine ok(!ret, "Unexpected return value %u.\n", ret);
ret = pHttpCloseServerSession(0xdead); diff --git a/include/http.h b/include/http.h index 84d3445b672..dc4af74a477 100644 --- a/include/http.h +++ b/include/http.h @@ -398,9 +398,9 @@ typedef struct _HTTP_LOG_DATA } HTTP_LOG_DATA, *PHTTP_LOG_DATA;
ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID); +ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id); ULONG WINAPI HttpCreateHttpHandle(PHANDLE,ULONG); ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION,PHTTP_SERVER_SESSION_ID,ULONG); -ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID); ULONG WINAPI HttpDeleteServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED); ULONG WINAPI HttpInitialize(HTTPAPI_VERSION version, ULONG flags, void *reserved); ULONG WINAPI HttpTerminate(ULONG flags, void *reserved);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/httpapi/httpapi.spec | 2 ++ dlls/httpapi/httpapi_main.c | 67 +++++++++++++++++++++++++++++++++++++ include/http.h | 2 ++ 3 files changed, 71 insertions(+)
diff --git a/dlls/httpapi/httpapi.spec b/dlls/httpapi/httpapi.spec index 88bc32488a3..aad5d58437c 100644 --- a/dlls/httpapi/httpapi.spec +++ b/dlls/httpapi/httpapi.spec @@ -7,7 +7,9 @@ @ stub HttpCreateFilter @ stdcall HttpCreateHttpHandle(ptr long) @ stdcall HttpCreateServerSession(long ptr long) +@ stdcall HttpCreateUrlGroup(int64 ptr long) @ stdcall HttpCloseServerSession(int64) +@ stdcall HttpCloseUrlGroup(int64) @ stub HttpDeleteConfigGroup @ stdcall HttpDeleteServiceConfiguration(ptr long ptr long ptr) @ stub HttpFilterAccept diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c index a71dcc5ce83..c7d95c9fbad 100644 --- a/dlls/httpapi/httpapi_main.c +++ b/dlls/httpapi/httpapi_main.c @@ -471,9 +471,28 @@ ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, return ret; }
+struct url_group +{ + struct list entry, session_entry; +}; + +static struct list url_groups = LIST_INIT(url_groups); + +static struct url_group *get_url_group(HTTP_URL_GROUP_ID id) +{ + struct url_group *group; + LIST_FOR_EACH_ENTRY(group, &url_groups, struct url_group, entry) + { + if ((HTTP_URL_GROUP_ID)(ULONG_PTR)group == id) + return group; + } + return NULL; +} + struct server_session { struct list entry; + struct list groups; };
static struct list server_sessions = LIST_INIT(server_sessions); @@ -510,6 +529,7 @@ ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION version, HTTP_SERVER_SESSIO return ERROR_OUTOFMEMORY;
list_add_tail(&server_sessions, &session->entry); + list_init(&session->groups);
*id = (ULONG_PTR)session; return ERROR_SUCCESS; @@ -520,6 +540,7 @@ ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION version, HTTP_SERVER_SESSIO */ ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id) { + struct url_group *group, *group_next; struct server_session *session;
TRACE("id %s.\n", wine_dbgstr_longlong(id)); @@ -527,7 +548,53 @@ ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id) if (!(session = get_server_session(id))) return ERROR_INVALID_PARAMETER;
+ LIST_FOR_EACH_ENTRY_SAFE(group, group_next, &session->groups, struct url_group, session_entry) + { + HttpCloseUrlGroup((ULONG_PTR)group); + } list_remove(&session->entry); heap_free(session); return ERROR_SUCCESS; } + +/*********************************************************************** + * HttpCreateUrlGroup (HTTPAPI.@) + */ +ULONG WINAPI HttpCreateUrlGroup(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved) +{ + struct server_session *session; + struct url_group *group; + + TRACE("session_id %#I64x, group_id %p, reserved %#x.\n", session_id, group_id, reserved); + + if (!(session = get_server_session(session_id))) + return ERROR_INVALID_PARAMETER; + + if (!(group = heap_alloc_zero(sizeof(*group)))) + return ERROR_OUTOFMEMORY; + list_add_tail(&url_groups, &group->entry); + list_add_tail(&session->groups, &group->session_entry); + + *group_id = (ULONG_PTR)group; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpCloseUrlGroup (HTTPAPI.@) + */ +ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id) +{ + struct url_group *group; + + TRACE("id %#I64x.\n", id); + + if (!(group = get_url_group(id))) + return ERROR_INVALID_PARAMETER; + + list_remove(&group->session_entry); + list_remove(&group->entry); + heap_free(group); + + return ERROR_SUCCESS; +} diff --git a/include/http.h b/include/http.h index dc4af74a477..b07c3b03f93 100644 --- a/include/http.h +++ b/include/http.h @@ -399,8 +399,10 @@ typedef struct _HTTP_LOG_DATA
ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID); ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id); +ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id); ULONG WINAPI HttpCreateHttpHandle(PHANDLE,ULONG); ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION,PHTTP_SERVER_SESSION_ID,ULONG); +ULONG WINAPI HttpCreateUrlGroup(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved); ULONG WINAPI HttpDeleteServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED); ULONG WINAPI HttpInitialize(HTTPAPI_VERSION version, ULONG flags, void *reserved); ULONG WINAPI HttpTerminate(ULONG flags, void *reserved);