62e90e85677ffe84900eb979ab375313c7a611ff
[reactos.git] / dll / win32 / httpapi / httpapi_main.c
1 /*
2 * HTTPAPI implementation
3 *
4 * Copyright 2009 Austin English
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #ifdef __REACTOS__
22 #include <stdio.h>
23 #endif
24 #include "wine/http.h"
25 #include "winsvc.h"
26 #include "wine/winternl.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/list.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(httpapi);
32
33 static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','H','t','t','p','\\','R','e','q','Q','u','e','u','e',0};
34
35 static WCHAR *heap_strdupW(const WCHAR *str)
36 {
37 int len = wcslen(str) + 1;
38 WCHAR *ret = heap_alloc(len * sizeof(WCHAR));
39 wcscpy(ret, str);
40 return ret;
41 }
42
43 /***********************************************************************
44 * HttpInitialize (HTTPAPI.@)
45 *
46 * Initializes HTTP Server API engine
47 *
48 * PARAMS
49 * version [ I] HTTP API version which caller will use
50 * flags [ I] initialization options which specify parts of API what will be used
51 * reserved [IO] reserved, must be NULL
52 *
53 * RETURNS
54 * NO_ERROR if function succeeds, or error code if function fails
55 *
56 */
57 ULONG WINAPI HttpInitialize(HTTPAPI_VERSION version, ULONG flags, void *reserved)
58 {
59 static const WCHAR httpW[] = {'h','t','t','p',0};
60 SC_HANDLE manager, service;
61
62 TRACE("version %u.%u, flags %#x, reserved %p.\n", version.HttpApiMajorVersion,
63 version.HttpApiMinorVersion, flags, reserved);
64
65 if (flags & ~HTTP_INITIALIZE_SERVER)
66 {
67 FIXME("Unhandled flags %#x.\n", flags);
68 return ERROR_CALL_NOT_IMPLEMENTED;
69 }
70
71 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
72 return GetLastError();
73
74 if (!(service = OpenServiceW(manager, httpW, SERVICE_START)))
75 {
76 ERR("Failed to open HTTP service, error %u.\n", GetLastError());
77 CloseServiceHandle(manager);
78 return GetLastError();
79 }
80
81 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
82 {
83 ERR("Failed to start HTTP service, error %u.\n", GetLastError());
84 CloseServiceHandle(service);
85 CloseServiceHandle(manager);
86 return GetLastError();
87 }
88
89 CloseServiceHandle(service);
90 CloseServiceHandle(manager);
91 return ERROR_SUCCESS;
92 }
93
94 /***********************************************************************
95 * HttpTerminate (HTTPAPI.@)
96 *
97 * Cleans up HTTP Server API engine resources allocated by HttpInitialize
98 *
99 * PARAMS
100 * flags [ I] options which specify parts of API what should be released
101 * reserved [IO] reserved, must be NULL
102 *
103 * RETURNS
104 * NO_ERROR if function succeeds, or error code if function fails
105 *
106 */
107 ULONG WINAPI HttpTerminate( ULONG flags, PVOID reserved )
108 {
109 FIXME( "(0x%x, %p): stub!\n", flags, reserved );
110 return NO_ERROR;
111 }
112
113 /***********************************************************************
114 * HttpDeleteServiceConfiguration (HTTPAPI.@)
115 *
116 * Remove configuration record from HTTP Server API configuration store
117 *
118 * PARAMS
119 * handle [I] reserved, must be 0
120 * type [I] configuration record type
121 * config [I] buffer which contains configuration record information
122 * length [I] length of configuration record buffer
123 * overlapped [I] reserved, must be NULL
124 *
125 * RETURNS
126 * NO_ERROR if function succeeds, or error code if function fails
127 *
128 */
129 ULONG WINAPI HttpDeleteServiceConfiguration( HANDLE handle, HTTP_SERVICE_CONFIG_ID type,
130 PVOID config, ULONG length, LPOVERLAPPED overlapped )
131 {
132 FIXME( "(%p, %d, %p, %d, %p): stub!\n", handle, type, config, length, overlapped );
133 return NO_ERROR;
134 }
135
136 /***********************************************************************
137 * HttpQueryServiceConfiguration (HTTPAPI.@)
138 *
139 * Retrieves configuration records from HTTP Server API configuration store
140 *
141 * PARAMS
142 * handle [ I] reserved, must be 0
143 * type [ I] configuration records type
144 * query [ I] buffer which contains query data used to retrieve records
145 * query_len [ I] length of query buffer
146 * buffer [IO] buffer to store query results
147 * buffer_len [ I] length of output buffer
148 * data_len [ O] optional pointer to a buffer which receives query result length
149 * overlapped [ I] reserved, must be NULL
150 *
151 * RETURNS
152 * NO_ERROR if function succeeds, or error code if function fails
153 *
154 */
155 ULONG WINAPI HttpQueryServiceConfiguration( HANDLE handle, HTTP_SERVICE_CONFIG_ID type,
156 PVOID query, ULONG query_len, PVOID buffer, ULONG buffer_len,
157 PULONG data_len, LPOVERLAPPED overlapped )
158 {
159 FIXME( "(%p, %d, %p, %d, %p, %d, %p, %p): stub!\n", handle, type, query, query_len,
160 buffer, buffer_len, data_len, overlapped );
161 return ERROR_FILE_NOT_FOUND;
162 }
163
164 /***********************************************************************
165 * HttpSetServiceConfiguration (HTTPAPI.@)
166 *
167 * Add configuration record to HTTP Server API configuration store
168 *
169 * PARAMS
170 * handle [I] reserved, must be 0
171 * type [I] configuration record type
172 * config [I] buffer which contains configuration record information
173 * length [I] length of configuration record buffer
174 * overlapped [I] reserved, must be NULL
175 *
176 * RETURNS
177 * NO_ERROR if function succeeds, or error code if function fails
178 *
179 */
180 ULONG WINAPI HttpSetServiceConfiguration( HANDLE handle, HTTP_SERVICE_CONFIG_ID type,
181 PVOID config, ULONG length, LPOVERLAPPED overlapped )
182 {
183 FIXME( "(%p, %d, %p, %d, %p): stub!\n", handle, type, config, length, overlapped );
184 return NO_ERROR;
185 }
186
187 /***********************************************************************
188 * HttpCreateHttpHandle (HTTPAPI.@)
189 *
190 * Creates a handle to the HTTP request queue
191 *
192 * PARAMS
193 * handle [O] handle to request queue
194 * reserved [I] reserved, must be NULL
195 *
196 * RETURNS
197 * NO_ERROR if function succeeds, or error code if function fails
198 *
199 */
200 ULONG WINAPI HttpCreateHttpHandle(HANDLE *handle, ULONG reserved)
201 {
202 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
203 UNICODE_STRING string;
204 IO_STATUS_BLOCK iosb;
205
206 TRACE("handle %p, reserved %#x.\n", handle, reserved);
207
208 if (!handle)
209 return ERROR_INVALID_PARAMETER;
210
211 RtlInitUnicodeString(&string, device_nameW);
212 attr.ObjectName = &string;
213 return RtlNtStatusToDosError(NtCreateFile(handle, 0, &attr, &iosb, NULL,
214 FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0));
215 }
216
217 static ULONG add_url(HANDLE queue, const WCHAR *urlW, HTTP_URL_CONTEXT context)
218 {
219 struct http_add_url_params *params;
220 ULONG ret = ERROR_SUCCESS;
221 OVERLAPPED ovl;
222 int len;
223
224 len = WideCharToMultiByte(CP_ACP, 0, urlW, -1, NULL, 0, NULL, NULL);
225 if (!(params = heap_alloc(offsetof(struct http_add_url_params, url[len]))))
226 return ERROR_OUTOFMEMORY;
227 WideCharToMultiByte(CP_ACP, 0, urlW, -1, params->url, len, NULL, NULL);
228 params->context = context;
229
230 ovl.hEvent = (HANDLE)((ULONG_PTR)CreateEventW(NULL, TRUE, FALSE, NULL) | 1);
231
232 if (!DeviceIoControl(queue, IOCTL_HTTP_ADD_URL, params,
233 offsetof(struct http_add_url_params, url[len]), NULL, 0, NULL, &ovl))
234 ret = GetLastError();
235 CloseHandle(ovl.hEvent);
236 heap_free(params);
237 return ret;
238 }
239
240 /***********************************************************************
241 * HttpAddUrl (HTTPAPI.@)
242 */
243 ULONG WINAPI HttpAddUrl(HANDLE queue, const WCHAR *url, void *reserved)
244 {
245 TRACE("queue %p, url %s, reserved %p.\n", queue, debugstr_w(url), reserved);
246
247 return add_url(queue, url, 0);
248 }
249
250 static ULONG remove_url(HANDLE queue, const WCHAR *urlW)
251 {
252 ULONG ret = ERROR_SUCCESS;
253 OVERLAPPED ovl = {0};
254 char *url;
255 int len;
256
257 len = WideCharToMultiByte(CP_ACP, 0, urlW, -1, NULL, 0, NULL, NULL);
258 if (!(url = heap_alloc(len)))
259 return ERROR_OUTOFMEMORY;
260 WideCharToMultiByte(CP_ACP, 0, urlW, -1, url, len, NULL, NULL);
261
262 ovl.hEvent = (HANDLE)((ULONG_PTR)CreateEventW(NULL, TRUE, FALSE, NULL) | 1);
263
264 if (!DeviceIoControl(queue, IOCTL_HTTP_REMOVE_URL, url, len, NULL, 0, NULL, &ovl))
265 ret = GetLastError();
266 CloseHandle(ovl.hEvent);
267 heap_free(url);
268 return ret;
269 }
270
271 /***********************************************************************
272 * HttpRemoveUrl (HTTPAPI.@)
273 */
274 ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *url)
275 {
276 TRACE("queue %p, url %s.\n", queue, debugstr_w(url));
277
278 if (!queue)
279 return ERROR_INVALID_PARAMETER;
280
281 return remove_url(queue, url);
282 }
283
284 /***********************************************************************
285 * HttpReceiveHttpRequest (HTTPAPI.@)
286 */
287 ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags,
288 HTTP_REQUEST *request, ULONG size, ULONG *ret_size, OVERLAPPED *ovl)
289 {
290 #ifndef __REACTOS__
291 struct http_receive_request_params params =
292 {
293 .addr = (ULONG_PTR)request,
294 .id = id,
295 .flags = flags,
296 .bits = sizeof(void *) * 8,
297 };
298 #else
299 struct http_receive_request_params params =
300 { (ULONGLONG)(ULONG_PTR)request, id, flags, sizeof(void *) * 8 };
301 #endif
302 ULONG ret = ERROR_SUCCESS;
303 OVERLAPPED sync_ovl;
304
305 TRACE("queue %p, id %s, flags %#x, request %p, size %#x, ret_size %p, ovl %p.\n",
306 queue, wine_dbgstr_longlong(id), flags, request, size, ret_size, ovl);
307
308 if (flags & ~HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY)
309 FIXME("Ignoring flags %#x.\n", flags & ~HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY);
310
311 if (size < sizeof(HTTP_REQUEST_V1))
312 return ERROR_INSUFFICIENT_BUFFER;
313
314 if (!ovl)
315 {
316 sync_ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
317 ovl = &sync_ovl;
318 }
319
320 if (!DeviceIoControl(queue, IOCTL_HTTP_RECEIVE_REQUEST, &params, sizeof(params), request, size, NULL, ovl))
321 ret = GetLastError();
322
323 if (ovl == &sync_ovl)
324 {
325 ret = ERROR_SUCCESS;
326 if (!GetOverlappedResult(queue, ovl, ret_size, TRUE))
327 ret = GetLastError();
328 CloseHandle(sync_ovl.hEvent);
329 }
330
331 return ret;
332 }
333
334 static void format_date(char *buffer)
335 {
336 static const char day_names[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
337 static const char month_names[12][4] =
338 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
339 SYSTEMTIME date;
340 GetSystemTime(&date);
341 sprintf(buffer + strlen(buffer), "Date: %s, %02u %s %u %02u:%02u:%02u GMT\r\n",
342 day_names[date.wDayOfWeek], date.wDay, month_names[date.wMonth - 1],
343 date.wYear, date.wHour, date.wMinute, date.wSecond);
344 }
345
346 /***********************************************************************
347 * HttpSendHttpResponse (HTTPAPI.@)
348 */
349 ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags,
350 HTTP_RESPONSE *response, HTTP_CACHE_POLICY *cache_policy, ULONG *ret_size,
351 void *reserved1, ULONG reserved2, OVERLAPPED *ovl, HTTP_LOG_DATA *log_data)
352 {
353 static const char *const header_names[] =
354 {
355 "Cache-Control",
356 "Connection",
357 "Date",
358 "Keep-Alive",
359 "Pragma",
360 "Trailer",
361 "Transfer-Encoding",
362 "Upgrade",
363 "Via",
364 "Warning",
365 "Allow",
366 "Content-Length",
367 "Content-Type",
368 "Content-Encoding",
369 "Content-Language",
370 "Content-Location",
371 "Content-MD5",
372 "Content-Range",
373 "Expires",
374 "Last-Modified",
375 "Accept-Ranges",
376 "Age",
377 "ETag",
378 "Location",
379 "Proxy-Authenticate",
380 "Retry-After",
381 "Server",
382 "Set-Cookie",
383 "Vary",
384 "WWW-Authenticate",
385 };
386
387 struct http_response *buffer;
388 OVERLAPPED dummy_ovl = {0};
389 ULONG ret = ERROR_SUCCESS;
390 int len, body_len = 0;
391 char *p, dummy[12];
392 USHORT i;
393
394 TRACE("queue %p, id %s, flags %#x, response %p, cache_policy %p, "
395 "ret_size %p, reserved1 %p, reserved2 %#x, ovl %p, log_data %p.\n",
396 queue, wine_dbgstr_longlong(id), flags, response, cache_policy,
397 ret_size, reserved1, reserved2, ovl, log_data);
398
399 if (flags)
400 FIXME("Unhandled flags %#x.\n", flags);
401 if (response->s.Flags)
402 FIXME("Unhandled response flags %#x.\n", response->s.Flags);
403 if (cache_policy)
404 WARN("Ignoring cache_policy.\n");
405 if (log_data)
406 WARN("Ignoring log_data.\n");
407
408 len = 12 + sprintf(dummy, "%hu", response->s.StatusCode) + response->s.ReasonLength;
409 for (i = 0; i < response->s.EntityChunkCount; ++i)
410 {
411 if (response->s.pEntityChunks[i].DataChunkType != HttpDataChunkFromMemory)
412 {
413 FIXME("Unhandled data chunk type %u.\n", response->s.pEntityChunks[i].DataChunkType);
414 return ERROR_CALL_NOT_IMPLEMENTED;
415 }
416 body_len += response->s.pEntityChunks[i].FromMemory.BufferLength;
417 }
418 len += body_len;
419 for (i = 0; i < HttpHeaderResponseMaximum; ++i)
420 {
421 if (i == HttpHeaderDate)
422 len += 37;
423 else if (response->s.Headers.KnownHeaders[i].RawValueLength)
424 len += strlen(header_names[i]) + 2 + response->s.Headers.KnownHeaders[i].RawValueLength + 2;
425 else if (i == HttpHeaderContentLength)
426 {
427 char dummy[12];
428 len += strlen(header_names[i]) + 2 + sprintf(dummy, "%d", body_len) + 2;
429 }
430 }
431 for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i)
432 {
433 len += response->s.Headers.pUnknownHeaders[i].NameLength + 2;
434 len += response->s.Headers.pUnknownHeaders[i].RawValueLength + 2;
435 }
436 len += 2;
437
438 if (!(buffer = heap_alloc(offsetof(struct http_response, buffer[len]))))
439 return ERROR_OUTOFMEMORY;
440 buffer->id = id;
441 buffer->len = len;
442 sprintf(buffer->buffer, "HTTP/1.1 %u %.*s\r\n", response->s.StatusCode,
443 response->s.ReasonLength, response->s.pReason);
444
445 for (i = 0; i < HttpHeaderResponseMaximum; ++i)
446 {
447 const HTTP_KNOWN_HEADER *header = &response->s.Headers.KnownHeaders[i];
448 if (i == HttpHeaderDate)
449 format_date(buffer->buffer);
450 else if (header->RawValueLength)
451 sprintf(buffer->buffer + strlen(buffer->buffer), "%s: %.*s\r\n",
452 header_names[i], header->RawValueLength, header->pRawValue);
453 else if (i == HttpHeaderContentLength)
454 sprintf(buffer->buffer + strlen(buffer->buffer), "Content-Length: %d\r\n", body_len);
455 }
456 for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i)
457 {
458 const HTTP_UNKNOWN_HEADER *header = &response->s.Headers.pUnknownHeaders[i];
459 sprintf(buffer->buffer + strlen(buffer->buffer), "%.*s: %.*s\r\n", header->NameLength,
460 header->pName, header->RawValueLength, header->pRawValue);
461 }
462 p = buffer->buffer + strlen(buffer->buffer);
463 /* Don't use strcat, because this might be the end of the buffer. */
464 memcpy(p, "\r\n", 2);
465 p += 2;
466 for (i = 0; i < response->s.EntityChunkCount; ++i)
467 {
468 const HTTP_DATA_CHUNK *chunk = &response->s.pEntityChunks[i];
469 memcpy(p, chunk->FromMemory.pBuffer, chunk->FromMemory.BufferLength);
470 p += chunk->FromMemory.BufferLength;
471 }
472
473 if (!ovl)
474 ovl = &dummy_ovl;
475
476 if (!DeviceIoControl(queue, IOCTL_HTTP_SEND_RESPONSE, buffer,
477 offsetof(struct http_response, buffer[len]), NULL, 0, NULL, ovl))
478 ret = GetLastError();
479
480 heap_free(buffer);
481 return ret;
482 }
483
484 struct url_group
485 {
486 struct list entry, session_entry;
487 HANDLE queue;
488 WCHAR *url;
489 HTTP_URL_CONTEXT context;
490 };
491
492 static struct list url_groups = LIST_INIT(url_groups);
493
494 static struct url_group *get_url_group(HTTP_URL_GROUP_ID id)
495 {
496 struct url_group *group;
497 LIST_FOR_EACH_ENTRY(group, &url_groups, struct url_group, entry)
498 {
499 if ((HTTP_URL_GROUP_ID)(ULONG_PTR)group == id)
500 return group;
501 }
502 return NULL;
503 }
504
505 struct server_session
506 {
507 struct list entry;
508 struct list groups;
509 };
510
511 static struct list server_sessions = LIST_INIT(server_sessions);
512
513 static struct server_session *get_server_session(HTTP_SERVER_SESSION_ID id)
514 {
515 struct server_session *session;
516 LIST_FOR_EACH_ENTRY(session, &server_sessions, struct server_session, entry)
517 {
518 if ((HTTP_SERVER_SESSION_ID)(ULONG_PTR)session == id)
519 return session;
520 }
521 return NULL;
522 }
523
524 /***********************************************************************
525 * HttpCreateServerSession (HTTPAPI.@)
526 */
527 ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *id, ULONG reserved)
528 {
529 struct server_session *session;
530
531 TRACE("version %u.%u, id %p, reserved %u.\n", version.HttpApiMajorVersion,
532 version.HttpApiMinorVersion, id, reserved);
533
534 if (!id)
535 return ERROR_INVALID_PARAMETER;
536
537 if ((version.HttpApiMajorVersion != 1 && version.HttpApiMajorVersion != 2)
538 || version.HttpApiMinorVersion)
539 return ERROR_REVISION_MISMATCH;
540
541 if (!(session = heap_alloc(sizeof(*session))))
542 return ERROR_OUTOFMEMORY;
543
544 list_add_tail(&server_sessions, &session->entry);
545 list_init(&session->groups);
546
547 *id = (ULONG_PTR)session;
548 return ERROR_SUCCESS;
549 }
550
551 /***********************************************************************
552 * HttpCloseServerSession (HTTPAPI.@)
553 */
554 ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id)
555 {
556 struct url_group *group, *group_next;
557 struct server_session *session;
558
559 TRACE("id %s.\n", wine_dbgstr_longlong(id));
560
561 if (!(session = get_server_session(id)))
562 return ERROR_INVALID_PARAMETER;
563
564 LIST_FOR_EACH_ENTRY_SAFE(group, group_next, &session->groups, struct url_group, session_entry)
565 {
566 HttpCloseUrlGroup((ULONG_PTR)group);
567 }
568 list_remove(&session->entry);
569 heap_free(session);
570 return ERROR_SUCCESS;
571 }
572
573 /***********************************************************************
574 * HttpCreateUrlGroup (HTTPAPI.@)
575 */
576 ULONG WINAPI HttpCreateUrlGroup(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved)
577 {
578 struct server_session *session;
579 struct url_group *group;
580
581 TRACE("session_id %s, group_id %p, reserved %#x.\n",
582 wine_dbgstr_longlong(session_id), group_id, reserved);
583
584 if (!(session = get_server_session(session_id)))
585 return ERROR_INVALID_PARAMETER;
586
587 if (!(group = heap_alloc_zero(sizeof(*group))))
588 return ERROR_OUTOFMEMORY;
589 list_add_tail(&url_groups, &group->entry);
590 list_add_tail(&session->groups, &group->session_entry);
591
592 *group_id = (ULONG_PTR)group;
593
594 return ERROR_SUCCESS;
595 }
596
597 /***********************************************************************
598 * HttpCloseUrlGroup (HTTPAPI.@)
599 */
600 ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id)
601 {
602 struct url_group *group;
603
604 TRACE("id %s.\n", wine_dbgstr_longlong(id));
605
606 if (!(group = get_url_group(id)))
607 return ERROR_INVALID_PARAMETER;
608
609 list_remove(&group->session_entry);
610 list_remove(&group->entry);
611 heap_free(group);
612
613 return ERROR_SUCCESS;
614 }
615
616 /***********************************************************************
617 * HttpSetUrlGroupProperty (HTTPAPI.@)
618 */
619 ULONG WINAPI HttpSetUrlGroupProperty(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY property, void *value, ULONG length)
620 {
621 struct url_group *group = get_url_group(id);
622 const HTTP_BINDING_INFO *info = value;
623
624 TRACE("id %s, property %u, value %p, length %u.\n",
625 wine_dbgstr_longlong(id), property, value, length);
626
627 if (property != HttpServerBindingProperty)
628 {
629 FIXME("Unhandled property %u.\n", property);
630 return ERROR_CALL_NOT_IMPLEMENTED;
631 }
632
633 TRACE("Binding to queue %p.\n", info->RequestQueueHandle);
634
635 group->queue = info->RequestQueueHandle;
636
637 if (group->url)
638 add_url(group->queue, group->url, group->context);
639
640 return ERROR_SUCCESS;
641 }
642
643 /***********************************************************************
644 * HttpAddUrlToUrlGroup (HTTPAPI.@)
645 */
646 ULONG WINAPI HttpAddUrlToUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url,
647 HTTP_URL_CONTEXT context, ULONG reserved)
648 {
649 struct url_group *group = get_url_group(id);
650
651 TRACE("id %s, url %s, context %s, reserved %#x.\n", wine_dbgstr_longlong(id),
652 debugstr_w(url), wine_dbgstr_longlong(context), reserved);
653
654 if (group->url)
655 {
656 FIXME("Multiple URLs are not handled!\n");
657 return ERROR_CALL_NOT_IMPLEMENTED;
658 }
659
660 if (!(group->url = heap_strdupW(url)))
661 return ERROR_OUTOFMEMORY;
662 group->context = context;
663
664 if (group->queue)
665 return add_url(group->queue, url, context);
666
667 return ERROR_SUCCESS;
668 }
669
670 /***********************************************************************
671 * HttpRemoveUrlFromUrlGroup (HTTPAPI.@)
672 */
673 ULONG WINAPI HttpRemoveUrlFromUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, ULONG flags)
674 {
675 struct url_group *group = get_url_group(id);
676
677 TRACE("id %s, url %s, flags %#x.\n", wine_dbgstr_longlong(id), debugstr_w(url), flags);
678
679 if (!group->url)
680 return ERROR_FILE_NOT_FOUND;
681
682 if (flags)
683 FIXME("Ignoring flags %#x.\n", flags);
684
685 heap_free(group->url);
686 group->url = NULL;
687
688 if (group->queue)
689 return remove_url(group->queue, url);
690
691 return ERROR_SUCCESS;
692 }
693
694 /***********************************************************************
695 * HttpCreateRequestQueue (HTTPAPI.@)
696 */
697 ULONG WINAPI HttpCreateRequestQueue(HTTPAPI_VERSION version, const WCHAR *name,
698 SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle)
699 {
700 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
701 UNICODE_STRING string;
702 IO_STATUS_BLOCK iosb;
703
704 TRACE("version %u.%u, name %s, sa %p, flags %#x, handle %p.\n",
705 version.HttpApiMajorVersion, version.HttpApiMinorVersion,
706 debugstr_w(name), sa, flags, handle);
707
708 if (name)
709 FIXME("Unhandled name %s.\n", debugstr_w(name));
710 if (flags)
711 FIXME("Unhandled flags %#x.\n", flags);
712
713 RtlInitUnicodeString(&string, device_nameW);
714 attr.ObjectName = &string;
715 if (sa && sa->bInheritHandle)
716 attr.Attributes |= OBJ_INHERIT;
717 attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
718 return RtlNtStatusToDosError(NtCreateFile(handle, 0, &attr, &iosb, NULL,
719 FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0));
720 }
721
722 /***********************************************************************
723 * HttpCloseRequestQueue (HTTPAPI.@)
724 */
725 ULONG WINAPI HttpCloseRequestQueue(HANDLE handle)
726 {
727 TRACE("handle %p.\n", handle);
728 if (!CloseHandle(handle))
729 return GetLastError();
730 return ERROR_SUCCESS;
731 }