wine  6.0.1
About: Wine is an Open Source implementation of the MS Windows API on top of X, OpenGL, and Unix. Think of Wine as a compatibility layer for running Windows programs.
  Fossies Dox: wine-6.0.1.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

http.c
Go to the documentation of this file.
1 /*
2  * HTTP server driver
3  *
4  * Copyright 2019 Zebediah Figura
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 #include <assert.h>
22 #include "ntstatus.h"
23 #define WIN32_NO_STATUS
24 #include "wine/http.h"
25 #include "winternl.h"
26 #include "ddk/wdm.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/list.h"
30 
33 
35 
36 #define DECLARE_CRITICAL_SECTION(cs) \
37  static CRITICAL_SECTION cs; \
38  static CRITICAL_SECTION_DEBUG cs##_debug = \
39  { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
40  0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
41  static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
42 
44 
47 
49 
50 struct connection
51 {
52  struct list entry; /* in "connections" below */
53 
54  SOCKET socket;
55 
56  char *buffer;
57  unsigned int len, size;
58 
59  /* If there is a request fully received and waiting to be read, the
60  * "available" parameter will be TRUE. Either there is no queue matching
61  * the URL of this request yet ("queue" is NULL), there is a queue but no
62  * IRPs have arrived for this request yet ("queue" is non-NULL and "req_id"
63  * is HTTP_NULL_ID), or an IRP has arrived but did not provide a large
64  * enough buffer to read the whole request ("queue" is non-NULL and
65  * "req_id" is not HTTP_NULL_ID).
66  *
67  * If "available" is FALSE, either we are waiting for a new request
68  * ("req_id" is HTTP_NULL_ID), or we are waiting for the user to send a
69  * response ("req_id" is not HTTP_NULL_ID). */
73 
74  /* Things we already parsed out of the request header in parse_request().
75  * These are valid only if "available" is TRUE. */
76  unsigned int req_len;
79  const char *url, *host;
81 };
82 
83 static struct list connections = LIST_INIT(connections);
84 
86 {
87  struct list entry;
90  char *url;
91  SOCKET socket;
92 };
93 
95 
96 static void accept_connection(SOCKET socket)
97 {
98  struct connection *conn;
99  ULONG true = 1;
100  SOCKET peer;
101 
102  if ((peer = accept(socket, NULL, NULL)) == INVALID_SOCKET)
103  return;
104 
105  if (!(conn = heap_alloc_zero(sizeof(*conn))))
106  {
107  ERR("Failed to allocate memory.\n");
108  shutdown(peer, SD_BOTH);
109  closesocket(peer);
110  return;
111  }
112  if (!(conn->buffer = heap_alloc(8192)))
113  {
114  ERR("Failed to allocate buffer memory.\n");
115  heap_free(conn);
116  shutdown(peer, SD_BOTH);
117  closesocket(peer);
118  return;
119  }
120  conn->size = 8192;
122  ioctlsocket(peer, FIONBIO, &true);
123  conn->socket = peer;
124  list_add_head(&connections, &conn->entry);
125 }
126 
127 static void close_connection(struct connection *conn)
128 {
129  heap_free(conn->buffer);
130  shutdown(conn->socket, SD_BOTH);
131  closesocket(conn->socket);
132  list_remove(&conn->entry);
133  heap_free(conn);
134 }
135 
136 static HTTP_VERB parse_verb(const char *verb, int len)
137 {
138  static const char *const verbs[] =
139  {
140  "OPTIONS",
141  "GET",
142  "HEAD",
143  "POST",
144  "PUT",
145  "DELETE",
146  "TRACE",
147  "CONNECT",
148  "TRACK",
149  "MOVE",
150  "COPY",
151  "PROPFIND",
152  "PROPPATCH",
153  "MKCOL",
154  "LOCK",
155  "UNLOCK",
156  "SEARCH",
157  };
158  unsigned int i;
159 
160  for (i = 0; i < ARRAY_SIZE(verbs); ++i)
161  {
162  if (!strncmp(verb, verbs[i], len))
163  return HttpVerbOPTIONS + i;
164  }
165  return HttpVerbUnknown;
166 }
167 
168 /* Return the length of a token, as defined in RFC 2616 section 2.2. */
169 static int parse_token(const char *str, const char *end)
170 {
171  const char *p;
172  for (p = str; !end || p < end; ++p)
173  {
174  if (!isgraph(*p) || strchr("()<>@,;:\\\"/[]?={}", *p))
175  break;
176  }
177  return p - str;
178 }
179 
180 static HTTP_HEADER_ID parse_header_name(const char *header, int len)
181 {
182  static const char *const headers[] =
183  {
184  "Cache-Control",
185  "Connection",
186  "Date",
187  "Keep-Alive",
188  "Pragma",
189  "Trailer",
190  "Transfer-Encoding",
191  "Upgrade",
192  "Via",
193  "Warning",
194  "Allow",
195  "Content-Length",
196  "Content-Type",
197  "Content-Encoding",
198  "Content-Language",
199  "Content-Location",
200  "Content-MD5",
201  "Content-Range",
202  "Expires",
203  "Last-Modified",
204  "Accept",
205  "Accept-Charset",
206  "Accept-Encoding",
207  "Accept-Language",
208  "Authorization",
209  "Cookie",
210  "Expect",
211  "From",
212  "Host",
213  "If-Match",
214  "If-Modified-Since",
215  "If-None-Match",
216  "If-Range",
217  "If-Unmodified-Since",
218  "Max-Forwards",
219  "Proxy-Authorization",
220  "Referer",
221  "Range",
222  "TE",
223  "Translate",
224  "User-Agent",
225  };
226  unsigned int i;
227 
228  for (i = 0; i < ARRAY_SIZE(headers); ++i)
229  {
230  if (!strncmp(header, headers[i], len))
231  return i;
232  }
234 }
235 
236 static void parse_header(const char *name, int *name_len, const char **value, int *value_len)
237 {
238  const char *p = name;
239  *name_len = parse_token(name, NULL);
240  p += *name_len;
241  while (*p == ' ' || *p == '\t') ++p;
242  ++p; /* skip colon */
243  while (*p == ' ' || *p == '\t') ++p;
244  *value = p;
245  while (isprint(*p) || *p == '\t') ++p;
246  while (isspace(*p)) --p; /* strip trailing LWS */
247  *value_len = p - *value + 1;
248 }
249 
250 #define http_unknown_header http_unknown_header_64
251 #define http_data_chunk http_data_chunk_64
252 #define http_request http_request_64
253 #define complete_irp complete_irp_64
254 #define POINTER ULONGLONG
255 #include "request.h"
256 #undef http_unknown_header
257 #undef http_data_chunk
258 #undef http_request
259 #undef complete_irp
260 #undef POINTER
261 
262 #define http_unknown_header http_unknown_header_32
263 #define http_data_chunk http_data_chunk_32
264 #define http_request http_request_32
265 #define complete_irp complete_irp_32
266 #define POINTER ULONG
267 #include "request.h"
268 #undef http_unknown_header
269 #undef http_data_chunk
270 #undef http_request
271 #undef complete_irp
272 #undef POINTER
273 
274 static NTSTATUS complete_irp(struct connection *conn, IRP *irp)
275 {
276  const struct http_receive_request_params params
278 
279  TRACE("Completing IRP %p.\n", irp);
280 
281  if (!conn->req_id)
282  conn->req_id = ++req_id_counter;
283 
284  if (params.bits == 32)
285  return complete_irp_32(conn, irp);
286  else
287  return complete_irp_64(conn, irp);
288 }
289 
290 /* Complete an IOCTL_HTTP_RECEIVE_REQUEST IRP if there is one to complete. */
291 static void try_complete_irp(struct connection *conn)
292 {
293  LIST_ENTRY *entry;
294  if (conn->queue && (entry = RemoveHeadList(&conn->queue->irp_queue)) != &conn->queue->irp_queue)
295  {
296  IRP *irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
297  irp->IoStatus.Status = complete_irp(conn, irp);
299  }
300 }
301 
302 /* Return 1 if str matches expect, 0 if str is incomplete, -1 if they don't match. */
303 static int compare_exact(const char *str, const char *expect, const char *end)
304 {
305  while (*expect)
306  {
307  if (str >= end) return 0;
308  if (*str++ != *expect++) return -1;
309  }
310  return 1;
311 }
312 
313 static int parse_number(const char *str, const char **endptr, const char *end)
314 {
315  int n = 0;
316  while (str < end && isdigit(*str))
317  n = n * 10 + (*str++ - '0');
318  *endptr = str;
319  return n;
320 }
321 
322 static BOOL host_matches(const struct connection *conn, const struct request_queue *queue)
323 {
324  const char *conn_host = (conn->url[0] == '/') ? conn->host : conn->url + 7;
325 
326  if (queue->url[7] == '+')
327  {
328  const char *queue_port = strchr(queue->url + 7, ':');
329  return !strncmp(queue_port, strchr(conn_host, ':'), strlen(queue_port) - 1 /* strip final slash */);
330  }
331 
332  return !memicmp(queue->url + 7, conn_host, strlen(queue->url) - 8 /* strip final slash */);
333 }
334 
335 /* Upon receiving a request, parse it to ensure that it is a valid HTTP request,
336  * and mark down some information that we will use later. Returns 1 if we parsed
337  * a complete request, 0 if incomplete, -1 if invalid. */
338 static int parse_request(struct connection *conn)
339 {
340  const char *const req = conn->buffer, *const end = conn->buffer + conn->len;
341  struct request_queue *queue;
342  const char *p = req, *q;
343  int len, ret;
344 
345  if (!conn->len) return 0;
346 
347  TRACE("%s\n", wine_dbgstr_an(conn->buffer, conn->len));
348 
349  len = parse_token(p, end);
350  if (p + len >= end) return 0;
351  if (!len || p[len] != ' ') return -1;
352 
353  /* verb */
354  if ((conn->verb = parse_verb(p, len)) == HttpVerbUnknown)
355  conn->unk_verb_len = len;
356  p += len + 1;
357 
358  TRACE("Got verb %u (%s).\n", conn->verb, debugstr_an(req, len));
359 
360  /* URL */
361  conn->url = p;
362  while (p < end && isgraph(*p)) ++p;
363  conn->url_len = p - conn->url;
364  if (p >= end) return 0;
365  if (!conn->url_len) return -1;
366 
367  TRACE("Got URI %s.\n", debugstr_an(conn->url, conn->url_len));
368 
369  /* version */
370  if ((ret = compare_exact(p, " HTTP/", end)) <= 0) return ret;
371  p += 6;
372  conn->version.MajorVersion = parse_number(p, &q, end);
373  if (q >= end) return 0;
374  if (q == p || *q != '.') return -1;
375  p = q + 1;
376  if (p >= end) return 0;
377  conn->version.MinorVersion = parse_number(p, &q, end);
378  if (q >= end) return 0;
379  if (q == p) return -1;
380  p = q;
381  if ((ret = compare_exact(p, "\r\n", end)) <= 0) return ret;
382  p += 2;
383 
384  TRACE("Got version %hu.%hu.\n", conn->version.MajorVersion, conn->version.MinorVersion);
385 
386  /* headers */
387  conn->host = NULL;
388  conn->content_len = 0;
389  for (;;)
390  {
391  const char *name = p;
392 
393  if (!(ret = compare_exact(p, "\r\n", end))) return 0;
394  else if (ret > 0) break;
395 
396  len = parse_token(p, end);
397  if (p + len >= end) return 0;
398  if (!len) return -1;
399  p += len;
400  while (p < end && (*p == ' ' || *p == '\t')) ++p;
401  if (p >= end) return 0;
402  if (*p != ':') return -1;
403  ++p;
404  while (p < end && (*p == ' ' || *p == '\t')) ++p;
405 
406  TRACE("Got %s header.\n", debugstr_an(name, len));
407 
408  if (!strncmp(name, "Host", len))
409  conn->host = p;
410  else if (!strncmp(name, "Content-Length", len))
411  {
412  conn->content_len = parse_number(p, &q, end);
413  if (q >= end) return 0;
414  if (q == p) return -1;
415  }
416  else if (!strncmp(name, "Transfer-Encoding", len))
417  FIXME("Unhandled Transfer-Encoding header.\n");
418  while (p < end && (isprint(*p) || *p == '\t')) ++p;
419  if ((ret = compare_exact(p, "\r\n", end)) <= 0) return ret;
420  p += 2;
421  }
422  p += 2;
423  if (conn->url[0] == '/' && !conn->host) return -1;
424 
425  if (end - p < conn->content_len) return 0;
426 
427  conn->req_len = (p - req) + conn->content_len;
428 
429  TRACE("Received a full request, length %u bytes.\n", conn->req_len);
430 
431  conn->queue = NULL;
432  /* Find a queue which can receive this request. */
434  {
435  if (host_matches(conn, queue))
436  {
437  TRACE("Assigning request to queue %p.\n", queue);
438  conn->queue = queue;
439  break;
440  }
441  }
442 
443  /* Stop selecting on incoming data until a response is queued. */
445 
446  conn->available = TRUE;
447  try_complete_irp(conn);
448 
449  return 1;
450 }
451 
452 static void format_date(char *buffer)
453 {
454  static const char day_names[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
455  static const char month_names[12][4] =
456  {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
457  SYSTEMTIME date;
458  GetSystemTime(&date);
459  sprintf(buffer + strlen(buffer), "Date: %s, %02u %s %u %02u:%02u:%02u GMT\r\n",
460  day_names[date.wDayOfWeek], date.wDay, month_names[date.wMonth - 1],
461  date.wYear, date.wHour, date.wMinute, date.wSecond);
462 }
463 
464 /* Send a 400 Bad Request response. */
465 static void send_400(struct connection *conn)
466 {
467  static const char response_header[] = "HTTP/1.1 400 Bad Request\r\n";
468  static const char response_body[] =
469  "Content-Type: text/html; charset=utf-8\r\n"
470  "Content-Language: en\r\n"
471  "Connection: close\r\n";
472  char buffer[sizeof(response_header) + sizeof(response_body) + 37];
473 
474  strcpy(buffer, response_header);
476  strcat(buffer, response_body);
477  if (send(conn->socket, buffer, strlen(buffer), 0) < 0)
478  ERR("Failed to send 400 response, error %u.\n", WSAGetLastError());
479 }
480 
481 static void receive_data(struct connection *conn)
482 {
483  int len, ret;
484 
485  /* We might be waiting for an IRP, but always call recv() anyway, since we
486  * might have been woken up by the socket closing. */
487  if ((len = recv(conn->socket, conn->buffer + conn->len, conn->size - conn->len, 0)) <= 0)
488  {
490  return; /* nothing to receive */
491  else if (!len)
492  TRACE("Connection was shut down by peer.\n");
493  else
494  ERR("Got error %u; shutting down connection.\n", WSAGetLastError());
495  close_connection(conn);
496  return;
497  }
498  conn->len += len;
499 
500  if (conn->available)
501  return; /* waiting for an HttpReceiveHttpRequest() call */
502  if (conn->req_id != HTTP_NULL_ID)
503  return; /* waiting for an HttpSendHttpResponse() call */
504 
505  TRACE("Received %u bytes of data.\n", len);
506 
507  if (!(ret = parse_request(conn)))
508  {
510  ioctlsocket(conn->socket, FIONREAD, &available);
511  if (available)
512  {
513  TRACE("%u more bytes of data available, trying with larger buffer.\n", available);
514  if (!(conn->buffer = heap_realloc(conn->buffer, conn->len + available)))
515  {
516  ERR("Failed to allocate %u bytes of memory.\n", conn->len + available);
517  close_connection(conn);
518  return;
519  }
520  conn->size = conn->len + available;
521 
522  if ((len = recv(conn->socket, conn->buffer + conn->len, conn->size - conn->len, 0)) < 0)
523  {
524  ERR("Got error %u; shutting down connection.\n", WSAGetLastError());
525  close_connection(conn);
526  return;
527  }
528  TRACE("Received %u bytes of data.\n", len);
529  conn->len += len;
530  ret = parse_request(conn);
531  }
532  }
533  if (!ret)
534  TRACE("Request is incomplete, waiting for more data.\n");
535  else if (ret < 0)
536  {
537  WARN("Failed to parse request; shutting down connection.\n");
538  send_400(conn);
539  close_connection(conn);
540  }
541 }
542 
544 {
545  struct connection *conn, *cursor;
546  struct request_queue *queue;
547 
548  TRACE("Starting request thread.\n");
549 
551  {
553 
555  {
556  if (queue->socket != -1)
557  accept_connection(queue->socket);
558  }
559 
561  {
562  receive_data(conn);
563  }
564 
566  }
567 
568  TRACE("Stopping request thread.\n");
569 
570  return 0;
571 }
572 
574 {
575  const struct http_add_url_params *params = irp->AssociatedIrp.SystemBuffer;
576  struct sockaddr_in addr;
577  struct connection *conn;
578  unsigned int count = 0;
579  char *url, *endptr;
580  ULONG true = 1;
581  const char *p;
582  SOCKET s;
583 
584  TRACE("host %s, context %s.\n", debugstr_a(params->url), wine_dbgstr_longlong(params->context));
585 
586  if (!strncmp(params->url, "https://", 8))
587  {
588  FIXME("HTTPS is not implemented.\n");
589  return STATUS_NOT_IMPLEMENTED;
590  }
591  else if (strncmp(params->url, "http://", 7) || !strchr(params->url + 7, ':')
592  || params->url[strlen(params->url) - 1] != '/')
594  if (!(addr.sin_port = htons(strtol(strchr(params->url + 7, ':') + 1, &endptr, 10))) || *endptr != '/')
596 
597  if (!(url = heap_alloc(strlen(params->url)+1)))
598  return STATUS_NO_MEMORY;
599  strcpy(url, params->url);
600 
601  for (p = url; *p; ++p)
602  if (*p == '/') ++count;
603  if (count > 3)
604  FIXME("Binding to relative URIs is not implemented; binding to all URIs instead.\n");
605 
607 
608  if (queue->url && !strcmp(queue->url, url))
609  {
611  heap_free(url);
613  }
614  else if (queue->url)
615  {
616  FIXME("Binding to multiple URLs is not implemented.\n");
618  heap_free(url);
619  return STATUS_NOT_IMPLEMENTED;
620  }
621 
622  if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
623  {
624  ERR("Failed to create socket, error %u.\n", WSAGetLastError());
626  heap_free(url);
627  return STATUS_UNSUCCESSFUL;
628  }
629 
630  addr.sin_family = AF_INET;
631  addr.sin_addr.S_un.S_addr = INADDR_ANY;
632  if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
633  {
635  closesocket(s);
636  heap_free(url);
638  {
639  WARN("Address %s is already in use.\n", debugstr_a(params->url));
641  }
642  else if (WSAGetLastError() == WSAEACCES)
643  {
644  WARN("Not enough permissions to bind to address %s.\n", debugstr_a(params->url));
645  return STATUS_ACCESS_DENIED;
646  }
647  ERR("Failed to bind socket, error %u.\n", WSAGetLastError());
648  return STATUS_UNSUCCESSFUL;
649  }
650 
651  if (listen(s, SOMAXCONN) == -1)
652  {
653  ERR("Failed to listen to port %u, error %u.\n", addr.sin_port, WSAGetLastError());
655  closesocket(s);
656  heap_free(url);
658  }
659 
660  ioctlsocket(s, FIONBIO, &true);
662  queue->socket = s;
663  queue->url = url;
664  queue->context = params->context;
665 
666  /* See if any pending requests now match this queue. */
668  {
669  if (conn->available && !conn->queue && host_matches(conn, queue))
670  {
671  conn->queue = queue;
672  try_complete_irp(conn);
673  }
674  }
675 
677 
678  return STATUS_SUCCESS;
679 }
680 
682 {
683  const char *url = irp->AssociatedIrp.SystemBuffer;
684 
685  TRACE("host %s.\n", debugstr_a(url));
686 
688 
689  if (!queue->url || strcmp(url, queue->url))
690  {
693  }
694  heap_free(queue->url);
695  queue->url = NULL;
696 
698  return STATUS_SUCCESS;
699 }
700 
702 {
703  struct connection *conn;
704 
706  {
707  if (conn->req_id == req_id)
708  return conn;
709  }
710  return NULL;
711 }
712 
714 {
715  TRACE("device %p, irp %p.\n", device, irp);
716 
718 
722 
725 }
726 
728 {
729  const struct http_receive_request_params *params = irp->AssociatedIrp.SystemBuffer;
730  struct connection *conn;
731  NTSTATUS ret;
732 
733  TRACE("addr %s, id %s, flags %#x, bits %u.\n", wine_dbgstr_longlong(params->addr),
734  wine_dbgstr_longlong(params->id), params->flags, params->bits);
735 
737 
738  if ((conn = get_connection(params->id)) && conn->available && conn->queue == queue)
739  {
740  ret = complete_irp(conn, irp);
742  return ret;
743  }
744 
745  if (params->id == HTTP_NULL_ID)
746  {
747  TRACE("Queuing IRP %p.\n", irp);
748 
750  if (irp->Cancel && !IoSetCancelRoutine(irp, NULL))
751  {
752  /* The IRP was canceled before we set the cancel routine. */
753  ret = STATUS_CANCELLED;
754  }
755  else
756  {
757  IoMarkIrpPending(irp);
758  InsertTailList(&queue->irp_queue, &irp->Tail.Overlay.ListEntry);
759  ret = STATUS_PENDING;
760  }
761  }
762  else
764 
766 
767  return ret;
768 }
769 
771 {
772  const struct http_response *response = irp->AssociatedIrp.SystemBuffer;
773  struct connection *conn;
774 
775  TRACE("id %s, len %d.\n", wine_dbgstr_longlong(response->id), response->len);
776 
778 
779  if ((conn = get_connection(response->id)))
780  {
781  if (send(conn->socket, response->buffer, response->len, 0) >= 0)
782  {
783  if (conn->content_len)
784  {
785  /* Discard whatever entity body is left. */
786  memmove(conn->buffer, conn->buffer + conn->content_len, conn->len - conn->content_len);
787  conn->len -= conn->content_len;
788  }
789 
790  conn->queue = NULL;
791  conn->req_id = HTTP_NULL_ID;
793  irp->IoStatus.Information = response->len;
794  /* We might have another request already in the buffer. */
795  if (parse_request(conn) < 0)
796  {
797  WARN("Failed to parse request; shutting down connection.\n");
798  send_400(conn);
799  close_connection(conn);
800  }
801  }
802  else
803  {
804  ERR("Got error %u; shutting down connection.\n", WSAGetLastError());
805  close_connection(conn);
806  }
807 
809  return STATUS_SUCCESS;
810  }
811 
814 }
815 
817 {
818  const struct http_receive_body_params *params = irp->AssociatedIrp.SystemBuffer;
820  const DWORD output_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
821  struct connection *conn;
822  NTSTATUS ret;
823 
824  TRACE("id %s, bits %u.\n", wine_dbgstr_longlong(params->id), params->bits);
825 
827 
828  if ((conn = get_connection(params->id)))
829  {
830  TRACE("%u bits remaining.\n", conn->content_len);
831 
832  if (conn->content_len)
833  {
834  ULONG len = min(conn->content_len, output_len);
836  memmove(conn->buffer, conn->buffer + len, conn->len - len);
837  conn->content_len -= len;
838  conn->len -= len;
839 
840  irp->IoStatus.Information = len;
841  ret = STATUS_SUCCESS;
842  }
843  else
844  ret = STATUS_END_OF_FILE;
845  }
846  else
848 
850 
851  return ret;
852 }
853 
855 {
857  struct request_queue *queue = stack->FileObject->FsContext;
858  NTSTATUS ret;
859 
860  switch (stack->Parameters.DeviceIoControl.IoControlCode)
861  {
862  case IOCTL_HTTP_ADD_URL:
863  ret = http_add_url(queue, irp);
864  break;
866  ret = http_remove_url(queue, irp);
867  break;
869  ret = http_receive_request(queue, irp);
870  break;
872  ret = http_send_response(queue, irp);
873  break;
875  ret = http_receive_body(queue, irp);
876  break;
877  default:
878  FIXME("Unhandled ioctl %#x.\n", stack->Parameters.DeviceIoControl.IoControlCode);
880  }
881 
882  if (ret != STATUS_PENDING)
883  {
884  irp->IoStatus.Status = ret;
886  }
887  return ret;
888 }
889 
891 {
893  struct request_queue *queue;
894 
895  if (!(queue = heap_alloc_zero(sizeof(*queue))))
896  return STATUS_NO_MEMORY;
897  stack->FileObject->FsContext = queue;
898  InitializeListHead(&queue->irp_queue);
899 
903 
904  TRACE("Created queue %p.\n", queue);
905 
908  return STATUS_SUCCESS;
909 }
910 
911 static void close_queue(struct request_queue *queue)
912 {
914  list_remove(&queue->entry);
915  if (queue->socket != -1)
916  {
917  shutdown(queue->socket, SD_BOTH);
918  closesocket(queue->socket);
919  }
921 
922  heap_free(queue->url);
923  heap_free(queue);
924 }
925 
927 {
929  struct request_queue *queue = stack->FileObject->FsContext;
930  LIST_ENTRY *entry;
931 
932  TRACE("Closing queue %p.\n", queue);
933 
935 
936  while ((entry = queue->irp_queue.Flink) != &queue->irp_queue)
937  {
938  IRP *queued_irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
939  IoCancelIrp(queued_irp);
940  }
941 
943 
945 
948  return STATUS_SUCCESS;
949 }
950 
952 {
953  struct request_queue *queue, *queue_next;
954  struct connection *conn, *conn_next;
955 
956  thread_stop = TRUE;
961 
962  LIST_FOR_EACH_ENTRY_SAFE(conn, conn_next, &connections, struct connection, entry)
963  {
964  close_connection(conn);
965  }
966 
968  {
970  }
971 
972  WSACleanup();
973 
976 }
977 
979 {
980  OBJECT_ATTRIBUTES attr = {sizeof(attr)};
982  WSADATA wsadata;
983  NTSTATUS ret;
984 
985  TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
986 
987  RtlInitUnicodeString(&string, L"\\Device\\Http");
988  attr.ObjectName = &string;
990  ERR("Failed to create \\Device\\Http directory, status %#x.\n", ret);
991 
992  RtlInitUnicodeString(&string, L"\\Device\\Http\\ReqQueue");
993  if ((ret = IoCreateDevice(driver, 0, &string, FILE_DEVICE_UNKNOWN, 0, FALSE, &device_obj)))
994  {
995  ERR("Failed to create request queue device, status %#x.\n", ret);
997  return ret;
998  }
999 
1000  driver->MajorFunction[IRP_MJ_CREATE] = dispatch_create;
1001  driver->MajorFunction[IRP_MJ_CLOSE] = dispatch_close;
1002  driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dispatch_ioctl;
1003  driver->DriverUnload = unload;
1004 
1005  WSAStartup(MAKEWORD(1,1), &wsadata);
1006 
1009 
1010  return STATUS_SUCCESS;
1011 }
LONG NTSTATUS
Definition: bcrypt.h:40
#define WINAPI
Definition: bcrypt.h:23
#define ERR(...)
Definition: cocoa_app.h:61
static int memicmp(const void *s1, const void *s2, size_t len)
int isdigit(int c)
Definition: ctype.c:246
int isgraph(int c)
Definition: ctype.c:262
int isspace(int c)
Definition: ctype.c:342
int isprint(int c)
Definition: ctype.c:310
static WCHAR available[128]
Definition: object.c:2372
void GetSystemTime(SYSTEMTIME *systime)
Definition: file.c:3883
BOOL CloseHandle(HANDLE handle)
Definition: process.c:390
HANDLE CreateThread(SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, LPDWORD id)
Definition: thread.c:111
size_t strlen(const char *str)
Definition: string.c:1502
void * memcpy(void *dst, const void *src, size_t n)
Definition: string.c:2580
char * strcpy(char *dst, const char *src)
Definition: string.c:1263
char * strcat(char *dst, const char *src)
Definition: string.c:1324
int strncmp(const char *str1, const char *str2, size_t len)
Definition: string.c:2642
int strcmp(const char *str1, const char *str2)
Definition: string.c:2631
__msvcrt_long strtol(const char *nptr, char **end, int base)
Definition: string.c:1743
void * memmove(void *dst, const void *src, size_t n)
Definition: string.c:2481
char * strchr(const char *str, int c)
Definition: string.c:2598
NTSTATUS NtClose(HANDLE handle)
Definition: server.c:1666
@ L
Definition: bidi.c:78
long BOOL
Definition: dxgitype.idl:24
const char * str
Definition: glu.c:32
static void heap_free(void *mem)
Definition: heap.h:44
HTTP_OPAQUE_ID HTTP_REQUEST_ID
Definition: http.h:78
ULONGLONG HTTP_URL_CONTEXT
Definition: http.h:81
#define HTTP_NULL_ID
Definition: http.h:73
enum _HTTP_VERB HTTP_VERB
@ HttpHeaderRequestMaximum
Definition: http.h:190
@ HttpVerbUnknown
Definition: http.h:92
@ HttpVerbOPTIONS
Definition: http.h:94
enum _HTTP_HEADER_ID HTTP_HEADER_ID
static NTSTATUS dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp)
Definition: http.c:854
static struct connection * get_connection(HTTP_REQUEST_ID req_id)
Definition: http.c:701
NTSTATUS DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
Definition: http.c:978
static HANDLE request_thread
Definition: http.c:43
static void format_date(char *buffer)
Definition: http.c:452
#define complete_irp
Definition: http.c:265
static struct list connections
Definition: http.c:83
static HTTP_REQUEST_ID req_id_counter
Definition: http.c:48
static NTSTATUS http_receive_request(struct request_queue *queue, IRP *irp)
Definition: http.c:727
static int parse_token(const char *str, const char *end)
Definition: http.c:169
static void parse_header(const char *name, int *name_len, const char **value, int *value_len)
Definition: http.c:236
static BOOL thread_stop
Definition: http.c:46
static void send_400(struct connection *conn)
Definition: http.c:465
static NTSTATUS dispatch_create(DEVICE_OBJECT *device, IRP *irp)
Definition: http.c:890
static CRITICAL_SECTION http_cs
Definition: http.c:43
static BOOL host_matches(const struct connection *conn, const struct request_queue *queue)
Definition: http.c:322
static int compare_exact(const char *str, const char *expect, const char *end)
Definition: http.c:303
static void accept_connection(SOCKET socket)
Definition: http.c:96
static void try_complete_irp(struct connection *conn)
Definition: http.c:291
static void close_queue(struct request_queue *queue)
Definition: http.c:911
static DEVICE_OBJECT * device_obj
Definition: http.c:32
static void receive_data(struct connection *conn)
Definition: http.c:481
#define DECLARE_CRITICAL_SECTION(cs)
Definition: http.c:36
static NTSTATUS dispatch_close(DEVICE_OBJECT *device, IRP *irp)
Definition: http.c:926
static HTTP_HEADER_ID parse_header_name(const char *header, int len)
Definition: http.c:180
static HTTP_VERB parse_verb(const char *verb, int len)
Definition: http.c:136
static void close_connection(struct connection *conn)
Definition: http.c:127
static void unload(DRIVER_OBJECT *driver)
Definition: http.c:951
static NTSTATUS http_remove_url(struct request_queue *queue, IRP *irp)
Definition: http.c:681
static NTSTATUS http_receive_body(struct request_queue *queue, IRP *irp)
Definition: http.c:816
static NTSTATUS http_add_url(struct request_queue *queue, IRP *irp)
Definition: http.c:573
static DWORD request_thread_proc(void *arg)
Definition: http.c:543
static int parse_number(const char *str, const char **endptr, const char *end)
Definition: http.c:313
static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp)
Definition: http.c:770
static HANDLE request_event
Definition: http.c:45
static HANDLE directory_obj
Definition: http.c:31
static void http_receive_request_cancel(DEVICE_OBJECT *device, IRP *irp)
Definition: http.c:713
static struct list request_queues
Definition: http.c:94
static int parse_request(struct connection *conn)
Definition: http.c:338
static const char * wine_dbgstr_an(const char *str, int n)
Definition: debug.h:221
static const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: debug.h:344
#define WINE_DEFAULT_DEBUG_CHANNEL(ch)
Definition: debug.h:499
HANDLE CreateEventW(SECURITY_ATTRIBUTES *sa, BOOL manual_reset, BOOL initial_state, LPCWSTR name)
Definition: sync.c:391
DWORD WaitForSingleObject(HANDLE handle, DWORD timeout)
Definition: sync.c:299
BOOL SetEvent(HANDLE handle)
Definition: sync.c:504
static void list_remove(struct list *elem)
Definition: list.h:98
static void list_add_head(struct list *list, struct list *elem)
Definition: list.h:86
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:188
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:194
#define LIST_INIT(list)
Definition: list.h:227
#define min(a, b)
Definition: minmax.h:28
static void size_t len
ULONG end
Definition: error.c:1729
NTSTATUS NtCreateDirectoryObject(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
Definition: sync.c:911
void IoCompleteRequest(IRP *irp, UCHAR priority_boost)
Definition: ntoskrnl.c:1901
NTSTATUS IoCreateDevice(DRIVER_OBJECT *driver, ULONG ext_size, UNICODE_STRING *name, DWORD type, ULONG characteristics, BOOLEAN exclusive, DEVICE_OBJECT **ret_device)
Definition: ntoskrnl.c:1490
void IoDeleteDevice(DEVICE_OBJECT *device)
Definition: ntoskrnl.c:1561
BOOLEAN IoCancelIrp(IRP *irp)
Definition: ntoskrnl.c:1964
void IoReleaseCancelSpinLock(KIRQL irql)
Definition: sync.c:731
PSecurityUserData *typedef PSECPKG_EXTENDED_INFORMATION *typedef ULONG
Definition: ntsecpkg.h:377
#define STATUS_ACCESS_DENIED
Definition: ntstatus.h:244
#define STATUS_END_OF_FILE
Definition: ntstatus.h:227
#define STATUS_INVALID_PARAMETER
Definition: ntstatus.h:223
#define STATUS_PENDING
Definition: ntstatus.h:48
#define STATUS_NO_MEMORY
Definition: ntstatus.h:233
#define STATUS_CONNECTION_INVALID
Definition: ntstatus.h:696
#define STATUS_UNSUCCESSFUL
Definition: ntstatus.h:211
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:212
#define STATUS_OBJECT_NAME_COLLISION
Definition: ntstatus.h:263
#define STATUS_SHARING_VIOLATION
Definition: ntstatus.h:277
#define STATUS_SUCCESS
Definition: ntstatus.h:30
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: ntstatus.h:262
#define STATUS_CANCELLED
Definition: ntstatus.h:498
char * url
Definition: main.c:55
void * heap_realloc(void *op, size_t len)
Definition: util.c:38
void * heap_alloc(size_t len)
Definition: util.c:30
WCHAR name[22]
Definition: registrar.c:32
void RtlInitUnicodeString(PUNICODE_STRING target, PCWSTR source)
Definition: rtlstr.c:171
#define FD_READ
Definition: sock.c:111
#define FD_CLOSE
Definition: sock.c:116
#define FD_ACCEPT
Definition: sock.c:114
PVOID FsContext
Definition: wdm.h:623
USHORT MajorVersion
Definition: http.h:85
USHORT MinorVersion
Definition: http.h:86
union _IO_STACK_LOCATION::@1029 Parameters
PFILE_OBJECT FileObject
Definition: wdm.h:998
struct _IO_STACK_LOCATION::@1029::@1036 DeviceIoControl
NTSTATUS Status
Definition: winternl.h:1470
ULONG_PTR Information
Definition: winternl.h:1474
Definition: wdm.h:511
LIST_ENTRY ListEntry
Definition: wdm.h:553
PVOID SystemBuffer
Definition: wdm.h:519
union _IRP::@1001 AssociatedIrp
KIRQL CancelIrql
Definition: wdm.h:528
union _IRP::@1003 Tail
BOOLEAN Cancel
Definition: wdm.h:527
IO_STATUS_BLOCK IoStatus
Definition: wdm.h:522
union _IRP::@1002 Overlay
Definition: winnt.h:836
WORD wYear
Definition: winbase.h:536
WORD wMonth
Definition: winbase.h:537
WORD wHour
Definition: winbase.h:540
WORD wSecond
Definition: winbase.h:542
WORD wMinute
Definition: winbase.h:541
WORD wDay
Definition: winbase.h:539
WORD wDayOfWeek
Definition: winbase.h:538
Definition: cookie.c:202
HTTP_REQUEST_ID req_id
Definition: http.c:72
unsigned int req_len
Definition: http.c:76
ULONG unk_verb_len
Definition: http.c:80
const char * url
Definition: http.c:79
HTTP_VERB verb
Definition: http.c:77
struct list entry
Definition: http.c:52
unsigned int size
Definition: http.c:57
ULONG url_len
Definition: http.c:80
const char * host
Definition: http.c:79
struct request_queue * queue
Definition: http.c:71
unsigned int len
Definition: http.c:57
ULONG content_len
Definition: http.c:80
SOCKET socket
Definition: http.c:54
HTTP_VERSION version
Definition: http.c:78
BOOL available
Definition: http.c:70
char * buffer
Definition: http.c:56
Definition: msg.c:48
HTTP_URL_CONTEXT context
Definition: http.h:34
char url[1]
Definition: http.h:35
HTTP_REQUEST_ID id
Definition: http.h:55
HTTP_REQUEST_ID id
Definition: http.h:41
HTTP_REQUEST_ID id
Definition: http.h:48
int len
Definition: http.h:49
char buffer[1]
Definition: http.h:50
Definition: list.h:27
Definition: name.c:36
Definition: queue.c:172
SOCKET socket
Definition: http.c:91
LIST_ENTRY irp_queue
Definition: http.c:88
char * url
Definition: http.c:90
HTTP_URL_CONTEXT context
Definition: http.c:89
struct list entry
Definition: http.c:87
#define NULL
Definition: ungif.h:66
#define TRUE
Definition: ungif.h:59
#define FALSE
Definition: ungif.h:62
Definition: pdh_main.c:90
int sprintf(char *str, const char *format,...)
Definition: wcs.c:1532
#define IO_NO_INCREMENT
Definition: wdm.h:305
#define IoGetCurrentIrpStackLocation(_Irp)
Definition: wdm.h:1586
#define IRP_MJ_CLOSE
Definition: wdm.h:324
#define IoSetCancelRoutine(irp, routine)
Definition: wdm.h:1592
#define IRP_MJ_DEVICE_CONTROL
Definition: wdm.h:336
static void IoMarkIrpPending(IRP *irp)
Definition: wdm.h:1607
#define IRP_MJ_CREATE
Definition: wdm.h:322
#define ARRAY_SIZE(x)
Definition: utils.h:37
DECLSPEC_IMPORT void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit)
#define INFINITE
Definition: winbase.h:377
DECLSPEC_IMPORT void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit)
unsigned int DWORD
Definition: windef.h:261
#define MAKEWORD(low, high)
Definition: windef.h:365
#define IOCTL_HTTP_SEND_RESPONSE
Definition: http.h:29
#define IOCTL_HTTP_RECEIVE_BODY
Definition: http.h:30
#define IOCTL_HTTP_RECEIVE_REQUEST
Definition: http.h:28
#define IOCTL_HTTP_REMOVE_URL
Definition: http.h:27
#define IOCTL_HTTP_ADD_URL
Definition: http.h:26
#define WSAEWOULDBLOCK
Definition: winerror.h:2318
#define WSAEACCES
Definition: winerror.h:2310
#define WSAEADDRINUSE
Definition: winerror.h:2331
#define FILE_DEVICE_UNKNOWN
Definition: winioctl.h:61
#define CONTAINING_RECORD(address, type, field)
Definition: winnt.h:826
#define SD_BOTH
Definition: winsock2.h:128
#define SOCK_STREAM
Definition: winsock2.h:82
#define InsertTailList(le, e)
Definition: winternl.h:3819
#define InitializeListHead(le)
Definition: winternl.h:3817
static PLIST_ENTRY RemoveHeadList(PLIST_ENTRY le)
Definition: winternl.h:3822
#define RemoveEntryList(e)
Definition: winternl.h:3821
INT WSACleanup(void)
Definition: socket.c:1866
int WSAEventSelect(SOCKET s, HANDLE hEvent, LONG lEvent)
Definition: socket.c:7220
INT WSAGetLastError(void)
Definition: socket.c:1889
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
Definition: socket.c:1836
static void * heap_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: wusa.h:88