ReactOS  0.4.14-dev-593-g1793dcc
request.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004 Mike McCormack for CodeWeavers
3  * Copyright 2006 Rob Shearman for CodeWeavers
4  * Copyright 2008, 2011 Hans Leidekker for CodeWeavers
5  * Copyright 2009 Juan Lang
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 #include "config.h"
24 #include "ws2tcpip.h"
25 #include <stdarg.h>
26 #include <assert.h>
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "ole2.h"
31 #include "initguid.h"
32 #include "httprequest.h"
33 #include "httprequestid.h"
34 #include "schannel.h"
35 #include "winhttp.h"
36 
37 #include "wine/debug.h"
38 #include "winhttp_private.h"
39 
41 
42 #ifdef __REACTOS__
43 #include "inet_ntop.c"
44 #endif
45 
46 #define DEFAULT_KEEP_ALIVE_TIMEOUT 30000
47 
48 static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0};
49 static const WCHAR attr_accept_charset[] = {'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0};
50 static const WCHAR attr_accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0};
51 static const WCHAR attr_accept_language[] = {'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0};
52 static const WCHAR attr_accept_ranges[] = {'A','c','c','e','p','t','-','R','a','n','g','e','s',0};
53 static const WCHAR attr_age[] = {'A','g','e',0};
54 static const WCHAR attr_allow[] = {'A','l','l','o','w',0};
55 static const WCHAR attr_authorization[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',0};
56 static const WCHAR attr_cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
57 static const WCHAR attr_connection[] = {'C','o','n','n','e','c','t','i','o','n',0};
58 static const WCHAR attr_content_base[] = {'C','o','n','t','e','n','t','-','B','a','s','e',0};
59 static const WCHAR attr_content_encoding[] = {'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0};
60 static const WCHAR attr_content_id[] = {'C','o','n','t','e','n','t','-','I','D',0};
61 static const WCHAR attr_content_language[] = {'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0};
62 static const WCHAR attr_content_length[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
63 static const WCHAR attr_content_location[] = {'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0};
64 static const WCHAR attr_content_md5[] = {'C','o','n','t','e','n','t','-','M','D','5',0};
65 static const WCHAR attr_content_range[] = {'C','o','n','t','e','n','t','-','R','a','n','g','e',0};
66 static const WCHAR attr_content_transfer_encoding[] = {'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
67 static const WCHAR attr_content_type[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0};
68 static const WCHAR attr_cookie[] = {'C','o','o','k','i','e',0};
69 static const WCHAR attr_date[] = {'D','a','t','e',0};
70 static const WCHAR attr_from[] = {'F','r','o','m',0};
71 static const WCHAR attr_etag[] = {'E','T','a','g',0};
72 static const WCHAR attr_expect[] = {'E','x','p','e','c','t',0};
73 static const WCHAR attr_expires[] = {'E','x','p','i','r','e','s',0};
74 static const WCHAR attr_host[] = {'H','o','s','t',0};
75 static const WCHAR attr_if_match[] = {'I','f','-','M','a','t','c','h',0};
76 static const WCHAR attr_if_modified_since[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0};
77 static const WCHAR attr_if_none_match[] = {'I','f','-','N','o','n','e','-','M','a','t','c','h',0};
78 static const WCHAR attr_if_range[] = {'I','f','-','R','a','n','g','e',0};
79 static const WCHAR attr_if_unmodified_since[] = {'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0};
80 static const WCHAR attr_last_modified[] = {'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
81 static const WCHAR attr_location[] = {'L','o','c','a','t','i','o','n',0};
82 static const WCHAR attr_max_forwards[] = {'M','a','x','-','F','o','r','w','a','r','d','s',0};
83 static const WCHAR attr_mime_version[] = {'M','i','m','e','-','V','e','r','s','i','o','n',0};
84 static const WCHAR attr_pragma[] = {'P','r','a','g','m','a',0};
85 static const WCHAR attr_proxy_authenticate[] = {'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0};
86 static const WCHAR attr_proxy_authorization[] = {'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0};
87 static const WCHAR attr_proxy_connection[] = {'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0};
88 static const WCHAR attr_public[] = {'P','u','b','l','i','c',0};
89 static const WCHAR attr_range[] = {'R','a','n','g','e',0};
90 static const WCHAR attr_referer[] = {'R','e','f','e','r','e','r',0};
91 static const WCHAR attr_retry_after[] = {'R','e','t','r','y','-','A','f','t','e','r',0};
92 static const WCHAR attr_server[] = {'S','e','r','v','e','r',0};
93 static const WCHAR attr_set_cookie[] = {'S','e','t','-','C','o','o','k','i','e',0};
94 static const WCHAR attr_status[] = {'S','t','a','t','u','s',0};
95 static const WCHAR attr_transfer_encoding[] = {'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
96 static const WCHAR attr_unless_modified_since[] = {'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0};
97 static const WCHAR attr_upgrade[] = {'U','p','g','r','a','d','e',0};
98 static const WCHAR attr_uri[] = {'U','R','I',0};
99 static const WCHAR attr_user_agent[] = {'U','s','e','r','-','A','g','e','n','t',0};
100 static const WCHAR attr_vary[] = {'V','a','r','y',0};
101 static const WCHAR attr_via[] = {'V','i','a',0};
102 static const WCHAR attr_warning[] = {'W','a','r','n','i','n','g',0};
103 static const WCHAR attr_www_authenticate[] = {'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0};
104 
105 static const WCHAR *attribute_table[] =
106 {
107  attr_mime_version, /* WINHTTP_QUERY_MIME_VERSION = 0 */
108  attr_content_type, /* WINHTTP_QUERY_CONTENT_TYPE = 1 */
109  attr_content_transfer_encoding, /* WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
110  attr_content_id, /* WINHTTP_QUERY_CONTENT_ID = 3 */
111  NULL, /* WINHTTP_QUERY_CONTENT_DESCRIPTION = 4 */
112  attr_content_length, /* WINHTTP_QUERY_CONTENT_LENGTH = 5 */
113  attr_content_language, /* WINHTTP_QUERY_CONTENT_LANGUAGE = 6 */
114  attr_allow, /* WINHTTP_QUERY_ALLOW = 7 */
115  attr_public, /* WINHTTP_QUERY_PUBLIC = 8 */
116  attr_date, /* WINHTTP_QUERY_DATE = 9 */
117  attr_expires, /* WINHTTP_QUERY_EXPIRES = 10 */
118  attr_last_modified, /* WINHTTP_QUERY_LAST_MODIFIEDcw = 11 */
119  NULL, /* WINHTTP_QUERY_MESSAGE_ID = 12 */
120  attr_uri, /* WINHTTP_QUERY_URI = 13 */
121  attr_from, /* WINHTTP_QUERY_DERIVED_FROM = 14 */
122  NULL, /* WINHTTP_QUERY_COST = 15 */
123  NULL, /* WINHTTP_QUERY_LINK = 16 */
124  attr_pragma, /* WINHTTP_QUERY_PRAGMA = 17 */
125  NULL, /* WINHTTP_QUERY_VERSION = 18 */
126  attr_status, /* WINHTTP_QUERY_STATUS_CODE = 19 */
127  NULL, /* WINHTTP_QUERY_STATUS_TEXT = 20 */
128  NULL, /* WINHTTP_QUERY_RAW_HEADERS = 21 */
129  NULL, /* WINHTTP_QUERY_RAW_HEADERS_CRLF = 22 */
130  attr_connection, /* WINHTTP_QUERY_CONNECTION = 23 */
131  attr_accept, /* WINHTTP_QUERY_ACCEPT = 24 */
132  attr_accept_charset, /* WINHTTP_QUERY_ACCEPT_CHARSET = 25 */
133  attr_accept_encoding, /* WINHTTP_QUERY_ACCEPT_ENCODING = 26 */
134  attr_accept_language, /* WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 */
135  attr_authorization, /* WINHTTP_QUERY_AUTHORIZATION = 28 */
136  attr_content_encoding, /* WINHTTP_QUERY_CONTENT_ENCODING = 29 */
137  NULL, /* WINHTTP_QUERY_FORWARDED = 30 */
138  NULL, /* WINHTTP_QUERY_FROM = 31 */
139  attr_if_modified_since, /* WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 */
140  attr_location, /* WINHTTP_QUERY_LOCATION = 33 */
141  NULL, /* WINHTTP_QUERY_ORIG_URI = 34 */
142  attr_referer, /* WINHTTP_QUERY_REFERER = 35 */
143  attr_retry_after, /* WINHTTP_QUERY_RETRY_AFTER = 36 */
144  attr_server, /* WINHTTP_QUERY_SERVER = 37 */
145  NULL, /* WINHTTP_TITLE = 38 */
146  attr_user_agent, /* WINHTTP_QUERY_USER_AGENT = 39 */
147  attr_www_authenticate, /* WINHTTP_QUERY_WWW_AUTHENTICATE = 40 */
148  attr_proxy_authenticate, /* WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 */
149  attr_accept_ranges, /* WINHTTP_QUERY_ACCEPT_RANGES = 42 */
150  attr_set_cookie, /* WINHTTP_QUERY_SET_COOKIE = 43 */
151  attr_cookie, /* WINHTTP_QUERY_COOKIE = 44 */
152  NULL, /* WINHTTP_QUERY_REQUEST_METHOD = 45 */
153  NULL, /* WINHTTP_QUERY_REFRESH = 46 */
154  NULL, /* WINHTTP_QUERY_CONTENT_DISPOSITION = 47 */
155  attr_age, /* WINHTTP_QUERY_AGE = 48 */
156  attr_cache_control, /* WINHTTP_QUERY_CACHE_CONTROL = 49 */
157  attr_content_base, /* WINHTTP_QUERY_CONTENT_BASE = 50 */
158  attr_content_location, /* WINHTTP_QUERY_CONTENT_LOCATION = 51 */
159  attr_content_md5, /* WINHTTP_QUERY_CONTENT_MD5 = 52 */
160  attr_content_range, /* WINHTTP_QUERY_CONTENT_RANGE = 53 */
161  attr_etag, /* WINHTTP_QUERY_ETAG = 54 */
162  attr_host, /* WINHTTP_QUERY_HOST = 55 */
163  attr_if_match, /* WINHTTP_QUERY_IF_MATCH = 56 */
164  attr_if_none_match, /* WINHTTP_QUERY_IF_NONE_MATCH = 57 */
165  attr_if_range, /* WINHTTP_QUERY_IF_RANGE = 58 */
166  attr_if_unmodified_since, /* WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
167  attr_max_forwards, /* WINHTTP_QUERY_MAX_FORWARDS = 60 */
168  attr_proxy_authorization, /* WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 */
169  attr_range, /* WINHTTP_QUERY_RANGE = 62 */
170  attr_transfer_encoding, /* WINHTTP_QUERY_TRANSFER_ENCODING = 63 */
171  attr_upgrade, /* WINHTTP_QUERY_UPGRADE = 64 */
172  attr_vary, /* WINHTTP_QUERY_VARY = 65 */
173  attr_via, /* WINHTTP_QUERY_VIA = 66 */
174  attr_warning, /* WINHTTP_QUERY_WARNING = 67 */
175  attr_expect, /* WINHTTP_QUERY_EXPECT = 68 */
176  attr_proxy_connection, /* WINHTTP_QUERY_PROXY_CONNECTION = 69 */
177  attr_unless_modified_since, /* WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
178  NULL, /* WINHTTP_QUERY_PROXY_SUPPORT = 75 */
179  NULL, /* WINHTTP_QUERY_AUTHENTICATION_INFO = 76 */
180  NULL, /* WINHTTP_QUERY_PASSPORT_URLS = 77 */
181  NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */
182 };
183 
184 static struct task_header *dequeue_task( struct request *request )
185 {
186  struct task_header *task;
187 
189  TRACE("%u tasks queued\n", list_count( &request->task_queue ));
190  task = LIST_ENTRY( list_head( &request->task_queue ), struct task_header, entry );
191  if (task) list_remove( &task->entry );
193 
194  TRACE("returning task %p\n", task);
195  return task;
196 }
197 
198 #ifdef __REACTOS__
200 #else
202 #endif
203 {
204 #ifdef __REACTOS__
205  struct request *request = param;
206 #else
207  struct request *request = ctx;
208 #endif
209  HANDLE handles[2];
210 
211  handles[0] = request->task_wait;
213  for (;;)
214  {
216  switch (err)
217  {
218  case WAIT_OBJECT_0:
219  {
220  struct task_header *task;
221  while ((task = dequeue_task( request )))
222  {
223  task->proc( task );
224  release_object( &task->request->hdr );
225  heap_free( task );
226  }
227  break;
228  }
229  case WAIT_OBJECT_0 + 1:
230  TRACE("exiting\n");
233  request->task_cs.DebugInfo->Spare[0] = 0;
235  request->hdr.vtbl->destroy( &request->hdr );
236 #ifdef __REACTOS__
237  return 0;
238 #else
239  return;
240 #endif
241 
242  default:
243  ERR("wait failed %u (%u)\n", err, GetLastError());
244  break;
245  }
246  }
247 #ifdef __REACTOS__
248  return 0;
249 #endif
250 }
251 
252 static BOOL queue_task( struct task_header *task )
253 {
254  struct request *request = task->request;
255 
256 #ifdef __REACTOS__
257  if (!request->task_thread)
258 #else
259  if (!request->task_wait)
260 #endif
261  {
262  if (!(request->task_wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
264  {
267  return FALSE;
268  }
269 #ifdef __REACTOS__
270  if (!(request->task_thread = CreateThread( NULL, 0, task_proc, request, 0, NULL )))
271 #else
272  if (!TrySubmitThreadpoolCallback( task_proc, request, NULL ))
273 #endif
274  {
279  return FALSE;
280  }
281 #ifndef __REACTOS__
283 #endif
285  request->task_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": request.task_cs");
286  }
287 
289  TRACE("queueing task %p\n", task );
290  list_add_tail( &request->task_queue, &task->entry );
292 
294  return TRUE;
295 }
296 
297 static void free_header( struct header *header )
298 {
299  heap_free( header->field );
300  heap_free( header->value );
301  heap_free( header );
302 }
303 
305 {
306  if (c < 32 || c == 127) return FALSE;
307  switch (c)
308  {
309  case '(': case ')':
310  case '<': case '>':
311  case '@': case ',':
312  case ';': case ':':
313  case '\\': case '\"':
314  case '/': case '[':
315  case ']': case '?':
316  case '=': case '{':
317  case '}': case ' ':
318  case '\t':
319  return FALSE;
320  default:
321  return TRUE;
322  }
323 }
324 
325 static struct header *parse_header( const WCHAR *string )
326 {
327  const WCHAR *p, *q;
328  struct header *header;
329  int len;
330 
331  p = string;
332  if (!(q = strchrW( p, ':' )))
333  {
334  WARN("no ':' in line %s\n", debugstr_w(string));
335  return NULL;
336  }
337  if (q == string)
338  {
339  WARN("empty field name in line %s\n", debugstr_w(string));
340  return NULL;
341  }
342  while (*p != ':')
343  {
344  if (!valid_token_char( *p ))
345  {
346  WARN("invalid character in field name %s\n", debugstr_w(string));
347  return NULL;
348  }
349  p++;
350  }
351  len = q - string;
352  if (!(header = heap_alloc_zero( sizeof(struct header) ))) return NULL;
353  if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) )))
354  {
355  heap_free( header );
356  return NULL;
357  }
358  memcpy( header->field, string, len * sizeof(WCHAR) );
359  header->field[len] = 0;
360 
361  q++; /* skip past colon */
362  while (*q == ' ') q++;
363  len = strlenW( q );
364 
365  if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
366  {
367  free_header( header );
368  return NULL;
369  }
370  memcpy( header->value, q, len * sizeof(WCHAR) );
371  header->value[len] = 0;
372 
373  return header;
374 }
375 
376 static int get_header_index( struct request *request, const WCHAR *field, int requested_index, BOOL request_only )
377 {
378  int index;
379 
380  TRACE("%s\n", debugstr_w(field));
381 
382  for (index = 0; index < request->num_headers; index++)
383  {
384  if (strcmpiW( request->headers[index].field, field )) continue;
385  if (request_only && !request->headers[index].is_request) continue;
386  if (!request_only && request->headers[index].is_request) continue;
387 
388  if (!requested_index) break;
389  requested_index--;
390  }
391  if (index >= request->num_headers) index = -1;
392  TRACE("returning %d\n", index);
393  return index;
394 }
395 
396 static BOOL insert_header( struct request *request, struct header *header )
397 {
399  struct header *hdrs;
400 
401  if (request->headers)
402  hdrs = heap_realloc_zero( request->headers, sizeof(struct header) * count );
403  else
404  hdrs = heap_alloc_zero( sizeof(struct header) );
405  if (!hdrs) return FALSE;
406 
407  request->headers = hdrs;
408  request->headers[count - 1].field = strdupW( header->field );
409  request->headers[count - 1].value = strdupW( header->value );
410  request->headers[count - 1].is_request = header->is_request;
412  return TRUE;
413 }
414 
416 {
417  if (!request->num_headers) return FALSE;
418  if (index >= request->num_headers) return FALSE;
419  request->num_headers--;
420 
421  heap_free( request->headers[index].field );
422  heap_free( request->headers[index].value );
423 
425  (request->num_headers - index) * sizeof(struct header) );
426  memset( &request->headers[request->num_headers], 0, sizeof(struct header) );
427  return TRUE;
428 }
429 
430 BOOL process_header( struct request *request, const WCHAR *field, const WCHAR *value, DWORD flags, BOOL request_only )
431 {
432  int index;
433  struct header hdr;
434 
435  TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags);
436 
437  if ((index = get_header_index( request, field, 0, request_only )) >= 0)
438  {
440  }
441 
443  {
444  if (index >= 0)
445  {
447  if (!value || !value[0]) return TRUE;
448  }
449  else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD))
450  {
452  return FALSE;
453  }
454 
455  hdr.field = (LPWSTR)field;
456  hdr.value = (LPWSTR)value;
457  hdr.is_request = request_only;
458  return insert_header( request, &hdr );
459  }
460  else if (value)
461  {
462 
464  index >= 0)
465  {
466  WCHAR *tmp;
467  int len, len_orig, len_value;
468  struct header *header = &request->headers[index];
469 
470  len_orig = strlenW( header->value );
471  len_value = strlenW( value );
472 
473  len = len_orig + len_value + 2;
474  if (!(tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return FALSE;
475  header->value = tmp;
476  header->value[len_orig++] = (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) ? ',' : ';';
477  header->value[len_orig++] = ' ';
478 
479  memcpy( &header->value[len_orig], value, len_value * sizeof(WCHAR) );
480  header->value[len] = 0;
481  return TRUE;
482  }
483  else
484  {
485  hdr.field = (LPWSTR)field;
486  hdr.value = (LPWSTR)value;
487  hdr.is_request = request_only;
488  return insert_header( request, &hdr );
489  }
490  }
491 
492  return TRUE;
493 }
494 
496 {
497  BOOL ret = FALSE;
498  WCHAR *buffer, *p, *q;
499  struct header *header;
500 
501  if (len == ~0u) len = strlenW( headers );
502  if (!len) return TRUE;
503  if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
504  memcpy( buffer, headers, len * sizeof(WCHAR) );
505  buffer[len] = 0;
506 
507  p = buffer;
508  do
509  {
510  q = p;
511  while (*q)
512  {
513  if (q[0] == '\n' && q[1] == '\r')
514  {
515  q[0] = '\r';
516  q[1] = '\n';
517  }
518  if (q[0] == '\r' && q[1] == '\n') break;
519  q++;
520  }
521  if (!*p) break;
522  if (*q == '\r')
523  {
524  *q = 0;
525  q += 2; /* jump over \r\n */
526  }
527  if ((header = parse_header( p )))
528  {
530  free_header( header );
531  }
532  p = q;
533  } while (ret);
534 
535  heap_free( buffer );
536  return ret;
537 }
538 
539 /***********************************************************************
540  * WinHttpAddRequestHeaders (winhttp.@)
541  */
543 {
544  BOOL ret;
545  struct request *request;
546 
547  TRACE("%p, %s, %u, 0x%08x\n", hrequest, debugstr_wn(headers, len), len, flags);
548 
549  if (!headers || !len)
550  {
552  return FALSE;
553  }
554  if (!(request = (struct request *)grab_object( hrequest )))
555  {
557  return FALSE;
558  }
560  {
563  return FALSE;
564  }
565 
567 
570  return ret;
571 }
572 
574 {
575  static const WCHAR http[] = {'h','t','t','p',0};
576  static const WCHAR https[] = {'h','t','t','p','s',0};
577  static const WCHAR fmt[] = {'%','s',':','/','/','%','s',0};
578  const WCHAR *scheme;
579  WCHAR *ret;
580  int len;
581 
582  scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? https : http;
583 
584  len = strlenW( scheme ) + strlenW( request->connect->hostname ) + 4; /* '://' + nul */
585  if (request->connect->hostport) len += 6; /* ':' between host and port, up to 5 for port */
586 
587  len += strlenW( request->path );
588  if ((ret = heap_alloc( len * sizeof(WCHAR) )))
589  {
590  len = sprintfW( ret, fmt, scheme, request->connect->hostname );
591  if (request->connect->hostport)
592  {
593  static const WCHAR port_fmt[] = {':','%','u',0};
594  len += sprintfW( ret + len, port_fmt, request->connect->hostport );
595  }
596  strcpyW( ret + len, request->path );
597  if (path) *path = ret + len;
598  }
599 
600  return ret;
601 }
602 
604 {
605  static const WCHAR spaceW[] = {' ',0}, crlfW[] = {'\r','\n',0}, colonW[] = {':',' ',0};
606  static const WCHAR twocrlfW[] = {'\r','\n','\r','\n',0};
607  WCHAR *path, *ret;
608  unsigned int i, len;
609 
610  if (!strcmpiW( request->connect->hostname, request->connect->servername )) path = request->path;
611  else if (!(path = build_absolute_request_path( request, NULL ))) return NULL;
612 
613  len = strlenW( request->verb ) + 1 /* ' ' */;
614  len += strlenW( path ) + 1 /* ' ' */;
615  len += strlenW( request->version );
616 
617  for (i = 0; i < request->num_headers; i++)
618  {
619  if (request->headers[i].is_request)
620  len += strlenW( request->headers[i].field ) + strlenW( request->headers[i].value ) + 4; /* '\r\n: ' */
621  }
622  len += 4; /* '\r\n\r\n' */
623 
624  if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) )))
625  {
626  strcpyW( ret, request->verb );
627  strcatW( ret, spaceW );
628  strcatW( ret, path );
629  strcatW( ret, spaceW );
630  strcatW( ret, request->version );
631 
632  for (i = 0; i < request->num_headers; i++)
633  {
634  if (request->headers[i].is_request)
635  {
636  strcatW( ret, crlfW );
637  strcatW( ret, request->headers[i].field );
638  strcatW( ret, colonW );
639  strcatW( ret, request->headers[i].value );
640  }
641  }
642  strcatW( ret, twocrlfW );
643  }
644 
645  if (path != request->path) heap_free( path );
646  return ret;
647 }
648 
649 #define QUERY_MODIFIER_MASK (WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_FLAG_SYSTEMTIME | WINHTTP_QUERY_FLAG_NUMBER)
650 
651 static BOOL query_headers( struct request *request, DWORD level, const WCHAR *name, void *buffer, DWORD *buflen,
652  DWORD *index )
653 {
654  struct header *header = NULL;
655  BOOL request_only, ret = FALSE;
656  int requested_index, header_index = -1;
657  DWORD attr, len;
658 
659  request_only = level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS;
660  requested_index = index ? *index : 0;
661 
663  switch (attr)
664  {
666  {
667  header_index = get_header_index( request, name, requested_index, request_only );
668  break;
669  }
671  {
672  WCHAR *headers, *p, *q;
673 
674  if (request_only)
676  else
678 
679  if (!(p = headers)) return FALSE;
680  for (len = 0; *p; p++) if (*p != '\r') len++;
681 
682  if (!buffer || len * sizeof(WCHAR) > *buflen)
684  else
685  {
686  for (p = headers, q = buffer; *p; p++, q++)
687  {
688  if (*p != '\r') *q = *p;
689  else
690  {
691  *q = 0;
692  p++; /* skip '\n' */
693  }
694  }
695  TRACE("returning data: %s\n", debugstr_wn(buffer, len));
696  if (len) len--;
697  ret = TRUE;
698  }
699  *buflen = len * sizeof(WCHAR);
700  if (request_only) heap_free( headers );
701  return ret;
702  }
704  {
705  WCHAR *headers;
706 
707  if (request_only)
709  else
711 
712  if (!headers) return FALSE;
713  len = strlenW( headers ) * sizeof(WCHAR);
714  if (!buffer || len + sizeof(WCHAR) > *buflen)
715  {
716  len += sizeof(WCHAR);
718  }
719  else
720  {
721  memcpy( buffer, headers, len + sizeof(WCHAR) );
722  TRACE("returning data: %s\n", debugstr_wn(buffer, len / sizeof(WCHAR)));
723  ret = TRUE;
724  }
725  *buflen = len;
726  if (request_only) heap_free( headers );
727  return ret;
728  }
730  len = strlenW( request->version ) * sizeof(WCHAR);
731  if (!buffer || len + sizeof(WCHAR) > *buflen)
732  {
733  len += sizeof(WCHAR);
735  }
736  else
737  {
739  TRACE("returning string: %s\n", debugstr_w(buffer));
740  ret = TRUE;
741  }
742  *buflen = len;
743  return ret;
744 
746  len = strlenW( request->status_text ) * sizeof(WCHAR);
747  if (!buffer || len + sizeof(WCHAR) > *buflen)
748  {
749  len += sizeof(WCHAR);
751  }
752  else
753  {
755  TRACE("returning string: %s\n", debugstr_w(buffer));
756  ret = TRUE;
757  }
758  *buflen = len;
759  return ret;
760 
762  len = strlenW( request->verb ) * sizeof(WCHAR);
763  if (!buffer || len + sizeof(WCHAR) > *buflen)
764  {
765  len += sizeof(WCHAR);
767  }
768  else
769  {
770  strcpyW( buffer, request->verb );
771  TRACE("returning string: %s\n", debugstr_w(buffer));
772  ret = TRUE;
773  }
774  *buflen = len;
775  return ret;
776 
777  default:
779  {
781  return FALSE;
782  }
783  if (!attribute_table[attr])
784  {
785  FIXME("attribute %u not implemented\n", attr);
787  return FALSE;
788  }
789  TRACE("attribute %s\n", debugstr_w(attribute_table[attr]));
790  header_index = get_header_index( request, attribute_table[attr], requested_index, request_only );
791  break;
792  }
793 
794  if (header_index >= 0)
795  {
796  header = &request->headers[header_index];
797  }
798  if (!header || (request_only && !header->is_request))
799  {
801  return FALSE;
802  }
804  {
805  if (!buffer || sizeof(int) > *buflen)
806  {
808  }
809  else
810  {
811  int *number = buffer;
812  *number = atoiW( header->value );
813  TRACE("returning number: %d\n", *number);
814  ret = TRUE;
815  }
816  *buflen = sizeof(int);
817  }
819  {
820  SYSTEMTIME *st = buffer;
821  if (!buffer || sizeof(SYSTEMTIME) > *buflen)
822  {
824  }
825  else if ((ret = WinHttpTimeToSystemTime( header->value, st )))
826  {
827  TRACE("returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
828  st->wYear, st->wMonth, st->wDay, st->wDayOfWeek,
829  st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
830  }
831  *buflen = sizeof(SYSTEMTIME);
832  }
833  else if (header->value)
834  {
835  len = strlenW( header->value ) * sizeof(WCHAR);
836  if (!buffer || len + sizeof(WCHAR) > *buflen)
837  {
838  len += sizeof(WCHAR);
840  }
841  else
842  {
843  strcpyW( buffer, header->value );
844  TRACE("returning string: %s\n", debugstr_w(buffer));
845  ret = TRUE;
846  }
847  *buflen = len;
848  }
849  if (ret && index) *index += 1;
850  return ret;
851 }
852 
853 /***********************************************************************
854  * WinHttpQueryHeaders (winhttp.@)
855  */
857 {
858  BOOL ret;
859  struct request *request;
860 
861  TRACE("%p, 0x%08x, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index);
862 
863  if (!(request = (struct request *)grab_object( hrequest )))
864  {
866  return FALSE;
867  }
869  {
872  return FALSE;
873  }
874 
875  ret = query_headers( request, level, name, buffer, buflen, index );
876 
879  return ret;
880 }
881 
882 static const WCHAR basicW[] = {'B','a','s','i','c',0};
883 static const WCHAR ntlmW[] = {'N','T','L','M',0};
884 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0};
885 static const WCHAR digestW[] = {'D','i','g','e','s','t',0};
886 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
887 
888 static const struct
889 {
890  const WCHAR *str;
891  unsigned int len;
893 }
894 auth_schemes[] =
895 {
901 };
902 
904 {
905  int i;
906 
907  for (i = 0; i < ARRAY_SIZE( auth_schemes ); i++) if (flag == auth_schemes[i].scheme) return i;
908  return SCHEME_INVALID;
909 }
910 
912 {
913  unsigned int i;
914 
915  for (i = 0; i < ARRAY_SIZE( auth_schemes ); i++)
916  {
918  (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
919  }
920  return 0;
921 }
922 
924 {
925  DWORD index = 0, supported_schemes = 0, first_scheme = 0;
926  BOOL ret = FALSE;
927 
928  for (;;)
929  {
930  WCHAR *buffer;
931  DWORD size, scheme;
932 
933  size = 0;
935  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
936 
937  if (!(buffer = heap_alloc( size ))) return FALSE;
939  {
940  heap_free( buffer );
941  return FALSE;
942  }
944  heap_free( buffer );
945  if (!scheme) continue;
946 
947  if (!first_scheme) first_scheme = scheme;
948  supported_schemes |= scheme;
949 
950  ret = TRUE;
951  }
952 
953  if (ret)
954  {
955  *supported = supported_schemes;
956  *first = first_scheme;
957  }
958  return ret;
959 }
960 
961 /***********************************************************************
962  * WinHttpQueryAuthSchemes (winhttp.@)
963  */
965 {
966  BOOL ret = FALSE;
967  struct request *request;
968 
969  TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target);
970 
971  if (!(request = (struct request *)grab_object( hrequest )))
972  {
974  return FALSE;
975  }
977  {
980  return FALSE;
981  }
982  if (!supported || !first || !target)
983  {
986  return FALSE;
987 
988  }
989 
991  {
993  ret = TRUE;
994  }
996  {
998  ret = TRUE;
999  }
1001 
1002  release_object( &request->hdr );
1003  if (ret) SetLastError( ERROR_SUCCESS );
1004  return ret;
1005 }
1006 
1007 static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 )
1008 {
1009  UINT n = 0, x;
1010  static const char base64enc[] =
1011  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1012 
1013  while (len > 0)
1014  {
1015  /* first 6 bits, all from bin[0] */
1016  base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
1017  x = (bin[0] & 3) << 4;
1018 
1019  /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1020  if (len == 1)
1021  {
1022  base64[n++] = base64enc[x];
1023  base64[n++] = '=';
1024  base64[n++] = '=';
1025  break;
1026  }
1027  base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
1028  x = (bin[1] & 0x0f) << 2;
1029 
1030  /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1031  if (len == 2)
1032  {
1033  base64[n++] = base64enc[x];
1034  base64[n++] = '=';
1035  break;
1036  }
1037  base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
1038 
1039  /* last 6 bits, all from bin [2] */
1040  base64[n++] = base64enc[bin[2] & 0x3f];
1041  bin += 3;
1042  len -= 3;
1043  }
1044  base64[n] = 0;
1045  return n;
1046 }
1047 
1048 static inline char decode_char( WCHAR c )
1049 {
1050  if (c >= 'A' && c <= 'Z') return c - 'A';
1051  if (c >= 'a' && c <= 'z') return c - 'a' + 26;
1052  if (c >= '0' && c <= '9') return c - '0' + 52;
1053  if (c == '+') return 62;
1054  if (c == '/') return 63;
1055  return 64;
1056 }
1057 
1058 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
1059 {
1060  unsigned int i = 0;
1061  char c0, c1, c2, c3;
1062  const WCHAR *p = base64;
1063 
1064  while (len > 4)
1065  {
1066  if ((c0 = decode_char( p[0] )) > 63) return 0;
1067  if ((c1 = decode_char( p[1] )) > 63) return 0;
1068  if ((c2 = decode_char( p[2] )) > 63) return 0;
1069  if ((c3 = decode_char( p[3] )) > 63) return 0;
1070 
1071  if (buf)
1072  {
1073  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1074  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1075  buf[i + 2] = (c2 << 6) | c3;
1076  }
1077  len -= 4;
1078  i += 3;
1079  p += 4;
1080  }
1081  if (p[2] == '=')
1082  {
1083  if ((c0 = decode_char( p[0] )) > 63) return 0;
1084  if ((c1 = decode_char( p[1] )) > 63) return 0;
1085 
1086  if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
1087  i++;
1088  }
1089  else if (p[3] == '=')
1090  {
1091  if ((c0 = decode_char( p[0] )) > 63) return 0;
1092  if ((c1 = decode_char( p[1] )) > 63) return 0;
1093  if ((c2 = decode_char( p[2] )) > 63) return 0;
1094 
1095  if (buf)
1096  {
1097  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1098  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1099  }
1100  i += 2;
1101  }
1102  else
1103  {
1104  if ((c0 = decode_char( p[0] )) > 63) return 0;
1105  if ((c1 = decode_char( p[1] )) > 63) return 0;
1106  if ((c2 = decode_char( p[2] )) > 63) return 0;
1107  if ((c3 = decode_char( p[3] )) > 63) return 0;
1108 
1109  if (buf)
1110  {
1111  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1112  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1113  buf[i + 2] = (c2 << 6) | c3;
1114  }
1115  i += 3;
1116  }
1117  return i;
1118 }
1119 
1120 static struct authinfo *alloc_authinfo(void)
1121 {
1122  struct authinfo *ret;
1123 
1124  if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
1125 
1126  SecInvalidateHandle( &ret->cred );
1127  SecInvalidateHandle( &ret->ctx );
1128  memset( &ret->exp, 0, sizeof(ret->exp) );
1129  ret->scheme = 0;
1130  ret->attr = 0;
1131  ret->max_token = 0;
1132  ret->data = NULL;
1133  ret->data_len = 0;
1134  ret->finished = FALSE;
1135  return ret;
1136 }
1137 
1139 {
1140  if (!authinfo) return;
1141 
1142  if (SecIsValidHandle( &authinfo->ctx ))
1144  if (SecIsValidHandle( &authinfo->cred ))
1146 
1147  heap_free( authinfo->data );
1148  heap_free( authinfo );
1149 }
1150 
1152 {
1153  DWORD size, index = 0;
1154  for (;;)
1155  {
1156  size = len;
1157  if (!query_headers( request, level, NULL, buffer, &size, &index )) return FALSE;
1158  if (auth_scheme_from_header( buffer ) == scheme) break;
1159  }
1160  return TRUE;
1161 }
1162 
1163 static BOOL do_authorization( struct request *request, DWORD target, DWORD scheme_flag )
1164 {
1165  struct authinfo *authinfo, **auth_ptr;
1166  enum auth_scheme scheme = scheme_from_flag( scheme_flag );
1167  const WCHAR *auth_target, *username, *password;
1168  WCHAR auth_value[2048], *auth_reply;
1169  DWORD len = sizeof(auth_value), len_scheme, flags;
1170  BOOL ret, has_auth_value;
1171 
1172  if (scheme == SCHEME_INVALID) return FALSE;
1173 
1174  switch (target)
1175  {
1177  has_auth_value = get_authvalue( request, WINHTTP_QUERY_WWW_AUTHENTICATE, scheme_flag, auth_value, len );
1178  auth_ptr = &request->authinfo;
1180  if (request->creds[TARGET_SERVER][scheme].username)
1181  {
1182  if (scheme != SCHEME_BASIC && !has_auth_value) return FALSE;
1183  username = request->creds[TARGET_SERVER][scheme].username;
1184  password = request->creds[TARGET_SERVER][scheme].password;
1185  }
1186  else
1187  {
1188  if (!has_auth_value) return FALSE;
1189  username = request->connect->username;
1190  password = request->connect->password;
1191  }
1192  break;
1193 
1195  if (!get_authvalue( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, scheme_flag, auth_value, len ))
1196  return FALSE;
1197  auth_ptr = &request->proxy_authinfo;
1199  if (request->creds[TARGET_PROXY][scheme].username)
1200  {
1201  username = request->creds[TARGET_PROXY][scheme].username;
1202  password = request->creds[TARGET_PROXY][scheme].password;
1203  }
1204  else
1205  {
1206  username = request->connect->session->proxy_username;
1207  password = request->connect->session->proxy_password;
1208  }
1209  break;
1210 
1211  default:
1212  WARN("unknown target %x\n", target);
1213  return FALSE;
1214  }
1215  authinfo = *auth_ptr;
1216 
1217  switch (scheme)
1218  {
1219  case SCHEME_BASIC:
1220  {
1221  int userlen, passlen;
1222 
1223  if (!username || !password) return FALSE;
1224  if ((!authinfo && !(authinfo = alloc_authinfo())) || authinfo->finished) return FALSE;
1225 
1226  userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL );
1227  passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL );
1228 
1229  authinfo->data_len = userlen + 1 + passlen;
1230  if (!(authinfo->data = heap_alloc( authinfo->data_len ))) return FALSE;
1231 
1232  WideCharToMultiByte( CP_UTF8, 0, username, -1, authinfo->data, userlen, NULL, NULL );
1233  authinfo->data[userlen] = ':';
1234  WideCharToMultiByte( CP_UTF8, 0, password, -1, authinfo->data + userlen + 1, passlen, NULL, NULL );
1235 
1237  authinfo->finished = TRUE;
1238  break;
1239  }
1240  case SCHEME_NTLM:
1241  case SCHEME_NEGOTIATE:
1242  {
1244  SecBufferDesc out_desc, in_desc;
1245  SecBuffer out, in;
1247  const WCHAR *p;
1248  BOOL first = FALSE;
1249 
1250  if (!authinfo)
1251  {
1252  TimeStamp exp;
1254  WCHAR *domain, *user;
1255 
1256  if (!username || !password || !(authinfo = alloc_authinfo())) return FALSE;
1257 
1258  first = TRUE;
1259  domain = (WCHAR *)username;
1260  user = strchrW( username, '\\' );
1261 
1262  if (user) user++;
1263  else
1264  {
1265  user = (WCHAR *)username;
1266  domain = NULL;
1267  }
1269  id.User = user;
1270  id.UserLength = strlenW( user );
1271  id.Domain = domain;
1272  id.DomainLength = domain ? user - domain - 1 : 0;
1273  id.Password = (WCHAR *)password;
1274  id.PasswordLength = strlenW( password );
1275 
1278  &authinfo->cred, &exp );
1279  if (status == SEC_E_OK)
1280  {
1283  if (status == SEC_E_OK)
1284  {
1285  authinfo->max_token = info->cbMaxToken;
1287  }
1288  }
1289  if (status != SEC_E_OK)
1290  {
1291  WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
1293  heap_free( authinfo );
1294  return FALSE;
1295  }
1296  authinfo->scheme = scheme;
1297  }
1298  else if (authinfo->finished) return FALSE;
1299 
1300  if ((strlenW( auth_value ) < auth_schemes[authinfo->scheme].len ||
1301  strncmpiW( auth_value, auth_schemes[authinfo->scheme].str, auth_schemes[authinfo->scheme].len )))
1302  {
1303  ERR("authentication scheme changed from %s to %s\n",
1304  debugstr_w(auth_schemes[authinfo->scheme].str), debugstr_w(auth_value));
1306  *auth_ptr = NULL;
1307  return FALSE;
1308  }
1309  in.BufferType = SECBUFFER_TOKEN;
1310  in.cbBuffer = 0;
1311  in.pvBuffer = NULL;
1312 
1313  in_desc.ulVersion = 0;
1314  in_desc.cBuffers = 1;
1315  in_desc.pBuffers = &in;
1316 
1317  p = auth_value + auth_schemes[scheme].len;
1318  if (*p == ' ')
1319  {
1320  int len = strlenW( ++p );
1321  in.cbBuffer = decode_base64( p, len, NULL );
1322  if (!(in.pvBuffer = heap_alloc( in.cbBuffer ))) {
1324  *auth_ptr = NULL;
1325  return FALSE;
1326  }
1327  decode_base64( p, len, in.pvBuffer );
1328  }
1329  out.BufferType = SECBUFFER_TOKEN;
1330  out.cbBuffer = authinfo->max_token;
1331  if (!(out.pvBuffer = heap_alloc( authinfo->max_token )))
1332  {
1333  heap_free( in.pvBuffer );
1335  *auth_ptr = NULL;
1336  return FALSE;
1337  }
1338  out_desc.ulVersion = 0;
1339  out_desc.cBuffers = 1;
1340  out_desc.pBuffers = &out;
1341 
1343  first ? request->connect->servername : NULL, flags, 0,
1344  SECURITY_NETWORK_DREP, in.pvBuffer ? &in_desc : NULL, 0,
1345  &authinfo->ctx, &out_desc, &authinfo->attr, &authinfo->exp );
1346  heap_free( in.pvBuffer );
1347  if (status == SEC_E_OK)
1348  {
1349  heap_free( authinfo->data );
1350  authinfo->data = out.pvBuffer;
1351  authinfo->data_len = out.cbBuffer;
1352  authinfo->finished = TRUE;
1353  TRACE("sending last auth packet\n");
1354  }
1355  else if (status == SEC_I_CONTINUE_NEEDED)
1356  {
1357  heap_free( authinfo->data );
1358  authinfo->data = out.pvBuffer;
1359  authinfo->data_len = out.cbBuffer;
1360  TRACE("sending next auth packet\n");
1361  }
1362  else
1363  {
1364  ERR("InitializeSecurityContextW failed with error 0x%08x\n", status);
1365  heap_free( out.pvBuffer );
1367  *auth_ptr = NULL;
1368  return FALSE;
1369  }
1370  break;
1371  }
1372  default:
1373  ERR("invalid scheme %u\n", scheme);
1374  return FALSE;
1375  }
1376  *auth_ptr = authinfo;
1377 
1378  len_scheme = auth_schemes[authinfo->scheme].len;
1379  len = len_scheme + 1 + ((authinfo->data_len + 2) * 4) / 3;
1380  if (!(auth_reply = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
1381 
1382  memcpy( auth_reply, auth_schemes[authinfo->scheme].str, len_scheme * sizeof(WCHAR) );
1383  auth_reply[len_scheme] = ' ';
1384  encode_base64( authinfo->data, authinfo->data_len, auth_reply + len_scheme + 1 );
1385 
1387  ret = process_header( request, auth_target, auth_reply, flags, TRUE );
1388  heap_free( auth_reply );
1389  return ret;
1390 }
1391 
1393 {
1394  static const WCHAR fmtW[] = {'%','s',':','%','u',0};
1395  static const WCHAR connectW[] = {'C','O','N','N','E','C','T', 0};
1396  static const WCHAR spaceW[] = {' ',0}, crlfW[] = {'\r','\n',0}, colonW[] = {':',' ',0};
1397  static const WCHAR twocrlfW[] = {'\r','\n','\r','\n',0};
1398  WCHAR *ret, *host;
1399  unsigned int i;
1400  int len;
1401 
1402  if (!(host = heap_alloc( (strlenW( request->connect->hostname ) + 7) * sizeof(WCHAR) ))) return NULL;
1403  len = sprintfW( host, fmtW, request->connect->hostname, request->connect->hostport );
1404 
1405  len += ARRAY_SIZE(connectW);
1406  len += ARRAY_SIZE(http1_1);
1407 
1408  for (i = 0; i < request->num_headers; i++)
1409  {
1410  if (request->headers[i].is_request)
1411  len += strlenW( request->headers[i].field ) + strlenW( request->headers[i].value ) + 4; /* '\r\n: ' */
1412  }
1413  len += 4; /* '\r\n\r\n' */
1414 
1415  if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) )))
1416  {
1417  strcpyW( ret, connectW );
1418  strcatW( ret, spaceW );
1419  strcatW( ret, host );
1420  strcatW( ret, spaceW );
1421  strcatW( ret, http1_1 );
1422 
1423  for (i = 0; i < request->num_headers; i++)
1424  {
1425  if (request->headers[i].is_request)
1426  {
1427  strcatW( ret, crlfW );
1428  strcatW( ret, request->headers[i].field );
1429  strcatW( ret, colonW );
1430  strcatW( ret, request->headers[i].value );
1431  }
1432  }
1433  strcatW( ret, twocrlfW );
1434  }
1435 
1436  heap_free( host );
1437  return ret;
1438 }
1439 
1440 static BOOL read_reply( struct request *request );
1441 
1443 {
1444  WCHAR *str;
1445  char *strA;
1446  int len, bytes_sent;
1447  BOOL ret;
1448 
1449  if (!(str = build_proxy_connect_string( request ))) return FALSE;
1450  strA = strdupWA( str );
1451  heap_free( str );
1452  if (!strA) return FALSE;
1453 
1454  len = strlen( strA );
1455  ret = netconn_send( request->netconn, strA, len, &bytes_sent );
1456  heap_free( strA );
1457  if (ret) ret = read_reply( request );
1458 
1459  return ret;
1460 }
1461 
1463 {
1464  char buf[INET6_ADDRSTRLEN];
1465  void *src;
1466 
1467  switch (addr->ss_family)
1468  {
1469  case AF_INET:
1470  src = &((struct sockaddr_in *)addr)->sin_addr;
1471  break;
1472  case AF_INET6:
1473  src = &((struct sockaddr_in6 *)addr)->sin6_addr;
1474  break;
1475  default:
1476  WARN("unsupported address family %d\n", addr->ss_family);
1477  return NULL;
1478  }
1479  if (!inet_ntop( addr->ss_family, src, buf, sizeof(buf) )) return NULL;
1480  return strdupAW( buf );
1481 }
1482 
1485 {
1486  0, 0, &connection_pool_cs,
1488  0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
1489 };
1490 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
1491 
1493 
1494 void release_host( struct hostdata *host )
1495 {
1496  LONG ref;
1497 
1499  if (!(ref = --host->ref)) list_remove( &host->entry );
1501  if (ref) return;
1502 
1503  assert( list_empty( &host->connections ) );
1504  heap_free( host->hostname );
1505  heap_free( host );
1506 }
1507 
1509 
1510 #ifdef __REACTOS__
1511 static DWORD WINAPI connection_collector(void *arg)
1512 #else
1514 #endif
1515 {
1516  unsigned int remaining_connections;
1517  struct netconn *netconn, *next_netconn;
1518  struct hostdata *host, *next_host;
1519  ULONGLONG now;
1520 
1521  do
1522  {
1523  /* FIXME: Use more sophisticated method */
1524  Sleep(5000);
1525  remaining_connections = 0;
1526  now = GetTickCount64();
1527 
1529 
1531  {
1532  LIST_FOR_EACH_ENTRY_SAFE(netconn, next_netconn, &host->connections, struct netconn, entry)
1533  {
1534  if (netconn->keep_until < now)
1535  {
1536  TRACE("freeing %p\n", netconn);
1539  }
1540  else remaining_connections++;
1541  }
1542  }
1543 
1544  if (!remaining_connections) connection_collector_running = FALSE;
1545 
1547  } while(remaining_connections);
1548 
1549 #ifdef __REACTOS__
1551 #else
1552  FreeLibraryWhenCallbackReturns( instance, winhttp_instance );
1553 #endif
1554 }
1555 
1556 static void cache_connection( struct netconn *netconn )
1557 {
1558  TRACE( "caching connection %p\n", netconn );
1559 
1561 
1563  list_add_head( &netconn->host->connections, &netconn->entry );
1564 
1566  {
1567  HMODULE module;
1568 #ifdef __REACTOS__
1569  HANDLE thread;
1570 #endif
1571 
1572  GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR *)winhttp_instance, &module );
1573 
1574 #ifdef __REACTOS__
1576  if (thread)
1577  {
1578  CloseHandle( thread );
1580  }
1581  else
1582  {
1584  }
1585 #else
1586  if (TrySubmitThreadpoolCallback( connection_collector, NULL, NULL )) connection_collector_running = TRUE;
1587  else FreeLibrary( winhttp_instance );
1588 #endif
1589  }
1590 
1592 }
1593 
1595 {
1596  DWORD ret = 0;
1602  return ret;
1603 }
1604 
1606 {
1608 
1609  if (request->cred_handle_initialized) return TRUE;
1610 
1612  {
1613  SCHANNEL_CRED cred;
1614  memset( &cred, 0, sizeof(cred) );
1616  cred.grbitEnabledProtocols = map_secure_protocols( request->connect->session->secure_protocols );
1617  if (request->client_cert)
1618  {
1619  cred.paCred = &request->client_cert;
1620  cred.cCreds = 1;
1621  }
1623  &cred, NULL, NULL, &request->cred_handle, NULL );
1624  if (status == SEC_E_OK)
1626  }
1627 
1628  if (status != SEC_E_OK)
1629  {
1630  WARN( "AcquireCredentialsHandleW failed: 0x%08x\n", status );
1631  return FALSE;
1632  }
1633  return TRUE;
1634 }
1635 
1637 {
1639  struct hostdata *host = NULL, *iter;
1640  struct netconn *netconn = NULL;
1641  struct connect *connect;
1642  WCHAR *addressW = NULL;
1644  DWORD len;
1645 
1646  if (request->netconn) goto done;
1647 
1648  connect = request->connect;
1649  port = connect->serverport ? connect->serverport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
1650 
1652 
1654  {
1655  if (iter->port == port && !strcmpW( connect->servername, iter->hostname ) && !is_secure == !iter->secure)
1656  {
1657  host = iter;
1658  host->ref++;
1659  break;
1660  }
1661  }
1662 
1663  if (!host)
1664  {
1665  if ((host = heap_alloc( sizeof(*host) )))
1666  {
1667  host->ref = 1;
1668  host->secure = is_secure;
1669  host->port = port;
1670  list_init( &host->connections );
1671  if ((host->hostname = strdupW( connect->servername )))
1672  {
1673  list_add_head( &connection_pool, &host->entry );
1674  }
1675  else
1676  {
1677  heap_free( host );
1678  host = NULL;
1679  }
1680  }
1681  }
1682 
1684 
1685  if (!host) return FALSE;
1686 
1687  for (;;)
1688  {
1690  if (!list_empty( &host->connections ))
1691  {
1692  netconn = LIST_ENTRY( list_head( &host->connections ), struct netconn, entry );
1693  list_remove( &netconn->entry );
1694  }
1696  if (!netconn) break;
1697 
1698  if (netconn_is_alive( netconn )) break;
1699  TRACE("connection %p no longer alive, closing\n", netconn);
1701  netconn = NULL;
1702  }
1703 
1704  if (!connect->resolved && netconn)
1705  {
1707  connect->resolved = TRUE;
1708  }
1709 
1710  if (!connect->resolved)
1711  {
1712  len = strlenW( host->hostname ) + 1;
1714 
1716  {
1717  release_host( host );
1718  return FALSE;
1719  }
1720  connect->resolved = TRUE;
1721 
1722  if (!(addressW = addr_to_str( &connect->sockaddr )))
1723  {
1724  release_host( host );
1725  return FALSE;
1726  }
1727  len = strlenW( addressW ) + 1;
1729  }
1730 
1731  if (!netconn)
1732  {
1733  if (!addressW && !(addressW = addr_to_str( &connect->sockaddr )))
1734  {
1735  release_host( host );
1736  return FALSE;
1737  }
1738 
1739  TRACE("connecting to %s:%u\n", debugstr_w(addressW), port);
1740 
1742 
1744  {
1745  heap_free( addressW );
1746  release_host( host );
1747  return FALSE;
1748  }
1751 
1752  request->netconn = netconn;
1753 
1754  if (is_secure)
1755  {
1756  if (connect->session->proxy_server &&
1758  {
1759  if (!secure_proxy_connect( request ))
1760  {
1761  request->netconn = NULL;
1762  heap_free( addressW );
1764  return FALSE;
1765  }
1766  }
1767 
1770 
1771  if (!ensure_cred_handle( request ) ||
1774  {
1775  request->netconn = NULL;
1776  heap_free( addressW );
1778  return FALSE;
1779  }
1780  }
1781 
1783  }
1784  else
1785  {
1786  TRACE("using connection %p\n", netconn);
1787 
1790  request->netconn = netconn;
1791  }
1792 
1794  {
1795  heap_free( addressW );
1797  return FALSE;
1798  }
1799 
1800 done:
1805  heap_free( addressW );
1806  return TRUE;
1807 }
1808 
1810 {
1811  if (!request->netconn) return;
1812 
1815  request->netconn = NULL;
1817 }
1818 
1819 static BOOL add_host_header( struct request *request, DWORD modifier )
1820 {
1821  BOOL ret;
1822  DWORD len;
1823  WCHAR *host;
1824  static const WCHAR fmt[] = {'%','s',':','%','u',0};
1825  struct connect *connect = request->connect;
1827 
1828  port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
1829 
1831  {
1832  return process_header( request, attr_host, connect->hostname, modifier, TRUE );
1833  }
1834  len = strlenW( connect->hostname ) + 7; /* sizeof(":65335") */
1835  if (!(host = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
1837  ret = process_header( request, attr_host, host, modifier, TRUE );
1838  heap_free( host );
1839  return ret;
1840 }
1841 
1843 {
1844  unsigned int i;
1845 
1846  for (i = 0; i < request->num_headers; i++)
1847  {
1848  if (!request->headers[i].field) continue;
1849  if (!request->headers[i].value) continue;
1850  if (request->headers[i].is_request) continue;
1851  delete_header( request, i );
1852  i--;
1853  }
1854 }
1855 
1856 /* remove some amount of data from the read buffer */
1857 static void remove_data( struct request *request, int count )
1858 {
1859  if (!(request->read_size -= count)) request->read_pos = 0;
1860  else request->read_pos += count;
1861 }
1862 
1863 /* read some more data into the read buffer */
1864 static BOOL read_more_data( struct request *request, int maxlen, BOOL notify )
1865 {
1866  int len;
1867  BOOL ret;
1868 
1869  if (request->read_chunked_eof) return FALSE;
1870 
1871  if (request->read_size && request->read_pos)
1872  {
1873  /* move existing data to the start of the buffer */
1875  request->read_pos = 0;
1876  }
1877  if (maxlen == -1) maxlen = sizeof(request->read_buf);
1878 
1880 
1882  maxlen - request->read_size, 0, &len );
1883 
1885 
1886  request->read_size += len;
1887  return ret;
1888 }
1889 
1890 /* discard data contents until we reach end of line */
1892 {
1893  do
1894  {
1895  char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size );
1896  if (eol)
1897  {
1898  remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) );
1899  break;
1900  }
1901  request->read_pos = request->read_size = 0; /* discard everything */
1902  if (!read_more_data( request, -1, notify )) return FALSE;
1903  } while (request->read_size);
1904  return TRUE;
1905 }
1906 
1907 /* read the size of the next chunk */
1909 {
1910  DWORD chunk_size = 0;
1911 
1913 
1914  if (request->read_chunked_eof) return FALSE;
1915 
1916  /* read terminator for the previous chunk */
1917  if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE;
1918 
1919  for (;;)
1920  {
1921  while (request->read_size)
1922  {
1923  char ch = request->read_buf[request->read_pos];
1924  if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
1925  else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
1926  else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
1927  else if (ch == ';' || ch == '\r' || ch == '\n')
1928  {
1929  TRACE("reading %u byte chunk\n", chunk_size);
1930 
1931  if (request->content_length == ~0u) request->content_length = chunk_size;
1932  else request->content_length += chunk_size;
1933 
1934  request->read_chunked_size = chunk_size;
1935  if (!chunk_size) request->read_chunked_eof = TRUE;
1936 
1937  return discard_eol( request, notify );
1938  }
1939  remove_data( request, 1 );
1940  }
1941  if (!read_more_data( request, -1, notify )) return FALSE;
1942  if (!request->read_size)
1943  {
1946  return TRUE;
1947  }
1948  }
1949 }
1950 
1952 {
1953  int len = sizeof(request->read_buf);
1954 
1955  if (request->read_chunked)
1956  {
1957  if (request->read_chunked_eof) return FALSE;
1959  {
1960  if (!start_next_chunk( request, notify )) return FALSE;
1961  }
1963  }
1964  else if (request->content_length != ~0u)
1965  {
1967  }
1968 
1969  if (len <= request->read_size) return TRUE;
1970  if (!read_more_data( request, len, notify )) return FALSE;
1972  return TRUE;
1973 }
1974 
1975 static void finished_reading( struct request *request )
1976 {
1977  static const WCHAR closeW[] = {'c','l','o','s','e',0};
1978 
1979  BOOL close = FALSE;
1980  WCHAR connection[20];
1981  DWORD size = sizeof(connection);
1982 
1983  if (!request->netconn) return;
1984 
1985  if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE;
1986  else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) ||
1988  {
1989  if (!strcmpiW( connection, closeW )) close = TRUE;
1990  }
1991  else if (!strcmpW( request->version, http1_0 )) close = TRUE;
1992  if (close)
1993  {
1995  return;
1996  }
1997 
1999  request->netconn = NULL;
2000 }
2001 
2002 /* return the size of data available to be read immediately */
2004 {
2006  return request->read_size;
2007 }
2008 
2009 /* check if we have reached the end of the data to read */
2011 {
2012  if (!request->content_length) return TRUE;
2014  if (request->content_length == ~0u) return FALSE;
2016 }
2017 
2018 static BOOL read_data( struct request *request, void *buffer, DWORD size, DWORD *read, BOOL async )
2019 {
2020  int count, bytes_read = 0;
2021  BOOL ret = TRUE;
2022 
2023  if (end_of_read_data( request )) goto done;
2024 
2025  while (size)
2026  {
2027  if (!(count = get_available_data( request )))
2028  {
2029  if (!(ret = refill_buffer( request, async ))) goto done;
2030  if (!(count = get_available_data( request ))) goto done;
2031  }
2032  count = min( count, size );
2033  memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count );
2036  size -= count;
2037  bytes_read += count;
2039  if (end_of_read_data( request )) goto done;
2040  }
2042 
2043 done:
2044  TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length );
2045  if (async)
2046  {
2048  else
2049  {
2051  result.dwResult = API_READ_DATA;
2052  result.dwError = GetLastError();
2054  }
2055  }
2056 
2057  if (ret && read) *read = bytes_read;
2059  return ret;
2060 }
2061 
2062 /* read any content returned by the server so that the connection can be reused */
2063 static void drain_content( struct request *request )
2064 {
2065  DWORD size, bytes_read, bytes_total = 0, bytes_left = request->content_length - request->content_read;
2066  char buffer[2048];
2067 
2069  for (;;)
2070  {
2071  if (request->read_chunked) size = sizeof(buffer);
2072  else
2073  {
2074  if (bytes_total >= bytes_left) return;
2075  size = min( sizeof(buffer), bytes_left - bytes_total );
2076  }
2077  if (!read_data( request, buffer, size, &bytes_read, FALSE ) || !bytes_read) return;
2078  bytes_total += bytes_read;
2079  }
2080 }
2081 
2083 {
2091 };
2092 
2093 #define ESCAPE_MASK_DEFAULT (ESCAPE_FLAG_NON_PRINTABLE | ESCAPE_FLAG_SPACE | ESCAPE_FLAG_UNSAFE |\
2094  ESCAPE_FLAG_DEL | ESCAPE_FLAG_8BIT)
2095 #define ESCAPE_MASK_PERCENT (ESCAPE_FLAG_PERCENT | ESCAPE_MASK_DEFAULT)
2096 #define ESCAPE_MASK_DISABLE (ESCAPE_FLAG_SPACE | ESCAPE_FLAG_8BIT | ESCAPE_FLAG_STRIP_CRLF)
2097 
2098 static inline BOOL need_escape( char ch, enum escape_flags flags )
2099 {
2100  static const char unsafe[] = "\"#<>[\\]^`{|}";
2101  const char *ptr = unsafe;
2102 
2103  if ((flags & ESCAPE_FLAG_SPACE) && ch == ' ') return TRUE;
2104  if ((flags & ESCAPE_FLAG_PERCENT) && ch == '%') return TRUE;
2105  if ((flags & ESCAPE_FLAG_NON_PRINTABLE) && ch < 0x20) return TRUE;
2106  if ((flags & ESCAPE_FLAG_DEL) && ch == 0x7f) return TRUE;
2107  if ((flags & ESCAPE_FLAG_8BIT) && (ch & 0x80)) return TRUE;
2108  if ((flags & ESCAPE_FLAG_UNSAFE)) while (*ptr) { if (ch == *ptr++) return TRUE; }
2109  return FALSE;
2110 }
2111 
2112 static DWORD escape_string( const char *src, DWORD len, char *dst, enum escape_flags flags )
2113 {
2114  static const char hex[] = "0123456789ABCDEF";
2115  DWORD i, ret = len;
2116  char *ptr = dst;
2117 
2118  for (i = 0; i < len; i++)
2119  {
2120  if ((flags & ESCAPE_FLAG_STRIP_CRLF) && (src[i] == '\r' || src[i] == '\n'))
2121  {
2122  ret--;
2123  continue;
2124  }
2125  if (need_escape( src[i], flags ))
2126  {
2127  if (dst)
2128  {
2129  ptr[0] = '%';
2130  ptr[1] = hex[(src[i] >> 4) & 0xf];
2131  ptr[2] = hex[src[i] & 0xf];
2132  ptr += 3;
2133  }
2134  ret += 2;
2135  }
2136  else if (dst) *ptr++ = src[i];
2137  }
2138 
2139  if (dst) dst[ret] = 0;
2140  return ret;
2141 }
2142 
2143 static DWORD str_to_wire( const WCHAR *src, int src_len, char *dst, enum escape_flags flags )
2144 {
2145  DWORD len;
2146  char *utf8;
2147 
2148  if (src_len < 0) src_len = strlenW( src );
2149  len = WideCharToMultiByte( CP_UTF8, 0, src, src_len, NULL, 0, NULL, NULL );
2150  if (!(utf8 = heap_alloc( len ))) return 0;
2151 
2152  WideCharToMultiByte( CP_UTF8, 0, src, -1, utf8, len, NULL, NULL );
2153  len = escape_string( utf8, len, dst, flags );
2154  heap_free( utf8 );
2155 
2156  return len;
2157 }
2158 
2159 static char *build_wire_path( struct request *request, DWORD *ret_len )
2160 {
2161  WCHAR *full_path;
2162  const WCHAR *start, *path, *query = NULL;
2163  DWORD len, len_path = 0, len_query = 0;
2164  enum escape_flags path_flags, query_flags;
2165  char *ret;
2166 
2167  if (!strcmpiW( request->connect->hostname, request->connect->servername )) start = full_path = request->path;
2168  else if (!(full_path = build_absolute_request_path( request, &start ))) return NULL;
2169 
2170  len = strlenW( full_path );
2171  if ((path = strchrW( start, '/' )))
2172  {
2173  len_path = strlenW( path );
2174  if ((query = strchrW( path, '?' )))
2175  {
2176  len_query = strlenW( query );
2177  len_path -= len_query;
2178  }
2179  }
2180 
2181  if (request->hdr.flags & WINHTTP_FLAG_ESCAPE_DISABLE) path_flags = ESCAPE_MASK_DISABLE;
2182  else if (request->hdr.flags & WINHTTP_FLAG_ESCAPE_PERCENT) path_flags = ESCAPE_MASK_PERCENT;
2183  else path_flags = ESCAPE_MASK_DEFAULT;
2184 
2186  else query_flags = path_flags;
2187 
2188  *ret_len = str_to_wire( full_path, len - len_path - len_query, NULL, 0 );
2189  if (path) *ret_len += str_to_wire( path, len_path, NULL, path_flags );
2190  if (query) *ret_len += str_to_wire( query, len_query, NULL, query_flags );
2191 
2192  if ((ret = heap_alloc( *ret_len + 1 )))
2193  {
2194  len = str_to_wire( full_path, len - len_path - len_query, ret, 0 );
2195  if (path) len += str_to_wire( path, len_path, ret + len, path_flags );
2196  if (query) str_to_wire( query, len_query, ret + len, query_flags );
2197  }
2198 
2199  if (full_path != request->path) heap_free( full_path );
2200  return ret;
2201 }
2202 
2203 static char *build_wire_request( struct request *request, DWORD *len )
2204 {
2205  char *path, *ptr, *ret;
2206  DWORD i, len_path;
2207 
2208  if (!(path = build_wire_path( request, &len_path ))) return NULL;
2209 
2210  *len = str_to_wire( request->verb, -1, NULL, 0 ) + 1; /* ' ' */
2211  *len += len_path + 1; /* ' ' */
2212  *len += str_to_wire( request->version, -1, NULL, 0 );
2213 
2214  for (i = 0; i < request->num_headers; i++)
2215  {
2216  if (request->headers[i].is_request)
2217  {
2218  *len += str_to_wire( request->headers[i].field, -1, NULL, 0 ) + 2; /* ': ' */
2219  *len += str_to_wire( request->headers[i].value, -1, NULL, 0 ) + 2; /* '\r\n' */
2220  }
2221  }
2222  *len += 4; /* '\r\n\r\n' */
2223 
2224  if ((ret = ptr = heap_alloc( *len + 1 )))
2225  {
2226  ptr += str_to_wire( request->verb, -1, ptr, 0 );
2227  *ptr++ = ' ';
2228  memcpy( ptr, path, len_path );
2229  ptr += len_path;
2230  *ptr++ = ' ';
2231  ptr += str_to_wire( request->version, -1, ptr, 0 );
2232 
2233  for (i = 0; i < request->num_headers; i++)
2234  {
2235  if (request->headers[i].is_request)
2236  {
2237  *ptr++ = '\r';
2238  *ptr++ = '\n';
2239  ptr += str_to_wire( request->headers[i].field, -1, ptr, 0 );
2240  *ptr++ = ':';
2241  *ptr++ = ' ';
2242  ptr += str_to_wire( request->headers[i].value, -1, ptr, 0 );
2243  }
2244  }
2245  memcpy( ptr, "\r\n\r\n", sizeof("\r\n\r\n") );
2246  }
2247 
2248  heap_free( path );
2249  return ret;
2250 }
2251 
2252 static BOOL send_request( struct request *request, const WCHAR *headers, DWORD headers_len, void *optional,
2253  DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
2254 {
2255  static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0};
2256  static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0};
2257  static const WCHAR length_fmt[] = {'%','l','d',0};
2258 
2259  BOOL ret = FALSE;
2260  struct connect *connect = request->connect;
2261  struct session *session = connect->session;
2262  char *wire_req;
2263  int bytes_sent;
2264  DWORD len;
2265 
2268 
2269  if (session->agent)
2271 
2272  if (connect->hostname)
2274 
2275  if (request->creds[TARGET_SERVER][SCHEME_BASIC].username)
2277 
2278  if (total_len || (request->verb && !strcmpW( request->verb, postW )))
2279  {
2280  WCHAR length[21]; /* decimal long int + null */
2281  sprintfW( length, length_fmt, total_len );
2283  }
2284  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE))
2285  {
2287  }
2288  if (request->hdr.flags & WINHTTP_FLAG_REFRESH)
2289  {
2292  }
2294  {
2295  TRACE("failed to add request headers\n");
2296  return FALSE;
2297  }
2298  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request ))
2299  {
2300  WARN("failed to add cookie headers\n");
2301  return FALSE;
2302  }
2303 
2304  if (context) request->hdr.context = context;
2305 
2306  if (!(ret = open_connection( request ))) goto end;
2307  if (!(wire_req = build_wire_request( request, &len ))) goto end;
2308  TRACE("full request: %s\n", debugstr_a(wire_req));
2309 
2311 
2312  ret = netconn_send( request->netconn, wire_req, len, &bytes_sent );
2313  heap_free( wire_req );
2314  if (!ret) goto end;
2315 
2316  if (optional_len)
2317  {
2318  if (!netconn_send( request->netconn, optional, optional_len, &bytes_sent )) goto end;
2320  request->optional_len = optional_len;
2321  len += optional_len;
2322  }
2324 
2325 end:
2326  if (async)
2327  {
2329  else
2330  {
2332  result.dwResult = API_SEND_REQUEST;
2333  result.dwError = GetLastError();
2335  }
2336  }
2337  return ret;
2338 }
2339 
2340 static void task_send_request( struct task_header *task )
2341 {
2342  struct send_request *s = (struct send_request *)task;
2343  send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE );
2344  heap_free( s->headers );
2345 }
2346 
2347 /***********************************************************************
2348  * WinHttpSendRequest (winhttp.@)
2349  */
2352 {
2353  BOOL ret;
2354  struct request *request;
2355 
2356  TRACE("%p, %s, %u, %p, %u, %u, %lx\n", hrequest, debugstr_wn(headers, headers_len), headers_len, optional,
2357  optional_len, total_len, context);
2358 
2359  if (!(request = (struct request *)grab_object( hrequest )))
2360  {
2362  return FALSE;
2363  }
2365  {
2366  release_object( &request->hdr );
2368  return FALSE;
2369  }
2370 
2371  if (headers && !headers_len) headers_len = strlenW( headers );
2372 
2373  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2374  {
2375  struct send_request *s;
2376 
2377  if (!(s = heap_alloc( sizeof(struct send_request) ))) return FALSE;
2378  s->hdr.request = request;
2379  s->hdr.proc = task_send_request;
2380  s->headers = strdupW( headers );
2381  s->headers_len = headers_len;
2382  s->optional = optional;
2383  s->optional_len = optional_len;
2384  s->total_len = total_len;
2385  s->context = context;
2386 
2387  addref_object( &request->hdr );
2388  ret = queue_task( (struct task_header *)s );
2389  }
2390  else
2392 
2393  release_object( &request->hdr );
2394  if (ret) SetLastError( ERROR_SUCCESS );
2395  return ret;
2396 }
2397 
2398 static BOOL set_credentials( struct request *request, DWORD target, DWORD scheme_flag, const WCHAR *username,
2399  const WCHAR *password )
2400 {
2401  enum auth_scheme scheme = scheme_from_flag( scheme_flag );
2402 
2403  if (scheme == SCHEME_INVALID || ((scheme == SCHEME_BASIC || scheme == SCHEME_DIGEST) && (!username || !password)))
2404  {
2406  return FALSE;
2407  }
2408  switch (target)
2409  {
2411  {
2412  heap_free( request->creds[TARGET_SERVER][scheme].username );
2413  if (!username) request->creds[TARGET_SERVER][scheme].username = NULL;
2414  else if (!(request->creds[TARGET_SERVER][scheme].username = strdupW( username ))) return FALSE;
2415 
2416  heap_free( request->creds[TARGET_SERVER][scheme].password );
2417  if (!password) request->creds[TARGET_SERVER][scheme].password = NULL;
2418  else if (!(request->creds[TARGET_SERVER][scheme].password = strdupW( password ))) return FALSE;
2419  break;
2420  }
2422  {
2423  heap_free( request->creds[TARGET_PROXY][scheme].username );
2424  if (!username) request->creds[TARGET_PROXY][scheme].username = NULL;
2425  else if (!(request->creds[TARGET_PROXY][scheme].username = strdupW( username ))) return FALSE;
2426 
2427  heap_free( request->creds[TARGET_PROXY][scheme].password );
2428  if (!password) request->creds[TARGET_PROXY][scheme].password = NULL;
2429  else if (!(request->creds[TARGET_PROXY][scheme].password = strdupW( password ))) return FALSE;
2430  break;
2431  }
2432  default:
2433  WARN("unknown target %u\n", target);
2434  return FALSE;
2435  }
2436  return TRUE;
2437 }
2438 
2439 /***********************************************************************
2440  * WinHttpSetCredentials (winhttp.@)
2441  */
2444 {
2445  BOOL ret;
2446  struct request *request;
2447 
2448  TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params);
2449 
2450  if (!(request = (struct request *)grab_object( hrequest )))
2451  {
2453  return FALSE;
2454  }
2456  {
2457  release_object( &request->hdr );
2459  return FALSE;
2460  }
2461 
2463 
2464  release_object( &request->hdr );
2465  if (ret) SetLastError( ERROR_SUCCESS );
2466  return ret;
2467 }
2468 
2470 {
2471  DWORD i, schemes, first, level, target;
2472 
2473  switch (status)
2474  {
2475  case HTTP_STATUS_DENIED:
2478  break;
2479 
2483  break;
2484 
2485  default:
2486  WARN("unhandled status %u\n", status);
2487  return FALSE;
2488  }
2489 
2490  if (!query_auth_schemes( request, level, &schemes, &first )) return FALSE;
2491  if (do_authorization( request, target, first )) return TRUE;
2492 
2493  schemes &= ~first;
2494  for (i = 0; i < ARRAY_SIZE( auth_schemes ); i++)
2495  {
2496  if (!(schemes & auth_schemes[i].scheme)) continue;
2498  }
2499  return FALSE;
2500 }
2501 
2502 /* set the request content length based on the headers */
2504 {
2505  WCHAR encoding[20];
2506  DWORD buflen = sizeof(request->content_length);
2507 
2509  request->content_length = 0;
2510  else
2511  {
2513  NULL, &request->content_length, &buflen, NULL ))
2514  request->content_length = ~0u;
2515 
2516  buflen = sizeof(encoding);
2518  !strcmpiW( encoding, chunkedW ))
2519  {
2520  request->content_length = ~0u;
2524  }
2525  }
2526  request->content_read = 0;
2527  return request->content_length;
2528 }
2529 
2530 static BOOL read_line( struct request *request, char *buffer, DWORD *len )
2531 {
2532  int count, bytes_read, pos = 0;
2533 
2534  for (;;)
2535  {
2536  char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size );
2537  if (eol)
2538  {
2539  count = eol - (request->read_buf + request->read_pos);
2540  bytes_read = count + 1;
2541  }
2542  else count = bytes_read = request->read_size;
2543 
2544  count = min( count, *len - pos );
2546  pos += count;
2547  remove_data( request, bytes_read );
2548  if (eol) break;
2549 
2550  if (!read_more_data( request, -1, TRUE )) return FALSE;
2551  if (!request->read_size)
2552  {
2553  *len = 0;
2554  TRACE("returning empty string\n");
2555  return FALSE;
2556  }
2557  }
2558  if (pos < *len)
2559  {
2560  if (pos && buffer[pos - 1] == '\r') pos--;
2561  *len = pos + 1;
2562  }
2563  buffer[*len - 1] = 0;
2564  TRACE("returning %s\n", debugstr_a(buffer));
2565  return TRUE;
2566 }
2567 
2568 #define MAX_REPLY_LEN 1460
2569 #define INITIAL_HEADER_BUFFER_LEN 512
2570 
2571 static BOOL read_reply( struct request *request )
2572 {
2573  static const WCHAR crlf[] = {'\r','\n',0};
2574 
2575  char buffer[MAX_REPLY_LEN];
2576  DWORD buflen, len, offset, crlf_len = 2; /* strlenW(crlf) */
2577  char *status_code, *status_text;
2578  WCHAR *versionW, *status_textW, *raw_headers;
2579  WCHAR status_codeW[4]; /* sizeof("nnn") */
2580 
2581  if (!request->netconn) return FALSE;
2582 
2583  do
2584  {
2585  buflen = MAX_REPLY_LEN;
2586  if (!read_line( request, buffer, &buflen )) return FALSE;
2587 
2588  /* first line should look like 'HTTP/1.x nnn OK' where nnn is the status code */
2589  if (!(status_code = strchr( buffer, ' ' ))) return FALSE;
2590  status_code++;
2591  if (!(status_text = strchr( status_code, ' ' ))) return FALSE;
2592  if ((len = status_text - status_code) != sizeof("nnn") - 1) return FALSE;
2593  status_text++;
2594 
2595  TRACE("version [%s] status code [%s] status text [%s]\n",
2599 
2600  } while (!memcmp( status_code, "100", len )); /* ignore "100 Continue" responses */
2601 
2602  /* we rely on the fact that the protocol is ascii */
2603  MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len );
2604  status_codeW[len] = 0;
2605  if (!(process_header( request, attr_status, status_codeW,
2607  return FALSE;
2608 
2609  len = status_code - buffer;
2610  if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2611  MultiByteToWideChar( CP_ACP, 0, buffer, len - 1, versionW, len -1 );
2612  versionW[len - 1] = 0;
2613 
2616 
2617  len = buflen - (status_text - buffer);
2618  if (!(status_textW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2619  MultiByteToWideChar( CP_ACP, 0, status_text, len, status_textW, len );
2620 
2622  request->status_text = status_textW;
2623 
2624  len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN );
2625  if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2626  MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen );
2627  memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) );
2628 
2631 
2632  offset = buflen + crlf_len - 1;
2633  for (;;)
2634  {
2635  struct header *header;
2636 
2637  buflen = MAX_REPLY_LEN;
2638  if (!read_line( request, buffer, &buflen )) return TRUE;
2639  if (!*buffer) buflen = 1;
2640 
2641  while (len - offset < buflen + crlf_len)
2642  {
2643  WCHAR *tmp;
2644  len *= 2;
2645  if (!(tmp = heap_realloc( raw_headers, len * sizeof(WCHAR) ))) return FALSE;
2646  request->raw_headers = raw_headers = tmp;
2647  }
2648  if (!*buffer)
2649  {
2650  memcpy( raw_headers + offset, crlf, sizeof(crlf) );
2651  break;
2652  }
2653  MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen );
2654 
2655  if (!(header = parse_header( raw_headers + offset ))) break;
2657  {
2658  free_header( header );
2659  break;
2660  }
2661  free_header( header );
2662  memcpy( raw_headers + offset + buflen - 1, crlf, sizeof(crlf) );
2663  offset += buflen + crlf_len - 1;
2664  }
2665 
2666  TRACE("raw headers: %s\n", debugstr_w(raw_headers));
2667  return TRUE;
2668 }
2669 
2670 static void record_cookies( struct request *request )
2671 {
2672  unsigned int i;
2673 
2674  for (i = 0; i < request->num_headers; i++)
2675  {
2676  struct header *set_cookie = &request->headers[i];
2677  if (!strcmpiW( set_cookie->field, attr_set_cookie ) && !set_cookie->is_request)
2678  {
2679  set_cookies( request, set_cookie->value );
2680  }
2681  }
2682 }
2683 
2685 {
2686  DWORD size;
2687  WCHAR *ret;
2688 
2690  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
2691  if (!(ret = heap_alloc( size ))) return NULL;
2692  *len = size / sizeof(WCHAR) - 1;
2694  heap_free( ret );
2695  return NULL;
2696 }
2697 
2699 {
2700  BOOL ret = FALSE;
2701  DWORD len, len_loc;
2702  URL_COMPONENTS uc;
2703  struct connect *connect = request->connect;
2705  WCHAR *hostname = NULL, *location;
2706  int index;
2707 
2708  if (!(location = get_redirect_url( request, &len_loc ))) return FALSE;
2709 
2710  memset( &uc, 0, sizeof(uc) );
2711  uc.dwStructSize = sizeof(uc);
2713 
2714  if (!WinHttpCrackUrl( location, len_loc, 0, &uc )) /* assume relative redirect */
2715  {
2716  WCHAR *path, *p;
2717 
2718  if (location[0] == '/')
2719  {
2720  if (!(path = heap_alloc( (len_loc + 1) * sizeof(WCHAR) ))) goto end;
2721  memcpy( path, location, len_loc * sizeof(WCHAR) );
2722  path[len_loc] = 0;
2723  }
2724  else
2725  {
2726  if ((p = strrchrW( request->path, '/' ))) *p = 0;
2727  len = strlenW( request->path ) + 1 + len_loc;
2728  if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2729  strcpyW( path, request->path );
2730  strcatW( path, slashW );
2731  memcpy( path + strlenW(path), location, len_loc * sizeof(WCHAR) );
2732  path[len_loc] = 0;
2733  }
2734  heap_free( request->path );
2735  request->path = path;
2736 
2738  }
2739  else
2740  {
2742  {
2744  TRACE("redirect from secure page to non-secure page\n");
2745  request->hdr.flags &= ~WINHTTP_FLAG_SECURE;
2746  }
2747  else if (uc.nScheme == INTERNET_SCHEME_HTTPS && !(request->hdr.flags & WINHTTP_FLAG_SECURE))
2748  {
2749  TRACE("redirect from non-secure page to secure page\n");
2750  request->hdr.flags |= WINHTTP_FLAG_SECURE;
2751  }
2752 
2754 
2755  len = uc.dwHostNameLength;
2756  if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2757  memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) );
2758  hostname[len] = 0;
2759 
2760  port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80);
2762  {
2765  connect->hostport = port;
2766  if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end;
2767 
2769  request->netconn = NULL;
2773  }
2774  else heap_free( hostname );
2775 
2777  if (!(ret = open_connection( request ))) goto end;
2778 
2779  heap_free( request->path );
2780  request->path = NULL;
2781  if (uc.dwUrlPathLength)
2782  {
2784  if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2785  memcpy( request->path, uc.lpszUrlPath, (len + 1) * sizeof(WCHAR) );
2786  request->path[len] = 0;
2787  }
2788  else request->path = strdupW( slashW );
2789  }
2790 
2791  /* remove content-type/length headers */
2794 
2796  {
2797  heap_free( request->verb );
2798  request->verb = strdupW( getW );
2799  request->optional = NULL;
2800  request->optional_len = 0;
2801  }
2802  ret = TRUE;
2803 
2804 end:
2805  heap_free( location );
2806  return ret;
2807 }
2808 
2810 {
2811  static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t','1','.','4'};
2812  WCHAR buf[1024];
2813  DWORD len = ARRAY_SIZE(buf);
2814 
2815  if (!(request->connect->session->passport_flags & WINHTTP_ENABLE_PASSPORT_AUTH) ||
2817 
2819  (buf[ARRAY_SIZE(passportW)] == ' ' || !buf[ARRAY_SIZE(passportW)])) return TRUE;
2820 
2821  return FALSE;
2822 }
2823 
2825 {
2826  static const WCHAR status401W[] = {'4','0','1',0};
2828  int i, len = strlenW( request->raw_headers );
2829  WCHAR *p = request->raw_headers;
2830 
2831  if (!process_header( request, attr_status, status401W, flags, FALSE )) return FALSE;
2832 
2833  for (i = 0; i < len; i++)
2834  {
2835  if (i <= len - 3 && p[i] == '3' && p[i + 1] == '0' && p[i + 2] == '2')
2836  {
2837  p[i] = '4';
2838  p[i + 2] = '1';
2839  break;
2840  }
2841  }
2842  return TRUE;
2843 }
2844 
2845 static BOOL receive_response( struct request *request, BOOL async )
2846 {
2847  BOOL ret;
2848  DWORD size, query, status;
2849 
2850  if (!request->netconn)
2851  {
2853  return FALSE;
2854  }
2855 
2857  for (;;)
2858  {
2859  if (!(ret = read_reply( request )))
2860  {
2862  break;
2863  }
2864  size = sizeof(DWORD);
2866  if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break;
2867 
2869 
2870  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request );
2871 
2873  {
2875  }
2877  {
2878  if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS ||
2879  request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break;
2880 
2881  if (!(ret = handle_redirect( request, status ))) break;
2882 
2883  /* recurse synchronously */
2884  if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue;
2885  }
2887  {
2888  if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break;
2889 
2890  if (!handle_authorization( request, status )) break;
2891 
2892  /* recurse synchronously */
2893  if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue;
2894  }
2895  break;
2896  }
2897 
2900 
2901  if (async)
2902  {
2904  else
2905  {
2907  result.dwResult = API_RECEIVE_RESPONSE;
2908  result.dwError = GetLastError();
2910  }
2911  }
2912  return ret;
2913 }
2914 
2915 static void task_receive_response( struct task_header *task )
2916 {
2917  struct receive_response *r = (struct receive_response *)task;
2918  receive_response( r->hdr.request, TRUE );
2919 }
2920 
2921 /***********************************************************************
2922  * WinHttpReceiveResponse (winhttp.@)
2923  */
2925 {
2926  BOOL ret;
2927  struct request *request;
2928 
2929  TRACE("%p, %p\n", hrequest, reserved);
2930 
2931  if (!(request = (struct request *)grab_object( hrequest )))
2932  {
2934  return FALSE;
2935  }
2937  {
2938  release_object( &request->hdr );
2940  return FALSE;
2941  }
2942 
2943  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2944  {
2945  struct receive_response *r;
2946 
2947  if (!(r = heap_alloc( sizeof(struct receive_response) ))) return FALSE;
2948  r->hdr.request = request;
2949  r->hdr.proc = task_receive_response;
2950 
2951  addref_object( &request->hdr );
2952  ret = queue_task( (struct task_header *)r );
2953  }
2954  else
2956 
2957  release_object( &request->hdr );
2958  if (ret) SetLastError( ERROR_SUCCESS );
2959  return ret;
2960 }
2961 
2963 {
2964  DWORD count = 0;
2965  BOOL ret = TRUE;
2966 
2967  if (end_of_read_data( request )) goto done;
2968 
2971  if (!count)
2972  {
2973  if (!(ret = refill_buffer( request, async ))) goto done;
2976  }
2977 
2978 done:
2979  TRACE("%u bytes available\n", count);
2980  if (async)
2981  {
2983  else
2984  {
2986  result.dwResult = API_QUERY_DATA_AVAILABLE;
2987  result.dwError = GetLastError();
2989  }
2990  }
2991 
2992  if (ret && available) *available = count;
2993  return ret;
2994 }
2995 
2996 static void task_query_data_available( struct task_header *task )
2997 {
2998  struct query_data *q = (struct query_data *)task;
2999  query_data_available( q->hdr.request, q->available, TRUE );
3000 }
3001 
3002 /***********************************************************************
3003  * WinHttpQueryDataAvailable (winhttp.@)
3004  */
3006 {
3007  BOOL ret;
3008  struct request *request;
3009 
3010  TRACE("%p, %p\n", hrequest, available);
3011 
3012  if (!(request = (struct request *)grab_object( hrequest )))
3013  {
3015  return FALSE;
3016  }
3018  {
3019  release_object( &request->hdr );
3021  return FALSE;
3022  }
3023 
3024  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
3025  {
3026  struct query_data *q;
3027 
3028  if (!(q = heap_alloc( sizeof(struct query_data) ))) return FALSE;
3029  q->hdr.request = request;
3031  q->available = available;
3032 
3033  addref_object( &request->hdr );
3034  ret = queue_task( (struct task_header *)q );
3035  }
3036  else
3038 
3039  release_object( &request->hdr );
3040  if (ret) SetLastError( ERROR_SUCCESS );
3041  return ret;
3042 }
3043 
3044 static void task_read_data( struct task_header *task )
3045 {
3046  struct read_data *r = (struct read_data *)task;
3047  read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE );
3048 }
3049 
3050 /***********************************************************************
3051  * WinHttpReadData (winhttp.@)
3052  */
3054 {
3055  BOOL ret;
3056  struct request *request;
3057 
3058  TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read);
3059 
3060  if (!(request = (struct request *)grab_object( hrequest )))
3061  {
3063  return FALSE;
3064  }
3066  {
3067  release_object( &request->hdr );
3069  return FALSE;
3070  }
3071 
3072  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
3073  {
3074  struct read_data *r;
3075 
3076  if (!(r = heap_alloc( sizeof(struct read_data) ))) return FALSE;
3077  r->hdr.request = request;
3078  r->hdr.proc = task_read_data;
3079  r->buffer = buffer;
3080  r->to_read = to_read;
3081  r->read = read;
3082 
3083  addref_object( &request->hdr );
3084  ret = queue_task( (struct task_header *)r );
3085  }
3086  else
3088 
3089  release_object( &request->hdr );
3090  if (ret) SetLastError( ERROR_SUCCESS );
3091  return ret;
3092 }
3093 
3094 static BOOL write_data( struct request *request, const void *buffer, DWORD to_write, DWORD *written, BOOL async )
3095 {
3096  BOOL ret;
3097  int num_bytes;
3098 
3099  ret = netconn_send( request->netconn, buffer, to_write, &num_bytes );
3100 
3101  if (async)
3102  {
3104  else
3105  {
3107  result.dwResult = API_WRITE_DATA;
3108  result.dwError = GetLastError();
3110  }
3111  }
3112  if (ret && written) *written = num_bytes;
3113  return ret;
3114 }
3115 
3116 static void task_write_data( struct task_header *task )
3117 {
3118  struct write_data *w = (struct write_data *)task;
3119  write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE );
3120 }
3121 
3122 /***********************************************************************
3123  * WinHttpWriteData (winhttp.@)
3124  */
3126 {
3127  BOOL ret;
3128  struct request *request;
3129 
3130  TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_write, written);
3131 
3132  if (!(request = (struct request *)grab_object( hrequest )))
3133  {
3135  return FALSE;
3136  }
3138  {
3139  release_object( &request->hdr );
3141  return FALSE;
3142  }
3143 
3144  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
3145  {
3146  struct write_data *w;
3147 
3148  if (!(w = heap_alloc( sizeof(struct write_data) ))) return FALSE;
3149  w->hdr.request = request;
3150  w->hdr.proc = task_write_data;
3151  w->buffer = buffer;
3152  w->to_write = to_write;
3153  w->written = written;
3154 
3155  addref_object( &request->hdr );
3156  ret = queue_task( (struct task_header *)w );
3157  }
3158  else
3160 
3161  release_object( &request->hdr );
3162  if (ret) SetLastError( ERROR_SUCCESS );
3163  return ret;
3164 }
3165 
3167 {
3173 };
3174 
3176 {
3177  IWinHttpRequest IWinHttpRequest_iface;
3186 #ifdef __REACTOS__
3187  HANDLE thread;
3188 #else
3190 #endif
3193 #ifndef __REACTOS__
3195 #endif
3196  char *buffer;
3210 };
3211 
3212 static inline struct winhttp_request *impl_from_IWinHttpRequest( IWinHttpRequest *iface )
3213 {
3214  return CONTAINING_RECORD( iface, struct winhttp_request, IWinHttpRequest_iface );
3215 }
3216 
3218  IWinHttpRequest *iface )
3219 {
3221  return InterlockedIncrement( &request->refs );
3222 }
3223 
3224 /* critical section must be held */
3226 {
3227  if (request->state <= REQUEST_STATE_CANCELLED) return;
3228 
3229 #ifdef __REACTOS__
3230  SetEvent( request->cancel );
3231  LeaveCriticalSection( &request->cs );
3232  WaitForSingleObject( request->thread, INFINITE );
3233  EnterCriticalSection( &request->cs );
3234 
3236 
3237  CloseHandle( request->thread );
3238  request->thread = NULL;
3239 #else
3240  if (request->proc_running)
3241  {
3242  SetEvent( request->cancel );
3243  LeaveCriticalSection( &request->cs );
3244 
3246 
3247  EnterCriticalSection( &request->cs );
3248  }
3250 #endif
3251 }
3252 
3253 /* critical section must be held */
3254 static void free_request( struct winhttp_request *request )
3255 {
3256  if (request->state < REQUEST_STATE_INITIALIZED) return;
3257  WinHttpCloseHandle( request->hrequest );
3258  WinHttpCloseHandle( request->hconnect );
3259  WinHttpCloseHandle( request->hsession );
3260 #ifdef __REACTOS__
3261  CloseHandle( request->thread );
3262 #else
3263  CloseHandle( request->done );
3264 #endif
3265  CloseHandle( request->wait );
3266  CloseHandle( request->cancel );
3267  heap_free( (WCHAR *)request->proxy.lpszProxy );
3268  heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
3269  heap_free( request->buffer );
3270  heap_free( request->verb );
3271  VariantClear( &request->data );
3272 }
3273 
3275  IWinHttpRequest *iface )
3276 {
3278  LONG refs = InterlockedDecrement( &request->refs );
3279  if (!refs)
3280  {
3281  TRACE("destroying %p\n", request);
3282 
3283  EnterCriticalSection( &request->cs );
3285  free_request( request );
3286  LeaveCriticalSection( &request->cs );
3287  request->cs.DebugInfo->Spare[0] = 0;
3289  heap_free( request );
3290  }
3291  return refs;
3292 }
3293 
3295  IWinHttpRequest *iface,
3296  REFIID riid,
3297  void **obj )
3298 {
3300 
3301  TRACE("%p, %s, %p\n", request, debugstr_guid(riid), obj );
3302 
3303  if (IsEqualGUID( riid, &IID_IWinHttpRequest ) ||
3306  {
3307  *obj = iface;
3308  }
3309  else
3310  {
3311  FIXME("interface %s not implemented\n", debugstr_guid(riid));
3312  return E_NOINTERFACE;
3313  }
3314  IWinHttpRequest_AddRef( iface );
3315  return S_OK;
3316 }
3317 
3319  IWinHttpRequest *iface,
3320  UINT *count )
3321 {
3323 
3324  TRACE("%p, %p\n", request, count);
3325  *count = 1;
3326  return S_OK;
3327 }
3328 
3330 {
3333 };
3334 
3337 
3339 {
3340  &IID_IWinHttpRequest
3341 };
3342 
3344 {
3345  HRESULT hr;
3346 
3347  if (!winhttp_typelib)
3348  {
3349  ITypeLib *typelib;
3350 
3351  hr = LoadRegTypeLib( &LIBID_WinHttp, 5, 1, LOCALE_SYSTEM_DEFAULT, &typelib );
3352  if (FAILED(hr))
3353  {
3354  ERR("LoadRegTypeLib failed: %08x\n", hr);
3355  return hr;
3356  }
3358  ITypeLib_Release( typelib );
3359  }
3360  if (!winhttp_typeinfo[tid])
3361  {
3363 
3364  hr = ITypeLib_GetTypeInfoOfGuid( winhttp_typelib, winhttp_tid_id[tid], &typeinfo );
3365  if (FAILED(hr))
3366  {
3367  ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(winhttp_tid_id[tid]), hr);
3368  return hr;
3369  }
3371  ITypeInfo_Release( typeinfo );
3372  }
3373  *ret = winhttp_typeinfo[tid];
3374  ITypeInfo_AddRef(winhttp_typeinfo[tid]);
3375  return S_OK;
3376 }
3377 
3379 {
3380  unsigned i;
3381 
3382  for (i = 0; i < ARRAY_SIZE(winhttp_typeinfo); i++)
3383  if (winhttp_typeinfo[i])
3384  ITypeInfo_Release(winhttp_typeinfo[i]);
3385 
3386  if (winhttp_typelib)
3387  ITypeLib_Release(winhttp_typelib);
3388 }
3389 
3391  IWinHttpRequest *iface,
3392  UINT index,
3393  LCID lcid,
3394  ITypeInfo **info )
3395 {
3397  TRACE("%p, %u, %u, %p\n", request, index, lcid, info);
3398 
3400 }
3401 
3403  IWinHttpRequest *iface,
3404  REFIID riid,
3405  LPOLESTR *names,
3406  UINT count,
3407  LCID lcid,
3408  DISPID *dispid )
3409 {
3412  HRESULT hr;
3413 
3414  TRACE("%p, %s, %p, %u, %u, %p\n", request, debugstr_guid(riid), names, count, lcid, dispid);
3415 
3416  if (!names || !count || !dispid) return E_INVALIDARG;
3417 
3419  if (SUCCEEDED(hr))
3420  {
3421  hr = ITypeInfo_GetIDsOfNames( typeinfo, names, count, dispid );
3422  ITypeInfo_Release( typeinfo );
3423  }
3424  return hr;
3425 }
3426 
3428  IWinHttpRequest *iface,
3429  DISPID member,
3430  REFIID riid,
3431  LCID lcid,
3432  WORD flags,
3433  DISPPARAMS *params,
3434  VARIANT *result,
3435  EXCEPINFO *excep_info,
3436  UINT *arg_err )
3437 {
3440  HRESULT hr;
3441 
3442  TRACE("%p, %d, %s, %d, %d, %p, %p, %p, %p\n", request, member, debugstr_guid(riid),
3443  lcid, flags, params, result, excep_info, arg_err);
3444 
3445  if (!IsEqualIID( riid, &IID_NULL )) return DISP_E_UNKNOWNINTERFACE;
3446 
3448  {
3449  VARIANT ret_value, option;
3450  UINT err_pos;
3451 
3452  if (!result) result = &ret_value;
3453  if (!arg_err) arg_err = &err_pos;
3454 
3455  VariantInit( &option );
3456  VariantInit( result );
3457 
3458  if (!flags) return S_OK;
3459 
3460  if (flags == DISPATCH_PROPERTYPUT)
3461  {
3462  hr = DispGetParam( params, 0, VT_I4, &option, arg_err );
3463  if (FAILED(hr)) return hr;
3464 
3465  hr = IWinHttpRequest_put_Option( &request->IWinHttpRequest_iface, V_I4( &option ), params->rgvarg[0] );
3466  if (FAILED(hr))
3467  WARN("put_Option(%d) failed: %x\n", V_I4( &option ), hr);
3468  return hr;
3469  }
3471  {
3472  hr = DispGetParam( params, 0, VT_I4, &option, arg_err );
3473  if (FAILED(hr)) return hr;
3474 
3475  hr = IWinHttpRequest_get_Option( &request->IWinHttpRequest_iface, V_I4( &option ), result );
3476  if (FAILED(hr))
3477  WARN("get_Option(%d) failed: %x\n", V_I4( &option ), hr);
3478  return hr;
3479  }
3480 
3481  FIXME("unsupported flags %x\n", flags);
3482  return E_NOTIMPL;
3483  }
3484 
3485  /* fallback to standard implementation */
3486 
3488  if (SUCCEEDED(hr))
3489  {
3490  hr = ITypeInfo_Invoke( typeinfo, &request->IWinHttpRequest_iface, member, flags,
3491  params, result, excep_info, arg_err );
3492  ITypeInfo_Release( typeinfo );
3493  }
3494  return hr;
3495 }
3496 
3498  IWinHttpRequest *iface,
3499  HTTPREQUEST_PROXY_SETTING proxy_setting,
3501  VARIANT bypass_list )
3502 {
3505 
3506  TRACE("%p, %u, %s, %s\n", request, proxy_setting, debugstr_variant(&proxy_server),
3507  debugstr_variant(&bypass_list));
3508 
3509  EnterCriticalSection( &request->cs );
3510