ReactOS  0.4.13-dev-79-gcd489d8
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 "wine/port.h"
25 
26 #include <stdarg.h>
27 #include <assert.h>
28 #ifdef HAVE_ARPA_INET_H
29 # include <arpa/inet.h>
30 #endif
31 
32 #include "windef.h"
33 #include "winbase.h"
34 #include "ole2.h"
35 #include "initguid.h"
36 #include "httprequest.h"
37 #include "httprequestid.h"
38 #include "schannel.h"
39 #include "winhttp.h"
40 
41 #include "winhttp_private.h"
42 
43 #include "wine/debug.h"
44 
46 
47 #ifdef __REACTOS__
48 #include "inet_ntop.c"
49 #endif
50 
51 #define DEFAULT_KEEP_ALIVE_TIMEOUT 30000
52 
53 static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0};
54 static const WCHAR attr_accept_charset[] = {'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0};
55 static const WCHAR attr_accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0};
56 static const WCHAR attr_accept_language[] = {'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0};
57 static const WCHAR attr_accept_ranges[] = {'A','c','c','e','p','t','-','R','a','n','g','e','s',0};
58 static const WCHAR attr_age[] = {'A','g','e',0};
59 static const WCHAR attr_allow[] = {'A','l','l','o','w',0};
60 static const WCHAR attr_authorization[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',0};
61 static const WCHAR attr_cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
62 static const WCHAR attr_connection[] = {'C','o','n','n','e','c','t','i','o','n',0};
63 static const WCHAR attr_content_base[] = {'C','o','n','t','e','n','t','-','B','a','s','e',0};
64 static const WCHAR attr_content_encoding[] = {'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0};
65 static const WCHAR attr_content_id[] = {'C','o','n','t','e','n','t','-','I','D',0};
66 static const WCHAR attr_content_language[] = {'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0};
67 static const WCHAR attr_content_length[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
68 static const WCHAR attr_content_location[] = {'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0};
69 static const WCHAR attr_content_md5[] = {'C','o','n','t','e','n','t','-','M','D','5',0};
70 static const WCHAR attr_content_range[] = {'C','o','n','t','e','n','t','-','R','a','n','g','e',0};
71 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};
72 static const WCHAR attr_content_type[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0};
73 static const WCHAR attr_cookie[] = {'C','o','o','k','i','e',0};
74 static const WCHAR attr_date[] = {'D','a','t','e',0};
75 static const WCHAR attr_from[] = {'F','r','o','m',0};
76 static const WCHAR attr_etag[] = {'E','T','a','g',0};
77 static const WCHAR attr_expect[] = {'E','x','p','e','c','t',0};
78 static const WCHAR attr_expires[] = {'E','x','p','i','r','e','s',0};
79 static const WCHAR attr_host[] = {'H','o','s','t',0};
80 static const WCHAR attr_if_match[] = {'I','f','-','M','a','t','c','h',0};
81 static const WCHAR attr_if_modified_since[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0};
82 static const WCHAR attr_if_none_match[] = {'I','f','-','N','o','n','e','-','M','a','t','c','h',0};
83 static const WCHAR attr_if_range[] = {'I','f','-','R','a','n','g','e',0};
84 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};
85 static const WCHAR attr_last_modified[] = {'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
86 static const WCHAR attr_location[] = {'L','o','c','a','t','i','o','n',0};
87 static const WCHAR attr_max_forwards[] = {'M','a','x','-','F','o','r','w','a','r','d','s',0};
88 static const WCHAR attr_mime_version[] = {'M','i','m','e','-','V','e','r','s','i','o','n',0};
89 static const WCHAR attr_pragma[] = {'P','r','a','g','m','a',0};
90 static const WCHAR attr_proxy_authenticate[] = {'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0};
91 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};
92 static const WCHAR attr_proxy_connection[] = {'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0};
93 static const WCHAR attr_public[] = {'P','u','b','l','i','c',0};
94 static const WCHAR attr_range[] = {'R','a','n','g','e',0};
95 static const WCHAR attr_referer[] = {'R','e','f','e','r','e','r',0};
96 static const WCHAR attr_retry_after[] = {'R','e','t','r','y','-','A','f','t','e','r',0};
97 static const WCHAR attr_server[] = {'S','e','r','v','e','r',0};
98 static const WCHAR attr_set_cookie[] = {'S','e','t','-','C','o','o','k','i','e',0};
99 static const WCHAR attr_status[] = {'S','t','a','t','u','s',0};
100 static const WCHAR attr_transfer_encoding[] = {'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
101 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};
102 static const WCHAR attr_upgrade[] = {'U','p','g','r','a','d','e',0};
103 static const WCHAR attr_uri[] = {'U','R','I',0};
104 static const WCHAR attr_user_agent[] = {'U','s','e','r','-','A','g','e','n','t',0};
105 static const WCHAR attr_vary[] = {'V','a','r','y',0};
106 static const WCHAR attr_via[] = {'V','i','a',0};
107 static const WCHAR attr_warning[] = {'W','a','r','n','i','n','g',0};
108 static const WCHAR attr_www_authenticate[] = {'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0};
109 
110 static const WCHAR *attribute_table[] =
111 {
112  attr_mime_version, /* WINHTTP_QUERY_MIME_VERSION = 0 */
113  attr_content_type, /* WINHTTP_QUERY_CONTENT_TYPE = 1 */
114  attr_content_transfer_encoding, /* WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
115  attr_content_id, /* WINHTTP_QUERY_CONTENT_ID = 3 */
116  NULL, /* WINHTTP_QUERY_CONTENT_DESCRIPTION = 4 */
117  attr_content_length, /* WINHTTP_QUERY_CONTENT_LENGTH = 5 */
118  attr_content_language, /* WINHTTP_QUERY_CONTENT_LANGUAGE = 6 */
119  attr_allow, /* WINHTTP_QUERY_ALLOW = 7 */
120  attr_public, /* WINHTTP_QUERY_PUBLIC = 8 */
121  attr_date, /* WINHTTP_QUERY_DATE = 9 */
122  attr_expires, /* WINHTTP_QUERY_EXPIRES = 10 */
123  attr_last_modified, /* WINHTTP_QUERY_LAST_MODIFIEDcw = 11 */
124  NULL, /* WINHTTP_QUERY_MESSAGE_ID = 12 */
125  attr_uri, /* WINHTTP_QUERY_URI = 13 */
126  attr_from, /* WINHTTP_QUERY_DERIVED_FROM = 14 */
127  NULL, /* WINHTTP_QUERY_COST = 15 */
128  NULL, /* WINHTTP_QUERY_LINK = 16 */
129  attr_pragma, /* WINHTTP_QUERY_PRAGMA = 17 */
130  NULL, /* WINHTTP_QUERY_VERSION = 18 */
131  attr_status, /* WINHTTP_QUERY_STATUS_CODE = 19 */
132  NULL, /* WINHTTP_QUERY_STATUS_TEXT = 20 */
133  NULL, /* WINHTTP_QUERY_RAW_HEADERS = 21 */
134  NULL, /* WINHTTP_QUERY_RAW_HEADERS_CRLF = 22 */
135  attr_connection, /* WINHTTP_QUERY_CONNECTION = 23 */
136  attr_accept, /* WINHTTP_QUERY_ACCEPT = 24 */
137  attr_accept_charset, /* WINHTTP_QUERY_ACCEPT_CHARSET = 25 */
138  attr_accept_encoding, /* WINHTTP_QUERY_ACCEPT_ENCODING = 26 */
139  attr_accept_language, /* WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 */
140  attr_authorization, /* WINHTTP_QUERY_AUTHORIZATION = 28 */
141  attr_content_encoding, /* WINHTTP_QUERY_CONTENT_ENCODING = 29 */
142  NULL, /* WINHTTP_QUERY_FORWARDED = 30 */
143  NULL, /* WINHTTP_QUERY_FROM = 31 */
144  attr_if_modified_since, /* WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 */
145  attr_location, /* WINHTTP_QUERY_LOCATION = 33 */
146  NULL, /* WINHTTP_QUERY_ORIG_URI = 34 */
147  attr_referer, /* WINHTTP_QUERY_REFERER = 35 */
148  attr_retry_after, /* WINHTTP_QUERY_RETRY_AFTER = 36 */
149  attr_server, /* WINHTTP_QUERY_SERVER = 37 */
150  NULL, /* WINHTTP_TITLE = 38 */
151  attr_user_agent, /* WINHTTP_QUERY_USER_AGENT = 39 */
152  attr_www_authenticate, /* WINHTTP_QUERY_WWW_AUTHENTICATE = 40 */
153  attr_proxy_authenticate, /* WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 */
154  attr_accept_ranges, /* WINHTTP_QUERY_ACCEPT_RANGES = 42 */
155  attr_set_cookie, /* WINHTTP_QUERY_SET_COOKIE = 43 */
156  attr_cookie, /* WINHTTP_QUERY_COOKIE = 44 */
157  NULL, /* WINHTTP_QUERY_REQUEST_METHOD = 45 */
158  NULL, /* WINHTTP_QUERY_REFRESH = 46 */
159  NULL, /* WINHTTP_QUERY_CONTENT_DISPOSITION = 47 */
160  attr_age, /* WINHTTP_QUERY_AGE = 48 */
161  attr_cache_control, /* WINHTTP_QUERY_CACHE_CONTROL = 49 */
162  attr_content_base, /* WINHTTP_QUERY_CONTENT_BASE = 50 */
163  attr_content_location, /* WINHTTP_QUERY_CONTENT_LOCATION = 51 */
164  attr_content_md5, /* WINHTTP_QUERY_CONTENT_MD5 = 52 */
165  attr_content_range, /* WINHTTP_QUERY_CONTENT_RANGE = 53 */
166  attr_etag, /* WINHTTP_QUERY_ETAG = 54 */
167  attr_host, /* WINHTTP_QUERY_HOST = 55 */
168  attr_if_match, /* WINHTTP_QUERY_IF_MATCH = 56 */
169  attr_if_none_match, /* WINHTTP_QUERY_IF_NONE_MATCH = 57 */
170  attr_if_range, /* WINHTTP_QUERY_IF_RANGE = 58 */
171  attr_if_unmodified_since, /* WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
172  attr_max_forwards, /* WINHTTP_QUERY_MAX_FORWARDS = 60 */
173  attr_proxy_authorization, /* WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 */
174  attr_range, /* WINHTTP_QUERY_RANGE = 62 */
175  attr_transfer_encoding, /* WINHTTP_QUERY_TRANSFER_ENCODING = 63 */
176  attr_upgrade, /* WINHTTP_QUERY_UPGRADE = 64 */
177  attr_vary, /* WINHTTP_QUERY_VARY = 65 */
178  attr_via, /* WINHTTP_QUERY_VIA = 66 */
179  attr_warning, /* WINHTTP_QUERY_WARNING = 67 */
180  attr_expect, /* WINHTTP_QUERY_EXPECT = 68 */
181  attr_proxy_connection, /* WINHTTP_QUERY_PROXY_CONNECTION = 69 */
182  attr_unless_modified_since, /* WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
183  NULL, /* WINHTTP_QUERY_PROXY_SUPPORT = 75 */
184  NULL, /* WINHTTP_QUERY_AUTHENTICATION_INFO = 76 */
185  NULL, /* WINHTTP_QUERY_PASSPORT_URLS = 77 */
186  NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */
187 };
188 
190 {
191  task_header_t *task;
192 
193  EnterCriticalSection( &request->task_cs );
194  TRACE("%u tasks queued\n", list_count( &request->task_queue ));
195  task = LIST_ENTRY( list_head( &request->task_queue ), task_header_t, entry );
196  if (task) list_remove( &task->entry );
197  LeaveCriticalSection( &request->task_cs );
198 
199  TRACE("returning task %p\n", task);
200  return task;
201 }
202 
204 {
206  HANDLE handles[2];
207 
208  handles[0] = request->task_wait;
209  handles[1] = request->task_cancel;
210  for (;;)
211  {
213  switch (err)
214  {
215  case WAIT_OBJECT_0:
216  {
217  task_header_t *task;
218  while ((task = dequeue_task( request )))
219  {
220  task->proc( task );
221  release_object( &task->request->hdr );
222  heap_free( task );
223  }
224  break;
225  }
226  case WAIT_OBJECT_0 + 1:
227  TRACE("exiting\n");
228  CloseHandle( request->task_cancel );
229  CloseHandle( request->task_wait );
230  request->task_cs.DebugInfo->Spare[0] = 0;
231  DeleteCriticalSection( &request->task_cs );
232  request->hdr.vtbl->destroy( &request->hdr );
233  return 0;
234 
235  default:
236  ERR("wait failed %u (%u)\n", err, GetLastError());
237  break;
238  }
239  }
240  return 0;
241 }
242 
244 {
245  request_t *request = task->request;
246 
247  if (!request->task_thread)
248  {
249  if (!(request->task_wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
250  if (!(request->task_cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
251  {
252  CloseHandle( request->task_wait );
253  request->task_wait = NULL;
254  return FALSE;
255  }
256  if (!(request->task_thread = CreateThread( NULL, 0, task_proc, request, 0, NULL )))
257  {
258  CloseHandle( request->task_wait );
259  request->task_wait = NULL;
260  CloseHandle( request->task_cancel );
261  request->task_cancel = NULL;
262  return FALSE;
263  }
264  InitializeCriticalSection( &request->task_cs );
265  request->task_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": request.task_cs");
266  }
267 
268  EnterCriticalSection( &request->task_cs );
269  TRACE("queueing task %p\n", task );
270  list_add_tail( &request->task_queue, &task->entry );
271  LeaveCriticalSection( &request->task_cs );
272 
273  SetEvent( request->task_wait );
274  return TRUE;
275 }
276 
277 static void free_header( header_t *header )
278 {
279  heap_free( header->field );
280  heap_free( header->value );
281  heap_free( header );
282 }
283 
285 {
286  if (c < 32 || c == 127) return FALSE;
287  switch (c)
288  {
289  case '(': case ')':
290  case '<': case '>':
291  case '@': case ',':
292  case ';': case ':':
293  case '\\': case '\"':
294  case '/': case '[':
295  case ']': case '?':
296  case '=': case '{':
297  case '}': case ' ':
298  case '\t':
299  return FALSE;
300  default:
301  return TRUE;
302  }
303 }
304 
305 static header_t *parse_header( LPCWSTR string )
306 {
307  const WCHAR *p, *q;
308  header_t *header;
309  int len;
310 
311  p = string;
312  if (!(q = strchrW( p, ':' )))
313  {
314  WARN("no ':' in line %s\n", debugstr_w(string));
315  return NULL;
316  }
317  if (q == string)
318  {
319  WARN("empty field name in line %s\n", debugstr_w(string));
320  return NULL;
321  }
322  while (*p != ':')
323  {
324  if (!valid_token_char( *p ))
325  {
326  WARN("invalid character in field name %s\n", debugstr_w(string));
327  return NULL;
328  }
329  p++;
330  }
331  len = q - string;
332  if (!(header = heap_alloc_zero( sizeof(header_t) ))) return NULL;
333  if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) )))
334  {
335  heap_free( header );
336  return NULL;
337  }
338  memcpy( header->field, string, len * sizeof(WCHAR) );
339  header->field[len] = 0;
340 
341  q++; /* skip past colon */
342  while (*q == ' ') q++;
343  len = strlenW( q );
344 
345  if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
346  {
347  free_header( header );
348  return NULL;
349  }
350  memcpy( header->value, q, len * sizeof(WCHAR) );
351  header->value[len] = 0;
352 
353  return header;
354 }
355 
356 static int get_header_index( request_t *request, LPCWSTR field, int requested_index, BOOL request_only )
357 {
358  int index;
359 
360  TRACE("%s\n", debugstr_w(field));
361 
362  for (index = 0; index < request->num_headers; index++)
363  {
364  if (strcmpiW( request->headers[index].field, field )) continue;
365  if (request_only && !request->headers[index].is_request) continue;
366  if (!request_only && request->headers[index].is_request) continue;
367 
368  if (!requested_index) break;
369  requested_index--;
370  }
371  if (index >= request->num_headers) index = -1;
372  TRACE("returning %d\n", index);
373  return index;
374 }
375 
377 {
378  DWORD count = request->num_headers + 1;
379  header_t *hdrs;
380 
381  if (request->headers)
382  hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count );
383  else
384  hdrs = heap_alloc_zero( sizeof(header_t) );
385  if (!hdrs) return FALSE;
386 
387  request->headers = hdrs;
388  request->headers[count - 1].field = strdupW( header->field );
389  request->headers[count - 1].value = strdupW( header->value );
390  request->headers[count - 1].is_request = header->is_request;
391  request->num_headers = count;
392  return TRUE;
393 }
394 
396 {
397  if (!request->num_headers) return FALSE;
398  if (index >= request->num_headers) return FALSE;
399  request->num_headers--;
400 
401  heap_free( request->headers[index].field );
402  heap_free( request->headers[index].value );
403 
404  memmove( &request->headers[index], &request->headers[index + 1], (request->num_headers - index) * sizeof(header_t) );
405  memset( &request->headers[request->num_headers], 0, sizeof(header_t) );
406  return TRUE;
407 }
408 
410 {
411  int index;
412  header_t hdr;
413 
414  TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags);
415 
416  if ((index = get_header_index( request, field, 0, request_only )) >= 0)
417  {
419  }
420 
422  {
423  if (index >= 0)
424  {
426  if (!value || !value[0]) return TRUE;
427  }
428  else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD))
429  {
431  return FALSE;
432  }
433 
434  hdr.field = (LPWSTR)field;
435  hdr.value = (LPWSTR)value;
436  hdr.is_request = request_only;
437  return insert_header( request, &hdr );
438  }
439  else if (value)
440  {
441 
443  index >= 0)
444  {
445  WCHAR *tmp;
446  int len, len_orig, len_value;
447  header_t *header = &request->headers[index];
448 
449  len_orig = strlenW( header->value );
450  len_value = strlenW( value );
451 
452  len = len_orig + len_value + 2;
453  if (!(tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return FALSE;
454  header->value = tmp;
455  header->value[len_orig++] = (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) ? ',' : ';';
456  header->value[len_orig++] = ' ';
457 
458  memcpy( &header->value[len_orig], value, len_value * sizeof(WCHAR) );
459  header->value[len] = 0;
460  return TRUE;
461  }
462  else
463  {
464  hdr.field = (LPWSTR)field;
465  hdr.value = (LPWSTR)value;
466  hdr.is_request = request_only;
467  return insert_header( request, &hdr );
468  }
469  }
470 
471  return TRUE;
472 }
473 
475 {
476  BOOL ret = FALSE;
477  WCHAR *buffer, *p, *q;
478  header_t *header;
479 
480  if (len == ~0u) len = strlenW( headers );
481  if (!len) return TRUE;
482  if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
483  memcpy( buffer, headers, len * sizeof(WCHAR) );
484  buffer[len] = 0;
485 
486  p = buffer;
487  do
488  {
489  q = p;
490  while (*q)
491  {
492  if (q[0] == '\n' && q[1] == '\r')
493  {
494  q[0] = '\r';
495  q[1] = '\n';
496  }
497  if (q[0] == '\r' && q[1] == '\n') break;
498  q++;
499  }
500  if (!*p) break;
501  if (*q == '\r')
502  {
503  *q = 0;
504  q += 2; /* jump over \r\n */
505  }
506  if ((header = parse_header( p )))
507  {
508  ret = process_header( request, header->field, header->value, flags, TRUE );
509  free_header( header );
510  }
511  p = q;
512  } while (ret);
513 
514  heap_free( buffer );
515  return ret;
516 }
517 
518 /***********************************************************************
519  * WinHttpAddRequestHeaders (winhttp.@)
520  */
522 {
523  BOOL ret;
525 
526  TRACE("%p, %s, %u, 0x%08x\n", hrequest, debugstr_wn(headers, len), len, flags);
527 
528  if (!headers || !len)
529  {
531  return FALSE;
532  }
533  if (!(request = (request_t *)grab_object( hrequest )))
534  {
536  return FALSE;
537  }
538  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
539  {
540  release_object( &request->hdr );
542  return FALSE;
543  }
544 
546 
547  release_object( &request->hdr );
549  return ret;
550 }
551 
553 {
554  WCHAR *ret;
555 
556  if (strcmpiW( request->connect->hostname, request->connect->servername ))
557  {
558  static const WCHAR http[] = { 'h','t','t','p',0 };
559  static const WCHAR https[] = { 'h','t','t','p','s',0 };
560  static const WCHAR fmt[] = { '%','s',':','/','/','%','s',0 };
561  LPCWSTR scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? https : http;
562  int len;
563 
564  len = strlenW( scheme ) + strlenW( request->connect->hostname );
565  /* 3 characters for '://', 1 for NUL. */
566  len += 4;
567  if (request->connect->hostport)
568  {
569  /* 1 for ':' between host and port, up to 5 for port */
570  len += 6;
571  }
572  if (request->path)
573  len += strlenW( request->path );
574  if ((ret = heap_alloc( len * sizeof(WCHAR) )))
575  {
576  sprintfW( ret, fmt, scheme, request->connect->hostname );
577  if (request->connect->hostport)
578  {
579  static const WCHAR colonFmt[] = { ':','%','u',0 };
580 
581  sprintfW( ret + strlenW( ret ), colonFmt,
582  request->connect->hostport );
583  }
584  if (request->path)
585  strcatW( ret, request->path );
586  }
587  }
588  else
589  ret = request->path;
590  return ret;
591 }
592 
594 {
595  static const WCHAR space[] = {' ',0};
596  static const WCHAR crlf[] = {'\r','\n',0};
597  static const WCHAR colon[] = {':',' ',0};
598  static const WCHAR twocrlf[] = {'\r','\n','\r','\n',0};
599 
600  WCHAR *path, *ret;
601  const WCHAR **headers, **p;
602  unsigned int len, i = 0, j;
603 
604  /* allocate space for an array of all the string pointers to be added */
605  len = request->num_headers * 4 + 7;
606  if (!(headers = heap_alloc( len * sizeof(LPCWSTR) ))) return NULL;
607 
609  headers[i++] = request->verb;
610  headers[i++] = space;
611  headers[i++] = path;
612  headers[i++] = space;
613  headers[i++] = request->version;
614 
615  for (j = 0; j < request->num_headers; j++)
616  {
617  if (request->headers[j].is_request)
618  {
619  headers[i++] = crlf;
620  headers[i++] = request->headers[j].field;
621  headers[i++] = colon;
622  headers[i++] = request->headers[j].value;
623 
624  TRACE("adding header %s (%s)\n", debugstr_w(request->headers[j].field),
625  debugstr_w(request->headers[j].value));
626  }
627  }
628  headers[i++] = twocrlf;
629  headers[i] = NULL;
630 
631  len = 0;
632  for (p = headers; *p; p++) len += strlenW( *p );
633  len++;
634 
635  if (!(ret = heap_alloc( len * sizeof(WCHAR) )))
636  goto out;
637  *ret = 0;
638  for (p = headers; *p; p++) strcatW( ret, *p );
639 
640 out:
641  if (path != request->path)
642  heap_free( path );
643  heap_free( headers );
644  return ret;
645 }
646 
647 #define QUERY_MODIFIER_MASK (WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_FLAG_SYSTEMTIME | WINHTTP_QUERY_FLAG_NUMBER)
648 
650 {
651  header_t *header = NULL;
652  BOOL request_only, ret = FALSE;
653  int requested_index, header_index = -1;
654  DWORD attr, len;
655 
656  request_only = level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS;
657  requested_index = index ? *index : 0;
658 
660  switch (attr)
661  {
663  {
664  header_index = get_header_index( request, name, requested_index, request_only );
665  break;
666  }
668  {
669  WCHAR *headers, *p, *q;
670 
671  if (request_only)
673  else
674  headers = request->raw_headers;
675 
676  if (!(p = headers)) return FALSE;
677  for (len = 0; *p; p++) if (*p != '\r') len++;
678 
679  if (!buffer || len * sizeof(WCHAR) > *buflen)
681  else
682  {
683  for (p = headers, q = buffer; *p; p++, q++)
684  {
685  if (*p != '\r') *q = *p;
686  else
687  {
688  *q = 0;
689  p++; /* skip '\n' */
690  }
691  }
692  TRACE("returning data: %s\n", debugstr_wn(buffer, len));
693  if (len) len--;
694  ret = TRUE;
695  }
696  *buflen = len * sizeof(WCHAR);
697  if (request_only) heap_free( headers );
698  return ret;
699  }
701  {
702  WCHAR *headers;
703 
704  if (request_only)
706  else
707  headers = request->raw_headers;
708 
709  if (!headers) return FALSE;
710  len = strlenW( headers ) * sizeof(WCHAR);
711  if (!buffer || len + sizeof(WCHAR) > *buflen)
712  {
713  len += sizeof(WCHAR);
715  }
716  else
717  {
718  memcpy( buffer, headers, len + sizeof(WCHAR) );
719  TRACE("returning data: %s\n", debugstr_wn(buffer, len / sizeof(WCHAR)));
720  ret = TRUE;
721  }
722  *buflen = len;
723  if (request_only) heap_free( headers );
724  return ret;
725  }
727  len = strlenW( request->version ) * sizeof(WCHAR);
728  if (!buffer || len + sizeof(WCHAR) > *buflen)
729  {
730  len += sizeof(WCHAR);
732  }
733  else
734  {
735  strcpyW( buffer, request->version );
736  TRACE("returning string: %s\n", debugstr_w(buffer));
737  ret = TRUE;
738  }
739  *buflen = len;
740  return ret;
741 
743  len = strlenW( request->status_text ) * sizeof(WCHAR);
744  if (!buffer || len + sizeof(WCHAR) > *buflen)
745  {
746  len += sizeof(WCHAR);
748  }
749  else
750  {
751  strcpyW( buffer, request->status_text );
752  TRACE("returning string: %s\n", debugstr_w(buffer));
753  ret = TRUE;
754  }
755  *buflen = len;
756  return ret;
757 
758  default:
759  if (attr >= sizeof(attribute_table)/sizeof(attribute_table[0]) || !attribute_table[attr])
760  {
761  FIXME("attribute %u not implemented\n", attr);
762  return FALSE;
763  }
764  TRACE("attribute %s\n", debugstr_w(attribute_table[attr]));
765  header_index = get_header_index( request, attribute_table[attr], requested_index, request_only );
766  break;
767  }
768 
769  if (header_index >= 0)
770  {
771  header = &request->headers[header_index];
772  }
773  if (!header || (request_only && !header->is_request))
774  {
776  return FALSE;
777  }
778  if (index) *index += 1;
780  {
781  if (!buffer || sizeof(int) > *buflen)
782  {
784  }
785  else
786  {
787  int *number = buffer;
788  *number = atoiW( header->value );
789  TRACE("returning number: %d\n", *number);
790  ret = TRUE;
791  }
792  *buflen = sizeof(int);
793  }
795  {
796  SYSTEMTIME *st = buffer;
797  if (!buffer || sizeof(SYSTEMTIME) > *buflen)
798  {
800  }
801  else if ((ret = WinHttpTimeToSystemTime( header->value, st )))
802  {
803  TRACE("returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
804  st->wYear, st->wMonth, st->wDay, st->wDayOfWeek,
805  st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
806  }
807  *buflen = sizeof(SYSTEMTIME);
808  }
809  else if (header->value)
810  {
811  len = strlenW( header->value ) * sizeof(WCHAR);
812  if (!buffer || len + sizeof(WCHAR) > *buflen)
813  {
814  len += sizeof(WCHAR);
816  }
817  else
818  {
819  strcpyW( buffer, header->value );
820  TRACE("returning string: %s\n", debugstr_w(buffer));
821  ret = TRUE;
822  }
823  *buflen = len;
824  }
825  return ret;
826 }
827 
828 /***********************************************************************
829  * WinHttpQueryHeaders (winhttp.@)
830  */
832 {
833  BOOL ret;
835 
836  TRACE("%p, 0x%08x, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index);
837 
838  if (!(request = (request_t *)grab_object( hrequest )))
839  {
841  return FALSE;
842  }
843  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
844  {
845  release_object( &request->hdr );
847  return FALSE;
848  }
849 
850  ret = query_headers( request, level, name, buffer, buflen, index );
851 
852  release_object( &request->hdr );
854  return ret;
855 }
856 
857 #undef ARRAYSIZE
858 #define ARRAYSIZE(array) (sizeof(array) / sizeof((array)[0]))
859 
860 static const WCHAR basicW[] = {'B','a','s','i','c',0};
861 static const WCHAR ntlmW[] = {'N','T','L','M',0};
862 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0};
863 static const WCHAR digestW[] = {'D','i','g','e','s','t',0};
864 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
865 
866 static const struct
867 {
868  const WCHAR *str;
869  unsigned int len;
871 }
872 auth_schemes[] =
873 {
879 };
880 static const unsigned int num_auth_schemes = sizeof(auth_schemes)/sizeof(auth_schemes[0]);
881 
883 {
884  int i;
885 
886  for (i = 0; i < num_auth_schemes; i++) if (flag == auth_schemes[i].scheme) return i;
887  return SCHEME_INVALID;
888 }
889 
891 {
892  unsigned int i;
893 
894  for (i = 0; i < num_auth_schemes; i++)
895  {
897  (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
898  }
899  return 0;
900 }
901 
903 {
904  DWORD index = 0, supported_schemes = 0, first_scheme = 0;
905  BOOL ret = FALSE;
906 
907  for (;;)
908  {
909  WCHAR *buffer;
910  DWORD size, scheme;
911 
912  size = 0;
915 
916  index--;
917  if (!(buffer = heap_alloc( size ))) return FALSE;
919  {
920  heap_free( buffer );
921  return FALSE;
922  }
924  heap_free( buffer );
925  if (!scheme) continue;
926 
927  if (!first_scheme) first_scheme = scheme;
928  supported_schemes |= scheme;
929 
930  ret = TRUE;
931  }
932 
933  if (ret)
934  {
935  *supported = supported_schemes;
936  *first = first_scheme;
937  }
938  return ret;
939 }
940 
941 /***********************************************************************
942  * WinHttpQueryAuthSchemes (winhttp.@)
943  */
945 {
946  BOOL ret = FALSE;
948 
949  TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target);
950 
951  if (!(request = (request_t *)grab_object( hrequest )))
952  {
954  return FALSE;
955  }
956  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
957  {
958  release_object( &request->hdr );
960  return FALSE;
961  }
962  if (!supported || !first || !target)
963  {
964  release_object( &request->hdr );
966  return FALSE;
967 
968  }
969 
971  {
973  ret = TRUE;
974  }
976  {
978  ret = TRUE;
979  }
980 
981  release_object( &request->hdr );
983  return ret;
984 }
985 
986 static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 )
987 {
988  UINT n = 0, x;
989  static const char base64enc[] =
990  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
991 
992  while (len > 0)
993  {
994  /* first 6 bits, all from bin[0] */
995  base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
996  x = (bin[0] & 3) << 4;
997 
998  /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
999  if (len == 1)
1000  {
1001  base64[n++] = base64enc[x];
1002  base64[n++] = '=';
1003  base64[n++] = '=';
1004  break;
1005  }
1006  base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
1007  x = (bin[1] & 0x0f) << 2;
1008 
1009  /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1010  if (len == 2)
1011  {
1012  base64[n++] = base64enc[x];
1013  base64[n++] = '=';
1014  break;
1015  }
1016  base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
1017 
1018  /* last 6 bits, all from bin [2] */
1019  base64[n++] = base64enc[bin[2] & 0x3f];
1020  bin += 3;
1021  len -= 3;
1022  }
1023  base64[n] = 0;
1024  return n;
1025 }
1026 
1027 static inline char decode_char( WCHAR c )
1028 {
1029  if (c >= 'A' && c <= 'Z') return c - 'A';
1030  if (c >= 'a' && c <= 'z') return c - 'a' + 26;
1031  if (c >= '0' && c <= '9') return c - '0' + 52;
1032  if (c == '+') return 62;
1033  if (c == '/') return 63;
1034  return 64;
1035 }
1036 
1037 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
1038 {
1039  unsigned int i = 0;
1040  char c0, c1, c2, c3;
1041  const WCHAR *p = base64;
1042 
1043  while (len > 4)
1044  {
1045  if ((c0 = decode_char( p[0] )) > 63) return 0;
1046  if ((c1 = decode_char( p[1] )) > 63) return 0;
1047  if ((c2 = decode_char( p[2] )) > 63) return 0;
1048  if ((c3 = decode_char( p[3] )) > 63) return 0;
1049 
1050  if (buf)
1051  {
1052  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1053  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1054  buf[i + 2] = (c2 << 6) | c3;
1055  }
1056  len -= 4;
1057  i += 3;
1058  p += 4;
1059  }
1060  if (p[2] == '=')
1061  {
1062  if ((c0 = decode_char( p[0] )) > 63) return 0;
1063  if ((c1 = decode_char( p[1] )) > 63) return 0;
1064 
1065  if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
1066  i++;
1067  }
1068  else if (p[3] == '=')
1069  {
1070  if ((c0 = decode_char( p[0] )) > 63) return 0;
1071  if ((c1 = decode_char( p[1] )) > 63) return 0;
1072  if ((c2 = decode_char( p[2] )) > 63) return 0;
1073 
1074  if (buf)
1075  {
1076  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1077  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1078  }
1079  i += 2;
1080  }
1081  else
1082  {
1083  if ((c0 = decode_char( p[0] )) > 63) return 0;
1084  if ((c1 = decode_char( p[1] )) > 63) return 0;
1085  if ((c2 = decode_char( p[2] )) > 63) return 0;
1086  if ((c3 = decode_char( p[3] )) > 63) return 0;
1087 
1088  if (buf)
1089  {
1090  buf[i + 0] = (c0 << 2) | (c1 >> 4);
1091  buf[i + 1] = (c1 << 4) | (c2 >> 2);
1092  buf[i + 2] = (c2 << 6) | c3;
1093  }
1094  i += 3;
1095  }
1096  return i;
1097 }
1098 
1099 static struct authinfo *alloc_authinfo(void)
1100 {
1101  struct authinfo *ret;
1102 
1103  if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
1104 
1105  SecInvalidateHandle( &ret->cred );
1106  SecInvalidateHandle( &ret->ctx );
1107  memset( &ret->exp, 0, sizeof(ret->exp) );
1108  ret->scheme = 0;
1109  ret->attr = 0;
1110  ret->max_token = 0;
1111  ret->data = NULL;
1112  ret->data_len = 0;
1113  ret->finished = FALSE;
1114  return ret;
1115 }
1116 
1118 {
1119  if (!authinfo) return;
1120 
1121  if (SecIsValidHandle( &authinfo->ctx ))
1123  if (SecIsValidHandle( &authinfo->cred ))
1125 
1126  heap_free( authinfo->data );
1127  heap_free( authinfo );
1128 }
1129 
1131 {
1132  DWORD size, index = 0;
1133  for (;;)
1134  {
1135  size = len;
1136  if (!query_headers( request, level, NULL, buffer, &size, &index )) return FALSE;
1137  if (auth_scheme_from_header( buffer ) == scheme) break;
1138  }
1139  return TRUE;
1140 }
1141 
1143 {
1144  struct authinfo *authinfo, **auth_ptr;
1145  enum auth_scheme scheme = scheme_from_flag( scheme_flag );
1146  const WCHAR *auth_target, *username, *password;
1147  WCHAR auth_value[2048], *auth_reply;
1148  DWORD len = sizeof(auth_value), len_scheme, flags;
1149  BOOL ret, has_auth_value;
1150 
1151  if (scheme == SCHEME_INVALID) return FALSE;
1152 
1153  switch (target)
1154  {
1156  has_auth_value = get_authvalue( request, WINHTTP_QUERY_WWW_AUTHENTICATE, scheme_flag, auth_value, len );
1157  auth_ptr = &request->authinfo;
1159  if (request->creds[TARGET_SERVER][scheme].username)
1160  {
1161  if (scheme != SCHEME_BASIC && !has_auth_value) return FALSE;
1162  username = request->creds[TARGET_SERVER][scheme].username;
1163  password = request->creds[TARGET_SERVER][scheme].password;
1164  }
1165  else
1166  {
1167  if (!has_auth_value) return FALSE;
1168  username = request->connect->username;
1169  password = request->connect->password;
1170  }
1171  break;
1172 
1174  if (!get_authvalue( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, scheme_flag, auth_value, len ))
1175  return FALSE;
1176  auth_ptr = &request->proxy_authinfo;
1178  if (request->creds[TARGET_PROXY][scheme].username)
1179  {
1180  username = request->creds[TARGET_PROXY][scheme].username;
1181  password = request->creds[TARGET_PROXY][scheme].password;
1182  }
1183  else
1184  {
1185  username = request->connect->session->proxy_username;
1186  password = request->connect->session->proxy_password;
1187  }
1188  break;
1189 
1190  default:
1191  WARN("unknown target %x\n", target);
1192  return FALSE;
1193  }
1194  authinfo = *auth_ptr;
1195 
1196  switch (scheme)
1197  {
1198  case SCHEME_BASIC:
1199  {
1200  int userlen, passlen;
1201 
1202  if (!username || !password) return FALSE;
1203  if ((!authinfo && !(authinfo = alloc_authinfo())) || authinfo->finished) return FALSE;
1204 
1205  userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL );
1206  passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL );
1207 
1208  authinfo->data_len = userlen + 1 + passlen;
1209  if (!(authinfo->data = heap_alloc( authinfo->data_len ))) return FALSE;
1210 
1211  WideCharToMultiByte( CP_UTF8, 0, username, -1, authinfo->data, userlen, NULL, NULL );
1212  authinfo->data[userlen] = ':';
1213  WideCharToMultiByte( CP_UTF8, 0, password, -1, authinfo->data + userlen + 1, passlen, NULL, NULL );
1214 
1216  authinfo->finished = TRUE;
1217  break;
1218  }
1219  case SCHEME_NTLM:
1220  case SCHEME_NEGOTIATE:
1221  {
1223  SecBufferDesc out_desc, in_desc;
1224  SecBuffer out, in;
1226  const WCHAR *p;
1227  BOOL first = FALSE;
1228 
1229  if (!authinfo)
1230  {
1231  TimeStamp exp;
1233  WCHAR *domain, *user;
1234 
1235  if (!username || !password || !(authinfo = alloc_authinfo())) return FALSE;
1236 
1237  first = TRUE;
1238  domain = (WCHAR *)username;
1239  user = strchrW( username, '\\' );
1240 
1241  if (user) user++;
1242  else
1243  {
1244  user = (WCHAR *)username;
1245  domain = NULL;
1246  }
1248  id.User = user;
1249  id.UserLength = strlenW( user );
1250  id.Domain = domain;
1251  id.DomainLength = domain ? user - domain - 1 : 0;
1252  id.Password = (WCHAR *)password;
1253  id.PasswordLength = strlenW( password );
1254 
1257  &authinfo->cred, &exp );
1258  if (status == SEC_E_OK)
1259  {
1262  if (status == SEC_E_OK)
1263  {
1264  authinfo->max_token = info->cbMaxToken;
1266  }
1267  }
1268  if (status != SEC_E_OK)
1269  {
1270  WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
1272  heap_free( authinfo );
1273  return FALSE;
1274  }
1275  authinfo->scheme = scheme;
1276  }
1277  else if (authinfo->finished) return FALSE;
1278 
1279  if ((strlenW( auth_value ) < auth_schemes[authinfo->scheme].len ||
1280  strncmpiW( auth_value, auth_schemes[authinfo->scheme].str, auth_schemes[authinfo->scheme].len )))
1281  {
1282  ERR("authentication scheme changed from %s to %s\n",
1283  debugstr_w(auth_schemes[authinfo->scheme].str), debugstr_w(auth_value));
1285  *auth_ptr = NULL;
1286  return FALSE;
1287  }
1288  in.BufferType = SECBUFFER_TOKEN;
1289  in.cbBuffer = 0;
1290  in.pvBuffer = NULL;
1291 
1292  in_desc.ulVersion = 0;
1293  in_desc.cBuffers = 1;
1294  in_desc.pBuffers = &in;
1295 
1296  p = auth_value + auth_schemes[scheme].len;
1297  if (*p == ' ')
1298  {
1299  int len = strlenW( ++p );
1300  in.cbBuffer = decode_base64( p, len, NULL );
1301  if (!(in.pvBuffer = heap_alloc( in.cbBuffer ))) {
1303  *auth_ptr = NULL;
1304  return FALSE;
1305  }
1306  decode_base64( p, len, in.pvBuffer );
1307  }
1308  out.BufferType = SECBUFFER_TOKEN;
1309  out.cbBuffer = authinfo->max_token;
1310  if (!(out.pvBuffer = heap_alloc( authinfo->max_token )))
1311  {
1312  heap_free( in.pvBuffer );
1314  *auth_ptr = NULL;
1315  return FALSE;
1316  }
1317  out_desc.ulVersion = 0;
1318  out_desc.cBuffers = 1;
1319  out_desc.pBuffers = &out;
1320 
1322  first ? request->connect->servername : NULL, flags, 0,
1323  SECURITY_NETWORK_DREP, in.pvBuffer ? &in_desc : NULL, 0,
1324  &authinfo->ctx, &out_desc, &authinfo->attr, &authinfo->exp );
1325  heap_free( in.pvBuffer );
1326  if (status == SEC_E_OK)
1327  {
1328  heap_free( authinfo->data );
1329  authinfo->data = out.pvBuffer;
1330  authinfo->data_len = out.cbBuffer;
1331  authinfo->finished = TRUE;
1332  TRACE("sending last auth packet\n");
1333  }
1334  else if (status == SEC_I_CONTINUE_NEEDED)
1335  {
1336  heap_free( authinfo->data );
1337  authinfo->data = out.pvBuffer;
1338  authinfo->data_len = out.cbBuffer;
1339  TRACE("sending next auth packet\n");
1340  }
1341  else
1342  {
1343  ERR("InitializeSecurityContextW failed with error 0x%08x\n", status);
1344  heap_free( out.pvBuffer );
1346  *auth_ptr = NULL;
1347  return FALSE;
1348  }
1349  break;
1350  }
1351  default:
1352  ERR("invalid scheme %u\n", scheme);
1353  return FALSE;
1354  }
1355  *auth_ptr = authinfo;
1356 
1357  len_scheme = auth_schemes[authinfo->scheme].len;
1358  len = len_scheme + 1 + ((authinfo->data_len + 2) * 4) / 3;
1359  if (!(auth_reply = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
1360 
1361  memcpy( auth_reply, auth_schemes[authinfo->scheme].str, len_scheme * sizeof(WCHAR) );
1362  auth_reply[len_scheme] = ' ';
1363  encode_base64( authinfo->data, authinfo->data_len, auth_reply + len_scheme + 1 );
1364 
1366  ret = process_header( request, auth_target, auth_reply, flags, TRUE );
1367  heap_free( auth_reply );
1368  return ret;
1369 }
1370 
1372 {
1373  LPCWSTR *t;
1374  LPWSTR str;
1375 
1376  for( t = list; *t ; t++ )
1377  len += strlenW( *t );
1378  len++;
1379 
1380  str = heap_alloc( len * sizeof(WCHAR) );
1381  if (!str) return NULL;
1382  *str = 0;
1383 
1384  for( t = list; *t ; t++ )
1385  strcatW( str, *t );
1386 
1387  return str;
1388 }
1389 
1392 {
1393  static const WCHAR crlf[] = {'\r','\n',0};
1394  static const WCHAR space[] = { ' ',0 };
1395  static const WCHAR colon[] = { ':',' ',0 };
1396  static const WCHAR twocrlf[] = {'\r','\n','\r','\n', 0};
1397  LPWSTR requestString;
1398  DWORD len, n;
1399  LPCWSTR *req;
1400  UINT i;
1401  LPWSTR p;
1402 
1403  /* allocate space for an array of all the string pointers to be added */
1404  len = (request->num_headers) * 4 + 10;
1405  req = heap_alloc( len * sizeof(LPCWSTR) );
1406  if (!req) return NULL;
1407 
1408  /* add the verb, path and HTTP version string */
1409  n = 0;
1410  req[n++] = verb;
1411  req[n++] = space;
1412  req[n++] = path;
1413  req[n++] = space;
1414  req[n++] = version;
1415 
1416  /* Append custom request headers */
1417  for (i = 0; i < request->num_headers; i++)
1418  {
1419  if (request->headers[i].is_request)
1420  {
1421  req[n++] = crlf;
1422  req[n++] = request->headers[i].field;
1423  req[n++] = colon;
1424  req[n++] = request->headers[i].value;
1425 
1426  TRACE("Adding custom header %s (%s)\n",
1427  debugstr_w(request->headers[i].field),
1428  debugstr_w(request->headers[i].value));
1429  }
1430  }
1431 
1432  if( n >= len )
1433  ERR("oops. buffer overrun\n");
1434 
1435  req[n] = NULL;
1436  requestString = concatenate_string_list( req, 4 );
1437  heap_free( req );
1438  if (!requestString) return NULL;
1439 
1440  /*
1441  * Set (header) termination string for request
1442  * Make sure there are exactly two new lines at the end of the request
1443  */
1444  p = &requestString[strlenW(requestString)-1];
1445  while ( (*p == '\n') || (*p == '\r') )
1446  p--;
1447  strcpyW( p+1, twocrlf );
1448 
1449  return requestString;
1450 }
1451 
1452 static BOOL read_reply( request_t *request );
1453 
1455 {
1456  static const WCHAR verbConnect[] = {'C','O','N','N','E','C','T',0};
1457  static const WCHAR fmt[] = {'%','s',':','%','u',0};
1458  BOOL ret = FALSE;
1459  LPWSTR path;
1460  connect_t *connect = request->connect;
1461 
1462  path = heap_alloc( (strlenW( connect->hostname ) + 13) * sizeof(WCHAR) );
1463  if (path)
1464  {
1465  LPWSTR requestString;
1466 
1467  sprintfW( path, fmt, connect->hostname, connect->hostport );
1468  requestString = build_header_request_string( request, verbConnect,
1469  path, http1_1 );
1470  heap_free( path );
1471  if (requestString)
1472  {
1473  LPSTR req_ascii = strdupWA( requestString );
1474 
1475  heap_free( requestString );
1476  if (req_ascii)
1477  {
1478  int len = strlen( req_ascii ), bytes_sent;
1479 
1480  ret = netconn_send( request->netconn, req_ascii, len, &bytes_sent );
1481  heap_free( req_ascii );
1482  if (ret)
1483  ret = read_reply( request );
1484  }
1485  }
1486  }
1487  return ret;
1488 }
1489 
1490 #ifndef INET6_ADDRSTRLEN
1491 #define INET6_ADDRSTRLEN 46
1492 #endif
1493 
1495 {
1496  char buf[INET6_ADDRSTRLEN];
1497  void *src;
1498 
1499  switch (addr->ss_family)
1500  {
1501  case AF_INET:
1502  src = &((struct sockaddr_in *)addr)->sin_addr;
1503  break;
1504  case AF_INET6:
1505  src = &((struct sockaddr_in6 *)addr)->sin6_addr;
1506  break;
1507  default:
1508  WARN("unsupported address family %d\n", addr->ss_family);
1509  return NULL;
1510  }
1511  if (!inet_ntop( addr->ss_family, src, buf, sizeof(buf) )) return NULL;
1512  return strdupAW( buf );
1513 }
1514 
1517 {
1518  0, 0, &connection_pool_cs,
1520  0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
1521 };
1522 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
1523 
1525 
1527 {
1528  LONG ref;
1529 
1531  if (!(ref = --host->ref)) list_remove( &host->entry );
1533  if (ref) return;
1534 
1535  assert( list_empty( &host->connections ) );
1536  heap_free( host->hostname );
1537  heap_free( host );
1538 }
1539 
1541 
1543 {
1544  unsigned int remaining_connections;
1545  netconn_t *netconn, *next_netconn;
1546  hostdata_t *host, *next_host;
1547  ULONGLONG now;
1548 
1549  do
1550  {
1551  /* FIXME: Use more sophisticated method */
1552  Sleep(5000);
1553  remaining_connections = 0;
1554  now = GetTickCount64();
1555 
1557 
1559  {
1560  LIST_FOR_EACH_ENTRY_SAFE(netconn, next_netconn, &host->connections, netconn_t, entry)
1561  {
1562  if (netconn->keep_until < now)
1563  {
1564  TRACE("freeing %p\n", netconn);
1565  list_remove(&netconn->entry);
1566  netconn_close(netconn);
1567  }
1568  else
1569  {
1570  remaining_connections++;
1571  }
1572  }
1573  }
1574 
1575  if (!remaining_connections) connection_collector_running = FALSE;
1576 
1578  } while(remaining_connections);
1579 
1581 }
1582 
1583 static void cache_connection( netconn_t *netconn )
1584 {
1585  TRACE( "caching connection %p\n", netconn );
1586 
1588 
1590  list_add_head( &netconn->host->connections, &netconn->entry );
1591 
1593  {
1594  HMODULE module;
1595  HANDLE thread;
1596 
1597  GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)winhttp_instance, &module );
1598 
1600  if (thread)
1601  {
1602  CloseHandle( thread );
1604  }
1605  else
1606  {
1608  }
1609  }
1610 
1612 }
1613 
1615 {
1616  DWORD ret = 0;
1622  return ret;
1623 }
1624 
1626 {
1627  SCHANNEL_CRED cred;
1629 
1630  if (session->cred_handle_initialized) return TRUE;
1631 
1632  memset( &cred, 0, sizeof(cred) );
1636  NULL, NULL, &session->cred_handle, NULL )) != SEC_E_OK)
1637  {
1638  WARN( "AcquireCredentialsHandleW failed: 0x%08x\n", status );
1639  return FALSE;
1640  }
1641  session->cred_handle_initialized = TRUE;
1642  return TRUE;
1643 }
1644 
1646 {
1647  BOOL is_secure = request->hdr.flags & WINHTTP_FLAG_SECURE;
1648  hostdata_t *host = NULL, *iter;
1649  netconn_t *netconn = NULL;
1650  connect_t *connect;
1651  WCHAR *addressW = NULL;
1653  DWORD len;
1654 
1655  if (request->netconn) goto done;
1656 
1657  connect = request->connect;
1658  port = connect->serverport ? connect->serverport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
1659 
1661 
1663  {
1664  if (iter->port == port && !strcmpW( connect->servername, iter->hostname ) && !is_secure == !iter->secure)
1665  {
1666  host = iter;
1667  host->ref++;
1668  break;
1669  }
1670  }
1671 
1672  if (!host)
1673  {
1674  if ((host = heap_alloc( sizeof(*host) )))
1675  {
1676  host->ref = 1;
1677  host->secure = is_secure;
1678  host->port = port;
1679  list_init( &host->connections );
1680  if ((host->hostname = strdupW( connect->servername )))
1681  {
1682  list_add_head( &connection_pool, &host->entry );
1683  }
1684  else
1685  {
1686  heap_free( host );
1687  host = NULL;
1688  }
1689  }
1690  }
1691 
1693 
1694  if (!host) return FALSE;
1695 
1696  for (;;)
1697  {
1699  if (!list_empty( &host->connections ))
1700  {
1701  netconn = LIST_ENTRY( list_head( &host->connections ), netconn_t, entry );
1702  list_remove( &netconn->entry );
1703  }
1705  if (!netconn) break;
1706 
1707  if (netconn_is_alive( netconn )) break;
1708  TRACE("connection %p no longer alive, closing\n", netconn);
1709  netconn_close( netconn );
1710  netconn = NULL;
1711  }
1712 
1713  if (!connect->resolved && netconn)
1714  {
1715  connect->sockaddr = netconn->sockaddr;
1716  connect->resolved = TRUE;
1717  }
1718 
1719  if (!connect->resolved)
1720  {
1721  len = strlenW( host->hostname ) + 1;
1723 
1724  if (!netconn_resolve( host->hostname, port, &connect->sockaddr, request->resolve_timeout ))
1725  {
1726  release_host( host );
1727  return FALSE;
1728  }
1729  connect->resolved = TRUE;
1730 
1731  if (!(addressW = addr_to_str( &connect->sockaddr )))
1732  {
1733  release_host( host );
1734  return FALSE;
1735  }
1736  len = strlenW( addressW ) + 1;
1738  }
1739 
1740  if (!netconn)
1741  {
1742  if (!addressW && !(addressW = addr_to_str( &connect->sockaddr )))
1743  {
1744  release_host( host );
1745  return FALSE;
1746  }
1747 
1748  TRACE("connecting to %s:%u\n", debugstr_w(addressW), port);
1749 
1751 
1752  if (!(netconn = netconn_create( host, &connect->sockaddr, request->connect_timeout )))
1753  {
1754  heap_free( addressW );
1755  release_host( host );
1756  return FALSE;
1757  }
1758  netconn_set_timeout( netconn, TRUE, request->send_timeout );
1759  netconn_set_timeout( netconn, FALSE, request->recv_timeout );
1760  if (is_secure)
1761  {
1762  if (connect->session->proxy_server &&
1763  strcmpiW( connect->hostname, connect->servername ))
1764  {
1765  if (!secure_proxy_connect( request ))
1766  {
1767  heap_free( addressW );
1768  netconn_close( netconn );
1769  return FALSE;
1770  }
1771  }
1772  if (!ensure_cred_handle( connect->session ) ||
1773  !netconn_secure_connect( netconn, connect->hostname, request->security_flags,
1774  &connect->session->cred_handle ))
1775  {
1776  heap_free( addressW );
1777  netconn_close( netconn );
1778  return FALSE;
1779  }
1780  }
1781 
1782  request->netconn = netconn;
1783  send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, strlenW(addressW) + 1 );
1784  }
1785  else
1786  {
1787  TRACE("using connection %p\n", netconn);
1788 
1789  netconn_set_timeout( netconn, TRUE, request->send_timeout );
1790  netconn_set_timeout( netconn, FALSE, request->recv_timeout );
1791  request->netconn = netconn;
1792  }
1793 
1794 done:
1795  request->read_pos = request->read_size = 0;
1796  request->read_chunked = FALSE;
1797  request->read_chunked_size = ~0u;
1798  request->read_chunked_eof = FALSE;
1799  heap_free( addressW );
1800  return TRUE;
1801 }
1802 
1804 {
1805  if (!request->netconn) return;
1806 
1808  netconn_close( request->netconn );
1809  request->netconn = NULL;
1811 }
1812 
1814 {
1815  BOOL ret;
1816  DWORD len;
1817  WCHAR *host;
1818  static const WCHAR fmt[] = {'%','s',':','%','u',0};
1819  connect_t *connect = request->connect;
1821 
1822  port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
1823 
1825  {
1826  return process_header( request, attr_host, connect->hostname, modifier, TRUE );
1827  }
1828  len = strlenW( connect->hostname ) + 7; /* sizeof(":65335") */
1829  if (!(host = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
1830  sprintfW( host, fmt, connect->hostname, port );
1831  ret = process_header( request, attr_host, host, modifier, TRUE );
1832  heap_free( host );
1833  return ret;
1834 }
1835 
1837 {
1838  unsigned int i;
1839 
1840  for (i = 0; i < request->num_headers; i++)
1841  {
1842  if (!request->headers[i].field) continue;
1843  if (!request->headers[i].value) continue;
1844  if (request->headers[i].is_request) continue;
1845  delete_header( request, i );
1846  i--;
1847  }
1848 }
1849 
1850 /* remove some amount of data from the read buffer */
1851 static void remove_data( request_t *request, int count )
1852 {
1853  if (!(request->read_size -= count)) request->read_pos = 0;
1854  else request->read_pos += count;
1855 }
1856 
1857 /* read some more data into the read buffer */
1859 {
1860  int len;
1861  BOOL ret;
1862 
1863  if (request->read_chunked_eof) return FALSE;
1864 
1865  if (request->read_size && request->read_pos)
1866  {
1867  /* move existing data to the start of the buffer */
1868  memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size );
1869  request->read_pos = 0;
1870  }
1871  if (maxlen == -1) maxlen = sizeof(request->read_buf);
1872 
1874 
1875  ret = netconn_recv( request->netconn, request->read_buf + request->read_size,
1876  maxlen - request->read_size, 0, &len );
1877 
1879 
1880  request->read_size += len;
1881  return ret;
1882 }
1883 
1884 /* discard data contents until we reach end of line */
1886 {
1887  do
1888  {
1889  char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size );
1890  if (eol)
1891  {
1892  remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) );
1893  break;
1894  }
1895  request->read_pos = request->read_size = 0; /* discard everything */
1896  if (!read_more_data( request, -1, notify )) return FALSE;
1897  } while (request->read_size);
1898  return TRUE;
1899 }
1900 
1901 /* read the size of the next chunk */
1903 {
1904  DWORD chunk_size = 0;
1905 
1906  assert(!request->read_chunked_size || request->read_chunked_size == ~0u);
1907 
1908  if (request->read_chunked_eof) return FALSE;
1909 
1910  /* read terminator for the previous chunk */
1911  if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE;
1912 
1913  for (;;)
1914  {
1915  while (request->read_size)
1916  {
1917  char ch = request->read_buf[request->read_pos];
1918  if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
1919  else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
1920  else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
1921  else if (ch == ';' || ch == '\r' || ch == '\n')
1922  {
1923  TRACE("reading %u byte chunk\n", chunk_size);
1924 
1925  if (request->content_length == ~0u) request->content_length = chunk_size;
1926  else request->content_length += chunk_size;
1927 
1928  request->read_chunked_size = chunk_size;
1929  if (!chunk_size) request->read_chunked_eof = TRUE;
1930 
1931  return discard_eol( request, notify );
1932  }
1933  remove_data( request, 1 );
1934  }
1935  if (!read_more_data( request, -1, notify )) return FALSE;
1936  if (!request->read_size)
1937  {
1938  request->content_length = request->content_read = 0;
1939  request->read_chunked_size = 0;
1940  return TRUE;
1941  }
1942  }
1943 }
1944 
1946 {
1947  int len = sizeof(request->read_buf);
1948 
1949  if (request->read_chunked)
1950  {
1951  if (request->read_chunked_eof) return FALSE;
1952  if (request->read_chunked_size == ~0u || !request->read_chunked_size)
1953  {
1954  if (!start_next_chunk( request, notify )) return FALSE;
1955  }
1956  len = min( len, request->read_chunked_size );
1957  }
1958  else if (request->content_length != ~0u)
1959  {
1960  len = min( len, request->content_length - request->content_read );
1961  }
1962 
1963  if (len <= request->read_size) return TRUE;
1964  if (!read_more_data( request, len, notify )) return FALSE;
1965  if (!request->read_size) request->content_length = request->content_read = 0;
1966  return TRUE;
1967 }
1968 
1970 {
1971  static const WCHAR closeW[] = {'c','l','o','s','e',0};
1972 
1973  BOOL close = FALSE;
1974  WCHAR connection[20];
1975  DWORD size = sizeof(connection);
1976 
1977  if (!request->netconn) return;
1978 
1979  if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE;
1980  else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) ||
1982  {
1983  if (!strcmpiW( connection, closeW )) close = TRUE;
1984  }
1985  else if (!strcmpW( request->version, http1_0 )) close = TRUE;
1986  if (close)
1987  {
1989  return;
1990  }
1991 
1992  cache_connection( request->netconn );
1993  request->netconn = NULL;
1994 }
1995 
1996 /* return the size of data available to be read immediately */
1998 {
1999  if (request->read_chunked) return min( request->read_chunked_size, request->read_size );
2000  return request->read_size;
2001 }
2002 
2003 /* check if we have reached the end of the data to read */
2005 {
2006  if (!request->content_length) return TRUE;
2007  if (request->read_chunked) return request->read_chunked_eof;
2008  if (request->content_length == ~0u) return FALSE;
2009  return (request->content_length == request->content_read);
2010 }
2011 
2013 {
2014  int count, bytes_read = 0;
2015 
2016  if (end_of_read_data( request )) goto done;
2017 
2018  while (size)
2019  {
2020  if (!(count = get_available_data( request )))
2021  {
2022  if (!refill_buffer( request, async )) goto done;
2023  if (!(count = get_available_data( request ))) goto done;
2024  }
2025  count = min( count, size );
2026  memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count );
2028  if (request->read_chunked) request->read_chunked_size -= count;
2029  size -= count;
2030  bytes_read += count;
2031  request->content_read += count;
2032  if (end_of_read_data( request )) goto done;
2033  }
2034  if (request->read_chunked && !request->read_chunked_size) refill_buffer( request, async );
2035 
2036 done:
2037  TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length );
2038 
2039  if (async) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read );
2040  if (read) *read = bytes_read;
2042  return TRUE;
2043 }
2044 
2045 /* read any content returned by the server so that the connection can be reused */
2047 {
2048  DWORD size, bytes_read, bytes_total = 0, bytes_left = request->content_length - request->content_read;
2049  char buffer[2048];
2050 
2052  for (;;)
2053  {
2054  if (request->read_chunked) size = sizeof(buffer);
2055  else
2056  {
2057  if (bytes_total >= bytes_left) return;
2058  size = min( sizeof(buffer), bytes_left - bytes_total );
2059  }
2060  if (!read_data( request, buffer, size, &bytes_read, FALSE ) || !bytes_read) return;
2061  bytes_total += bytes_read;
2062  }
2063 }
2064 
2066  DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
2067 {
2068  static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0};
2069  static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0};
2070  static const WCHAR length_fmt[] = {'%','l','d',0};
2071 
2072  BOOL ret = FALSE;
2073  connect_t *connect = request->connect;
2074  session_t *session = connect->session;
2075  WCHAR *req = NULL;
2076  char *req_ascii;
2077  int bytes_sent;
2078  DWORD len;
2079 
2082 
2083  if (session->agent)
2085 
2086  if (connect->hostname)
2088 
2089  if (request->creds[TARGET_SERVER][SCHEME_BASIC].username)
2091 
2092  if (total_len || (request->verb && !strcmpW( request->verb, postW )))
2093  {
2094  WCHAR length[21]; /* decimal long int + null */
2095  sprintfW( length, length_fmt, total_len );
2097  }
2098  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE))
2099  {
2101  }
2102  if (request->hdr.flags & WINHTTP_FLAG_REFRESH)
2103  {
2106  }
2108  {
2109  TRACE("failed to add request headers\n");
2110  return FALSE;
2111  }
2112  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request ))
2113  {
2114  WARN("failed to add cookie headers\n");
2115  return FALSE;
2116  }
2117 
2118  if (context) request->hdr.context = context;
2119 
2120  if (!(ret = open_connection( request ))) goto end;
2121  if (!(req = build_request_string( request ))) goto end;
2122 
2123  if (!(req_ascii = strdupWA( req ))) goto end;
2124  TRACE("full request: %s\n", debugstr_a(req_ascii));
2125  len = strlen(req_ascii);
2126 
2128 
2129  ret = netconn_send( request->netconn, req_ascii, len, &bytes_sent );
2130  heap_free( req_ascii );
2131  if (!ret) goto end;
2132 
2133  if (optional_len)
2134  {
2135  if (!netconn_send( request->netconn, optional, optional_len, &bytes_sent )) goto end;
2136  request->optional = optional;
2137  request->optional_len = optional_len;
2138  len += optional_len;
2139  }
2141 
2142 end:
2143  if (async)
2144  {
2146  else
2147  {
2149  result.dwResult = API_SEND_REQUEST;
2150  result.dwError = get_last_error();
2152  }
2153  }
2154  heap_free( req );
2155  return ret;
2156 }
2157 
2158 static void task_send_request( task_header_t *task )
2159 {
2160  send_request_t *s = (send_request_t *)task;
2161  send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE );
2162  heap_free( s->headers );
2163 }
2164 
2165 /***********************************************************************
2166  * WinHttpSendRequest (winhttp.@)
2167  */
2169  LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context )
2170 {
2171  BOOL ret;
2172  request_t *request;
2173 
2174  TRACE("%p, %s, %u, %u, %u, %lx\n", hrequest, debugstr_wn(headers, headers_len), headers_len, optional_len,
2175  total_len, context);
2176 
2177  if (!(request = (request_t *)grab_object( hrequest )))
2178  {
2180  return FALSE;
2181  }
2182  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2183  {
2184  release_object( &request->hdr );
2186  return FALSE;
2187  }
2188 
2189  if (headers && !headers_len) headers_len = strlenW( headers );
2190 
2191  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2192  {
2193  send_request_t *s;
2194 
2195  if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE;
2196  s->hdr.request = request;
2197  s->hdr.proc = task_send_request;
2198  s->headers = strdupW( headers );
2199  s->headers_len = headers_len;
2200  s->optional = optional;
2201  s->optional_len = optional_len;
2202  s->total_len = total_len;
2203  s->context = context;
2204 
2205  addref_object( &request->hdr );
2206  ret = queue_task( (task_header_t *)s );
2207  }
2208  else
2209  ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE );
2210 
2211  release_object( &request->hdr );
2213  return ret;
2214 }
2215 
2217  const WCHAR *password )
2218 {
2219  enum auth_scheme scheme = scheme_from_flag( scheme_flag );
2220 
2221  if (scheme == SCHEME_INVALID || ((scheme == SCHEME_BASIC || scheme == SCHEME_DIGEST) && (!username || !password)))
2222  {
2224  return FALSE;
2225  }
2226  switch (target)
2227  {
2229  {
2230  heap_free( request->creds[TARGET_SERVER][scheme].username );
2231  if (!username) request->creds[TARGET_SERVER][scheme].username = NULL;
2232  else if (!(request->creds[TARGET_SERVER][scheme].username = strdupW( username ))) return FALSE;
2233 
2234  heap_free( request->creds[TARGET_SERVER][scheme].password );
2235  if (!password) request->creds[TARGET_SERVER][scheme].password = NULL;
2236  else if (!(request->creds[TARGET_SERVER][scheme].password = strdupW( password ))) return FALSE;
2237  break;
2238  }
2240  {
2241  heap_free( request->creds[TARGET_PROXY][scheme].username );
2242  if (!username) request->creds[TARGET_PROXY][scheme].username = NULL;
2243  else if (!(request->creds[TARGET_PROXY][scheme].username = strdupW( username ))) return FALSE;
2244 
2245  heap_free( request->creds[TARGET_PROXY][scheme].password );
2246  if (!password) request->creds[TARGET_PROXY][scheme].password = NULL;
2247  else if (!(request->creds[TARGET_PROXY][scheme].password = strdupW( password ))) return FALSE;
2248  break;
2249  }
2250  default:
2251  WARN("unknown target %u\n", target);
2252  return FALSE;
2253  }
2254  return TRUE;
2255 }
2256 
2257 /***********************************************************************
2258  * WinHttpSetCredentials (winhttp.@)
2259  */
2262 {
2263  BOOL ret;
2264  request_t *request;
2265 
2266  TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params);
2267 
2268  if (!(request = (request_t *)grab_object( hrequest )))
2269  {
2271  return FALSE;
2272  }
2273  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2274  {
2275  release_object( &request->hdr );
2277  return FALSE;
2278  }
2279 
2281 
2282  release_object( &request->hdr );
2284  return ret;
2285 }
2286 
2288 {
2289  DWORD i, schemes, first, level, target;
2290 
2291  switch (status)
2292  {
2293  case HTTP_STATUS_DENIED:
2296  break;
2297 
2301  break;
2302 
2303  default:
2304  WARN("unhandled status %u\n", status);
2305  return FALSE;
2306  }
2307 
2308  if (!query_auth_schemes( request, level, &schemes, &first )) return FALSE;
2309  if (do_authorization( request, target, first )) return TRUE;
2310 
2311  schemes &= ~first;
2312  for (i = 0; i < num_auth_schemes; i++)
2313  {
2314  if (!(schemes & auth_schemes[i].scheme)) continue;
2316  }
2317  return FALSE;
2318 }
2319 
2320 /* set the request content length based on the headers */
2322 {
2323  WCHAR encoding[20];
2324  DWORD buflen = sizeof(request->content_length);
2325 
2327  request->content_length = 0;
2328  else
2329  {
2331  NULL, &request->content_length, &buflen, NULL ))
2332  request->content_length = ~0u;
2333 
2334  buflen = sizeof(encoding);
2336  !strcmpiW( encoding, chunkedW ))
2337  {
2338  request->content_length = ~0u;
2339  request->read_chunked = TRUE;
2340  request->read_chunked_size = ~0u;
2341  request->read_chunked_eof = FALSE;
2342  }
2343  }
2344  request->content_read = 0;
2345  return request->content_length;
2346 }
2347 
2349 {
2350  int count, bytes_read, pos = 0;
2351 
2352  for (;;)
2353  {
2354  char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size );
2355  if (eol)
2356  {
2357  count = eol - (request->read_buf + request->read_pos);
2358  bytes_read = count + 1;
2359  }
2360  else count = bytes_read = request->read_size;
2361 
2362  count = min( count, *len - pos );
2363  memcpy( buffer + pos, request->read_buf + request->read_pos, count );
2364  pos += count;
2365  remove_data( request, bytes_read );
2366  if (eol) break;
2367 
2368  if (!read_more_data( request, -1, TRUE )) return FALSE;
2369  if (!request->read_size)
2370  {
2371  *len = 0;
2372  TRACE("returning empty string\n");
2373  return FALSE;
2374  }
2375  }
2376  if (pos < *len)
2377  {
2378  if (pos && buffer[pos - 1] == '\r') pos--;
2379  *len = pos + 1;
2380  }
2381  buffer[*len - 1] = 0;
2382  TRACE("returning %s\n", debugstr_a(buffer));
2383  return TRUE;
2384 }
2385 
2386 #define MAX_REPLY_LEN 1460
2387 #define INITIAL_HEADER_BUFFER_LEN 512
2388 
2390 {
2391  static const WCHAR crlf[] = {'\r','\n',0};
2392 
2393  char buffer[MAX_REPLY_LEN];
2394  DWORD buflen, len, offset, crlf_len = 2; /* strlenW(crlf) */
2395  char *status_code, *status_text;
2396  WCHAR *versionW, *status_textW, *raw_headers;
2397  WCHAR status_codeW[4]; /* sizeof("nnn") */
2398 
2399  if (!request->netconn) return FALSE;
2400 
2401  do
2402  {
2403  buflen = MAX_REPLY_LEN;
2404  if (!read_line( request, buffer, &buflen )) return FALSE;
2405 
2406  /* first line should look like 'HTTP/1.x nnn OK' where nnn is the status code */
2407  if (!(status_code = strchr( buffer, ' ' ))) return FALSE;
2408  status_code++;
2409  if (!(status_text = strchr( status_code, ' ' ))) return FALSE;
2410  if ((len = status_text - status_code) != sizeof("nnn") - 1) return FALSE;
2411  status_text++;
2412 
2413  TRACE("version [%s] status code [%s] status text [%s]\n",
2416  debugstr_a(status_text));
2417 
2418  } while (!memcmp( status_code, "100", len )); /* ignore "100 Continue" responses */
2419 
2420  /* we rely on the fact that the protocol is ascii */
2421  MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len );
2422  status_codeW[len] = 0;
2423  if (!(process_header( request, attr_status, status_codeW,
2425  return FALSE;
2426 
2427  len = status_code - buffer;
2428  if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2429  MultiByteToWideChar( CP_ACP, 0, buffer, len - 1, versionW, len -1 );
2430  versionW[len - 1] = 0;
2431 
2432  heap_free( request->version );
2433  request->version = versionW;
2434 
2435  len = buflen - (status_text - buffer);
2436  if (!(status_textW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2437  MultiByteToWideChar( CP_ACP, 0, status_text, len, status_textW, len );
2438 
2439  heap_free( request->status_text );
2440  request->status_text = status_textW;
2441 
2442  len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN );
2443  if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2444  MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen );
2445  memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) );
2446 
2447  heap_free( request->raw_headers );
2448  request->raw_headers = raw_headers;
2449 
2450  offset = buflen + crlf_len - 1;
2451  for (;;)
2452  {
2453  header_t *header;
2454 
2455  buflen = MAX_REPLY_LEN;
2456  if (!read_line( request, buffer, &buflen )) return TRUE;
2457  if (!*buffer) buflen = 1;
2458 
2459  while (len - offset < buflen + crlf_len)
2460  {
2461  WCHAR *tmp;
2462  len *= 2;
2463  if (!(tmp = heap_realloc( raw_headers, len * sizeof(WCHAR) ))) return FALSE;
2464  request->raw_headers = raw_headers = tmp;
2465  }
2466  if (!*buffer)
2467  {
2468  memcpy( raw_headers + offset, crlf, sizeof(crlf) );
2469  break;
2470  }
2471  MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen );
2472 
2473  if (!(header = parse_header( raw_headers + offset ))) break;
2474  if (!(process_header( request, header->field, header->value, WINHTTP_ADDREQ_FLAG_ADD, FALSE )))
2475  {
2476  free_header( header );
2477  break;
2478  }
2479  free_header( header );
2480  memcpy( raw_headers + offset + buflen - 1, crlf, sizeof(crlf) );
2481  offset += buflen + crlf_len - 1;
2482  }
2483 
2484  TRACE("raw headers: %s\n", debugstr_w(raw_headers));
2485  return TRUE;
2486 }
2487 
2489 {
2490  unsigned int i;
2491 
2492  for (i = 0; i < request->num_headers; i++)
2493  {
2494  header_t *set_cookie = &request->headers[i];
2495  if (!strcmpiW( set_cookie->field, attr_set_cookie ) && !set_cookie->is_request)
2496  {
2497  set_cookies( request, set_cookie->value );
2498  }
2499  }
2500 }
2501 
2503 {
2504  DWORD size;
2505  WCHAR *ret;
2506 
2509  if (!(ret = heap_alloc( size ))) return NULL;
2510  *len = size / sizeof(WCHAR);
2512  heap_free( ret );
2513  return NULL;
2514 }
2515 
2517 {
2518  BOOL ret = FALSE;
2519  DWORD len, len_url;
2520  URL_COMPONENTS uc;
2521  connect_t *connect = request->connect;
2523  WCHAR *hostname = NULL, *location;
2524  int index;
2525 
2526  if (!(location = get_redirect_url( request, &len_url ))) return FALSE;
2527 
2528  memset( &uc, 0, sizeof(uc) );
2529  uc.dwStructSize = sizeof(uc);
2531 
2532  if (!WinHttpCrackUrl( location, len_url, 0, &uc )) /* assume relative redirect */
2533  {
2534  WCHAR *path, *p;
2535 
2536  if (location[0] == '/')
2537  {
2538  len = strlenW( location );
2539  if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2540  strcpyW( path, location );
2541  }
2542  else
2543  {
2544  if ((p = strrchrW( request->path, '/' ))) *p = 0;
2545  len = strlenW( request->path ) + 1 + strlenW( location );
2546  if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2547  strcpyW( path, request->path );
2548  strcatW( path, slashW );
2549  strcatW( path, location );
2550  }
2551  heap_free( request->path );
2552  request->path = path;
2553 
2555  }
2556  else
2557  {
2558  if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE)
2559  {
2560  if (request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP) goto end;
2561  TRACE("redirect from secure page to non-secure page\n");
2562  request->hdr.flags &= ~WINHTTP_FLAG_SECURE;
2563  }
2564  else if (uc.nScheme == INTERNET_SCHEME_HTTPS && !(request->hdr.flags & WINHTTP_FLAG_SECURE))
2565  {
2566  TRACE("redirect from non-secure page to secure page\n");
2567  request->hdr.flags |= WINHTTP_FLAG_SECURE;
2568  }
2569 
2571 
2572  len = uc.dwHostNameLength;
2573  if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2574  memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) );
2575  hostname[len] = 0;
2576 
2577  port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80);
2578  if (strcmpiW( connect->hostname, hostname ) || connect->serverport != port)
2579  {
2580  heap_free( connect->hostname );
2581  connect->hostname = hostname;
2582  connect->hostport = port;
2583  if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end;
2584 
2585  netconn_close( request->netconn );
2586  request->netconn = NULL;
2587  request->content_length = request->content_read = 0;
2588  request->read_pos = request->read_size = 0;
2589  request->read_chunked = request->read_chunked_eof = FALSE;
2590  }
2591  else heap_free( hostname );
2592 
2594  if (!(ret = open_connection( request ))) goto end;
2595 
2596  heap_free( request->path );
2597  request->path = NULL;
2598  if (uc.dwUrlPathLength)
2599  {
2601  if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
2602  strcpyW( request->path, uc.lpszUrlPath );
2603  }
2604  else request->path = strdupW( slashW );
2605  }
2606 
2607  /* remove content-type/length headers */
2610 
2612  {
2613  heap_free( request->verb );
2614  request->verb = strdupW( getW );
2615  request->optional = NULL;
2616  request->optional_len = 0;
2617  }
2618  ret = TRUE;
2619 
2620 end:
2621  heap_free( location );
2622  return ret;
2623 }
2624 
2626 {
2627  BOOL ret;
2628  DWORD size, query, status;
2629 
2630  for (;;)
2631  {
2632  if (!(ret = read_reply( request )))
2633  {
2635  break;
2636  }
2637  size = sizeof(DWORD);
2639  if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break;
2640 
2642 
2643  if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request );
2644 
2646  {
2647  if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS ||
2648  request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break;
2649 
2650  if (!(ret = handle_redirect( request, status ))) break;
2651 
2652  /* recurse synchronously */
2653  if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue;
2654  }
2656  {
2657  if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break;
2658 
2659  if (!handle_authorization( request, status )) break;
2660 
2661  /* recurse synchronously */
2662  if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue;
2663  }
2664  break;
2665  }
2666 
2667  if (request->content_length) refill_buffer( request, FALSE );
2668 
2669  if (async)
2670  {
2672  else
2673  {
2675  result.dwResult = API_RECEIVE_RESPONSE;
2676  result.dwError = get_last_error();
2678  }
2679  }
2680  return ret;
2681 }
2682 
2684 {
2686  receive_response( r->hdr.request, TRUE );
2687 }
2688 
2689 /***********************************************************************
2690  * WinHttpReceiveResponse (winhttp.@)
2691  */
2693 {
2694  BOOL ret;
2695  request_t *request;
2696 
2697  TRACE("%p, %p\n", hrequest, reserved);
2698 
2699  if (!(request = (request_t *)grab_object( hrequest )))
2700  {
2702  return FALSE;
2703  }
2704  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2705  {
2706  release_object( &request->hdr );
2708  return FALSE;
2709  }
2710 
2711  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2712  {
2714 
2715  if (!(r = heap_alloc( sizeof(receive_response_t) ))) return FALSE;
2716  r->hdr.request = request;
2717  r->hdr.proc = task_receive_response;
2718 
2719  addref_object( &request->hdr );
2720  ret = queue_task( (task_header_t *)r );
2721  }
2722  else
2724 
2725  release_object( &request->hdr );
2727  return ret;
2728 }
2729 
2731 {
2732  DWORD count = 0;
2733 
2734  if (end_of_read_data( request )) goto done;
2735 
2737  if (!request->read_chunked && request->netconn)
2739  if (!count)
2740  {
2741  refill_buffer( request, async );
2743  if (!request->read_chunked && request->netconn)
2745  }
2746 
2747 done:
2749  TRACE("%u bytes available\n", count);
2750  if (available) *available = count;
2751  return TRUE;
2752 }
2753 
2755 {
2756  query_data_t *q = (query_data_t *)task;
2757  query_data_available( q->hdr.request, q->available, TRUE );
2758 }
2759 
2760 /***********************************************************************
2761  * WinHttpQueryDataAvailable (winhttp.@)
2762  */
2764 {
2765  BOOL ret;
2766  request_t *request;
2767 
2768  TRACE("%p, %p\n", hrequest, available);
2769 
2770  if (!(request = (request_t *)grab_object( hrequest )))
2771  {
2773  return FALSE;
2774  }
2775  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2776  {
2777  release_object( &request->hdr );
2779  return FALSE;
2780  }
2781 
2782  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2783  {
2784  query_data_t *q;
2785 
2786  if (!(q = heap_alloc( sizeof(query_data_t) ))) return FALSE;
2787  q->hdr.request = request;
2788  q->hdr.proc = task_query_data_available;
2789  q->available = available;
2790 
2791  addref_object( &request->hdr );
2792  ret = queue_task( (task_header_t *)q );
2793  }
2794  else
2796 
2797  release_object( &request->hdr );
2799  return ret;
2800 }
2801 
2802 static void task_read_data( task_header_t *task )
2803 {
2804  read_data_t *r = (read_data_t *)task;
2805  read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE );
2806 }
2807 
2808 /***********************************************************************
2809  * WinHttpReadData (winhttp.@)
2810  */
2812 {
2813  BOOL ret;
2814  request_t *request;
2815 
2816  TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read);
2817 
2818  if (!(request = (request_t *)grab_object( hrequest )))
2819  {
2821  return FALSE;
2822  }
2823  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2824  {
2825  release_object( &request->hdr );
2827  return FALSE;
2828  }
2829 
2830  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2831  {
2832  read_data_t *r;
2833 
2834  if (!(r = heap_alloc( sizeof(read_data_t) ))) return FALSE;
2835  r->hdr.request = request;
2836  r->hdr.proc = task_read_data;
2837  r->buffer = buffer;
2838  r->to_read = to_read;
2839  r->read = read;
2840 
2841  addref_object( &request->hdr );
2842  ret = queue_task( (task_header_t *)r );
2843  }
2844  else
2846 
2847  release_object( &request->hdr );
2849  return ret;
2850 }
2851 
2852 static BOOL write_data( request_t *request, LPCVOID buffer, DWORD to_write, LPDWORD written, BOOL async )
2853 {
2854  BOOL ret;
2855  int num_bytes;
2856 
2857  ret = netconn_send( request->netconn, buffer, to_write, &num_bytes );
2858 
2859  if (async)
2860  {
2862  else
2863  {
2865  result.dwResult = API_WRITE_DATA;
2866  result.dwError = get_last_error();
2868  }
2869  }
2870  if (ret && written) *written = num_bytes;
2871  return ret;
2872 }
2873 
2874 static void task_write_data( task_header_t *task )
2875 {
2876  write_data_t *w = (write_data_t *)task;
2877  write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE );
2878 }
2879 
2880 /***********************************************************************
2881  * WinHttpWriteData (winhttp.@)
2882  */
2884 {
2885  BOOL ret;
2886  request_t *request;
2887 
2888  TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_write, written);
2889 
2890  if (!(request = (request_t *)grab_object( hrequest )))
2891  {
2893  return FALSE;
2894  }
2895  if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
2896  {
2897  release_object( &request->hdr );
2899  return FALSE;
2900  }
2901 
2902  if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
2903  {
2904  write_data_t *w;
2905 
2906  if (!(w = heap_alloc( sizeof(write_data_t) ))) return FALSE;
2907  w->hdr.request = request;
2908  w->hdr.proc = task_write_data;
2909  w->buffer = buffer;
2910  w->to_write = to_write;
2911  w->written = written;
2912 
2913  addref_object( &request->hdr );
2914  ret = queue_task( (task_header_t *)w );
2915  }
2916  else
2917  ret = write_data( request, buffer, to_write, written, FALSE );
2918 
2919  release_object( &request->hdr );
2921  return ret;
2922 }
2923 
2925 {
2932 };
2933 
2935 {
2936  IWinHttpRequest IWinHttpRequest_iface;
2948  char *buffer;
2962 };
2963 
2964 static inline struct winhttp_request *impl_from_IWinHttpRequest( IWinHttpRequest *iface )
2965 {
2966  return CONTAINING_RECORD( iface, struct winhttp_request, IWinHttpRequest_iface );
2967 }
2968 
2970  IWinHttpRequest *iface )
2971 {
2973  return InterlockedIncrement( &request->refs );
2974 }
2975 
2976 /* critical section must be held */
2978 {
2979  if (request->state <= REQUEST_STATE_CANCELLED) return;
2980 
2981  SetEvent( request->cancel );
2982  LeaveCriticalSection( &request->cs );
2983  WaitForSingleObject( request->thread, INFINITE );
2984  EnterCriticalSection( &request->cs );
2985 
2987 
2988  CloseHandle( request->thread );
2989  request->thread = NULL;
2990  CloseHandle( request->wait );
2991  request->wait = NULL;
2992  CloseHandle( request->cancel );
2993  request->cancel = NULL;
2994 }
2995 
2996 /* critical section must be held */
2997 static void free_request( struct winhttp_request *request )
2998 {
2999  if (request->state < REQUEST_STATE_INITIALIZED) return;
3000  WinHttpCloseHandle( request->hrequest );
3001  WinHttpCloseHandle( request->hconnect );
3002  WinHttpCloseHandle( request->hsession );
3003  CloseHandle( request->thread );
3004  CloseHandle( request->wait );
3005  CloseHandle( request->cancel );
3006  heap_free( (WCHAR *)request->proxy.lpszProxy );
3007  heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
3008  heap_free( request->buffer );
3009  heap_free( request->verb );
3010  VariantClear( &request->data );
3011 }
3012 
3014  IWinHttpRequest *iface )
3015 {
3017  LONG refs = InterlockedDecrement( &request->refs );
3018  if (!refs)
3019  {
3020  TRACE("destroying %p\n", request);
3021 
3022  EnterCriticalSection( &request->cs );
3024  free_request( request );
3025  LeaveCriticalSection( &request->cs );
3026  request->cs.DebugInfo->Spare[0] = 0;
3028  heap_free( request );
3029  }
3030  return refs;
3031 }
3032 
3034  IWinHttpRequest *iface,
3035  REFIID riid,
3036  void **obj )
3037 {
3039 
3040  TRACE("%p, %s, %p\n", request, debugstr_guid(riid), obj );
3041 
3042  if (IsEqualGUID( riid, &IID_IWinHttpRequest ) ||
3045  {
3046  *obj = iface;
3047  }
3048  else
3049  {
3050  FIXME("interface %s not implemented\n", debugstr_guid(riid));
3051  return E_NOINTERFACE;
3052  }
3053  IWinHttpRequest_AddRef( iface );
3054  return S_OK;
3055 }
3056 
3058  IWinHttpRequest *iface,
3059  UINT *count )
3060 {
3062 
3063  TRACE("%p, %p\n", request, count);
3064  *count = 1;
3065  return S_OK;
3066 }
3067 
3069 {
3072 };
3073 
3076 
3078 {
3079  &IID_IWinHttpRequest
3080 };
3081 
3083 {
3084  HRESULT hr;
3085 
3086  if (!winhttp_typelib)
3087  {
3088  ITypeLib *typelib;
3089 
3090  hr = LoadRegTypeLib( &LIBID_WinHttp, 5, 1, LOCALE_SYSTEM_DEFAULT, &typelib );
3091  if (FAILED(hr))
3092  {
3093  ERR("LoadRegTypeLib failed: %08x\n", hr);
3094  return hr;
3095  }
3097  ITypeLib_Release( typelib );
3098  }
3099  if (!winhttp_typeinfo[tid])
3100  {
3102 
3103  hr = ITypeLib_GetTypeInfoOfGuid( winhttp_typelib, winhttp_tid_id[tid], &typeinfo );
3104  if (FAILED(hr))
3105  {
3106  ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(winhttp_tid_id[tid]), hr);
3107  return hr;
3108  }
3110  ITypeInfo_Release( typeinfo );
3111  }
3112  *ret = winhttp_typeinfo[tid];
3113  ITypeInfo_AddRef(winhttp_typeinfo[tid]);
3114  return S_OK;
3115 }
3116 
3118 {
3119  unsigned i;
3120 
3121  for (i = 0; i < sizeof(winhttp_typeinfo)/sizeof(*winhttp_typeinfo); i++)
3122  if (winhttp_typeinfo[i])
3123  ITypeInfo_Release(winhttp_typeinfo[i]);
3124 
3125  if (winhttp_typelib)
3126  ITypeLib_Release(winhttp_typelib);
3127 }
3128 
3130  IWinHttpRequest *iface,
3131  UINT index,
3132  LCID lcid,
3133  ITypeInfo **info )
3134 {
3136  TRACE("%p, %u, %u, %p\n", request, index, lcid, info);
3137 
3139 }
3140 
3142  IWinHttpRequest *iface,
3143  REFIID riid,
3144  LPOLESTR *names,
3145  UINT count,
3146  LCID lcid,
3147  DISPID *dispid )
3148 {
3151  HRESULT hr;
3152 
3153  TRACE("%p, %s, %p, %u, %u, %p\n", request, debugstr_guid(riid), names, count, lcid, dispid);
3154 
3155  if (!names || !count || !dispid) return E_INVALIDARG;
3156 
3158  if (SUCCEEDED(hr))
3159  {
3160  hr = ITypeInfo_GetIDsOfNames( typeinfo, names, count, dispid );
3161  ITypeInfo_Release( typeinfo );
3162  }
3163  return hr;
3164 }
3165 
3167  IWinHttpRequest *iface,
3168  DISPID member,
3169  REFIID riid,
3170  LCID lcid,
3171  WORD flags,
3172  DISPPARAMS *params,
3173  VARIANT *result,
3174  EXCEPINFO *excep_info,
3175  UINT *arg_err )
3176 {
3179  HRESULT hr;
3180 
3181  TRACE("%p, %d, %s, %d, %d, %p, %p, %p, %p\n", request, member, debugstr_guid(riid),
3182  lcid, flags, params, result, excep_info, arg_err);
3183 
3184  if (!IsEqualIID( riid, &IID_NULL )) return DISP_E_UNKNOWNINTERFACE;
3185 
3187  {
3188  VARIANT ret_value, option;
3189  UINT err_pos;
3190 
3191  if (!result) result = &ret_value;
3192  if (!arg_err) arg_err = &err_pos;
3193 
3194  VariantInit( &option );
3195  VariantInit( result );
3196 
3197  if (!flags) return S_OK;
3198 
3199  if (flags == DISPATCH_PROPERTYPUT)
3200  {
3201  hr = DispGetParam( params, 0, VT_I4, &option, arg_err );
3202  if (FAILED(hr)) return hr;
3203 
3204  hr = IWinHttpRequest_put_Option( &request->IWinHttpRequest_iface, V_I4( &option ), params->rgvarg[0] );
3205  if (FAILED(hr))
3206  WARN("put_Option(%d) failed: %x\n", V_I4( &option ), hr);
3207  return hr;
3208  }
3210  {
3211  hr = DispGetParam( params, 0, VT_I4, &option, arg_err );
3212  if (FAILED(hr)) return hr;
3213 
3214  hr = IWinHttpRequest_get_Option( &request->IWinHttpRequest_iface, V_I4( &option ), result );
3215  if (FAILED(hr))
3216  WARN("get_Option(%d) failed: %x\n", V_I4( &option ), hr);
3217  return hr;
3218  }
3219 
3220  FIXME("unsupported flags %x\n", flags);
3221  return E_NOTIMPL;
3222  }
3223 
3224  /* fallback to standard implementation */
3225 
3227  if (SUCCEEDED(hr))
3228  {
3229  hr = ITypeInfo_Invoke( typeinfo, &request->IWinHttpRequest_iface, member, flags,
3230  params, result, excep_info, arg_err );
3231  ITypeInfo_Release( typeinfo );
3232  }
3233  return hr;
3234 }
3235 
3237  IWinHttpRequest *iface,
3238  HTTPREQUEST_PROXY_SETTING proxy_setting,
3240  VARIANT bypass_list )
3241 {
3244 
3245  TRACE("%p, %u, %s, %s\n", request, proxy_setting, debugstr_variant(&proxy_server),
3246  debugstr_variant(&bypass_list));
3247 
3248  EnterCriticalSection( &request->cs );
3249  switch (proxy_setting)
3250  {
3252  request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
3253  heap_free( (WCHAR *)request->proxy.lpszProxy );
3254  heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
3255  request->proxy.lpszProxy = NULL;
3256  request->proxy.lpszProxyBypass = NULL;
3257  break;
3258 
3260  request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
3261  heap_free( (WCHAR *)request->proxy.lpszProxy );
3262  heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
3263  request->proxy.lpszProxy = NULL;
3264  request->proxy.lpszProxyBypass = NULL;
3265  break;
3266 
3268  request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
3269  if (V_VT( &proxy_server ) == VT_BSTR)
3270  {
3271  heap_free( (WCHAR *)request->proxy.lpszProxy );
3272  request->proxy.lpszProxy = strdupW( V_BSTR( &proxy_server ) );
3273  }
3274  if (V_VT( &bypass_list ) == VT_BSTR)
3275  {
3276  heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
3277  request->proxy.lpszProxyBypass = strdupW( V_BSTR( &bypass_list ) );
3278  }
3279  break;
3280 
3281  default:
3283  break;
3284  }
3285  LeaveCriticalSection( &request->cs );
3286  return HRESULT_FROM_WIN32( err );
3287 }
3288 
3290  IWinHttpRequest *iface,
3291  BSTR username,
3292  BSTR password,
3294 {
3296  DWORD target, scheme = WINHTTP_AUTH_SCHEME_BASIC; /* FIXME: query supported schemes */
3298 
3299  TRACE("%p, %s, %p, 0x%08x\n", request, debugstr_w(username), password, flags);
3300 
3301  EnterCriticalSection( &request->cs );
3302  if (request->state < REQUEST_STATE_OPEN)
3303  {
3305  goto done;
3306  }
3307  switch (flags)
3308  {
3311  break;
3314  break;
3315  default:
3317  goto done;
3318  }
3320  {
3321  err = get_last_error();
3322  }
3323 done:
3324  LeaveCriticalSection( &request->cs );
3325  return HRESULT_FROM_WIN32( err );
3326 }
3327 
3329 {
3330  request->hrequest = NULL;
3331  request->hconnect = NULL;
3332  request->hsession = NULL;
3333  request->thread = NULL;
3334  request->wait = NULL;
3335  request->cancel = NULL;
3336  request->buffer = NULL;
3337  request->verb = NULL;
3338  request->offset = 0;
3339  request->bytes_available = 0;
3340  request->bytes_read = 0;
3341  request->error = ERROR_SUCCESS;
3342  request->async = FALSE;
3344  request->disable_feature = 0;
3345  request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
3346  request->proxy.lpszProxy = NULL;
3347  request->proxy.lpszProxyBypass = NULL;
3348  request->resolve_timeout = 0;
3349  request->connect_timeout = 60000;
3350  request->send_timeout = 30000;
3351  request->receive_timeout = 30000;
3352  request->url_codepage = CP_UTF8;
3353  VariantInit( &request->data );
3355 }
3356 
3357 static void reset_request( struct winhttp_request *request )
3358 {
3360  WinHttpCloseHandle( request->hrequest );
3361  request->hrequest = NULL;
3362  WinHttpCloseHandle( request->hconnect );
3363  request->hconnect = NULL;
3364  heap_free( request->buffer );
3365  request->buffer = NULL;
3366  heap_free( request->verb );
3367  request->verb = NULL;
3368  request->offset = 0;
3369  request->bytes_available = 0;
3370  request->bytes_read = 0;
3371  request->error = ERROR_SUCCESS;
3372  request->async = FALSE;
3373  request->url_codepage = CP_UTF8;
3374  VariantClear( &request->data );
3376 }
3377 
3379  IWinHttpRequest *iface,
3380  BSTR method,
3381  BSTR url,
3382  VARIANT async )
3383 {
3384  static const WCHAR typeW[] = {'*','/','*',0};
3385  static const WCHAR *acceptW[] = {typeW, NULL};
3386  static const WCHAR httpsW[] = {'h','t','t','p','s'};
3387  static const WCHAR user_agentW[] = {
3388  'M','o','z','i','l','l','a','/','4','.','0',' ','(','c','o','m','p','a','t','i','b','l','e',';',' ',
3389  'W','i','n','3','2',';',' ','W','i','n','H','t','t','p','.','W','i','n','H','t','t','p',
3390  'R','e','q','u','e','s','t','.','5',')',0};
3392  URL_COMPONENTS uc;
3393  WCHAR *hostname, *path = NULL, *verb = NULL;
3395 
3396  TRACE("%p, %s, %s, %s\n", request, debugstr_w(method), debugstr_w(url),
3398 
3399  if (!method || !url) return E_INVALIDARG;
3400 
3401  memset( &uc, 0, sizeof(uc) );
3402  uc.dwStructSize = sizeof(uc);
3403  uc.dwSchemeLength = ~0u;
3404  uc.dwHostNameLength = ~0u;
3405  uc.dwUrlPathLength = ~0u;
3406  uc.dwExtraInfoLength = ~0u;
3407  if (!WinHttpCrackUrl( url, 0, 0, &uc )) return HRESULT_FROM_WIN32( get_last_error() );
3408 
3409  EnterCriticalSection( &request->cs );
3411  else reset_request( request );
3412 
3413  if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) goto error;
3414  memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
3415  hostname[uc.dwHostNameLength] = 0;
3416 
3417  if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) ))) goto error;
3418  memcpy( path, uc.lpszUrlPath, (uc.dwUrlPathLength + uc.dwExtraInfoLength) * sizeof(WCHAR) );
3419  path[uc.dwUrlPathLength + uc.dwExtraInfoLength] = 0;
3420 
3421  if (!(verb = strdupW( method ))) goto error;
3422  if (SUCCEEDED( VariantChangeType( &async, &async, 0, VT_BOOL )) && V_BOOL( &async )) request->async = TRUE;
3423  else request->async = FALSE;
3424 
3425  if (!request->hsession)
3426  {
3428  WINHTTP_FLAG_ASYNC )))
3429  {
3430  err = get_last_error();
3431  goto error;
3432  }
3433  if (!(request->hconnect = WinHttpConnect( request->hsession, hostname, uc.nPort, 0 )))
3434  {
3435  WinHttpCloseHandle( request->hsession );
3436  request->hsession = NULL;
3437  err = get_last_error();
3438  goto error;
3439  }
3440  }
3441  else if (!(request->hconnect = WinHttpConnect( request->hsession, hostname, uc.nPort, 0 )))
3442  {
3443  err = get_last_error();
3444  goto error;
3445  }
3446 
3447  len = sizeof(httpsW) / sizeof(WCHAR);
3448  if (uc.dwSchemeLength == len && !memcmp( uc.lpszScheme, httpsW, len * sizeof(WCHAR) ))
3449  {
3451  }
3452  if (!(request->hrequest = WinHttpOpenRequest( request->hconnect, method, path, NULL, NULL, acceptW, flags )))
3453  {
3454  err = get_last_error();
3455  goto error;
3456  }
3458 
3459  request->state = REQUEST_STATE_OPEN;
3460  request->verb = verb;
3461  heap_free( hostname );
3462  heap_free( path );
3463  LeaveCriticalSection( &request->cs );
3464  return S_OK;
3465 
3466 error:
3467  WinHttpCloseHandle( request->hconnect );
3468  request->hconnect = NULL;
3469  heap_free( hostname );
3470  heap_free( path );
3471  heap_free( verb );
3472  LeaveCriticalSection( &request->cs );
3473  return HRESULT_FROM_WIN32( err );
3474 }
3475 
3477  IWinHttpRequest *iface,
3478  BSTR header,
3479  BSTR value )
3480 {
3481  static const WCHAR fmtW[] = {'%','s',':',' ','%','s','\r','\n',0};
3482  static const WCHAR emptyW[] = {0};
3485  WCHAR *str;
3486 
3487  TRACE("%p, %s, %s\n", request, debugstr_w(header), debugstr_w(value));
3488 
3489  if (!header) return E_INVALIDARG;
3490 
3491  EnterCriticalSection( &request->cs );
3492  if (request->state < REQUEST_STATE_OPEN)
3493  {
3495  goto done;
3496  }
3497  if (request->state >= REQUEST_STATE_SENT)
3498  {
3500  goto done;
3501  }
3502  len = strlenW( header ) + 4;
3503  if (value) len += strlenW( value );
3504  if (!(str = heap_alloc( (len + 1) * sizeof(WCHAR) )))
3505  {
3507  goto done;
3508  }
3509  sprintfW( str, fmtW, header, value ? value : emptyW );
3510  if (!WinHttpAddRequestHeaders( request->hrequest, str, len,
3512  {
3513  err = get_last_error();
3514  }
3515  heap_free( str );
3516 
3517 done:
3518  LeaveCriticalSection( &request->cs );
3519  return HRESULT_FROM_WIN32( err );
3520 }
3521 
3523  IWinHttpRequest *iface,
3524  BSTR header,
3525  BSTR *value )
3526 {
3529 
3530  TRACE("%p, %p\n", request, header);
3531 
3532  EnterCriticalSection( &request->cs );
3533  if (request->state < REQUEST_STATE_SENT)
3534  {
3536  goto done;
3537  }
3538  if (!header || !value)
3539  {
3541  goto done;
3542  }
3543  size = 0;
3545  {
3546  err = get_last_error();
3547  if (err != ERROR_INSUFFICIENT_BUFFER) goto done;
3548  }
3549  if (!(*value = SysAllocStringLen( NULL, size / sizeof(WCHAR) )))
3550  {
3552  goto done;
3553  }
3554  err = ERROR_SUCCESS;
3556  {
3557  err = get_last_error();
3558  SysFreeString( *value );
3559  }
3560 done:
3561  LeaveCriticalSection( &request->cs );
3562  return HRESULT_FROM_WIN32( err );
3563 }
3564 
3566  IWinHttpRequest *iface,
3567  BSTR *headers )
3568 {
3571 
3572  TRACE("%p, %p\n", request, headers);
3573 
3574  if (!headers) return E_INVALIDARG;
3575 
3576  EnterCriticalSection( &request->cs );
3577  if (request->state < REQUEST_STATE_SENT)
3578  {
3580  goto done;
3581  }
3582  size = 0;
3584  {
3585  err = get_last_error();
3586  if (err != ERROR_INSUFFICIENT_BUFFER) goto done;
3587  }
3588  if (!(*headers = SysAllocStringLen( NULL, size / sizeof(WCHAR) )))
3589  {
3591  goto done;
3592  }
3593  err = ERROR_SUCCESS;
3595  {
3596  err = get_last_error();
3597  SysFreeString( *headers );
3598  }
3599 done:
3600  LeaveCriticalSection( &request->cs );
3601  return HRESULT_FROM_WIN32( err );
3602 }
3603 
3605 {
3606  struct winhttp_request *request = (struct winhttp_request *)context;
3607 
3608  switch (status)
3609  {
3611  request->bytes_available = *(DWORD *)buffer;
3612  request->error = ERROR_SUCCESS;
3613  break;
3615  request->bytes_read = size;
3616  request->error = ERROR_SUCCESS;
3617  break;
3619  {
3621  request->error = result->dwError;
3622  break;
3623  }
3624  default: break;
3625  }
3626  SetEvent( request->wait );
3627 }
3628 
3630 {
3633 }
3634 
3636 {
3637  HANDLE handles[2] = { request->wait, request->cancel };
3638 
3639  switch (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ))
3640  {
3641  case WAIT_OBJECT_0:
3642  break;
3643  case WAIT_OBJECT_0 + 1:
3644  request->error = ERROR_CANCELLED;
3645  break;
3646  default:
3647  request->error = get_last_error();
3648  break;
3649  }
3650  return request->error;
3651 }
3652 
3654 {
3655  DWORD err, size, buflen = 4096;
3656 
3658  if (!WinHttpReceiveResponse( request->hrequest, NULL ))
3659  {
3660  return HRESULT_FROM_WIN32( get_last_error() );
3661  }
3662  if ((err = wait_for_completion( request ))) return HRESULT_FROM_WIN32( err );
3663  if (!strcmpW( request->verb, headW ))
3664  {
3666  return S_OK;
3667  }
3668  if (!(request->buffer = heap_alloc( buflen ))) return E_OUTOFMEMORY;
3669  request->buffer[0] = 0;
3670  size = 0;
3671  do
3672  {
3674  if (!WinHttpQueryDataAvailable( request->hrequest, &request->bytes_available ))
3675  {
3676  err = get_last_error();
3677  goto error;
3678  }
3679  if ((err = wait_for_completion( request ))) goto error;
3680  if (!request->bytes_available) break;
3681  size += request->bytes_available;
3682  if (buflen < size)
3683  {
3684  char *tmp;
3685  while (buflen < size) buflen *= 2;
3686  if (!(tmp = heap_realloc( request->buffer, buflen )))
3687  {
3689  goto error;
3690  }
3691  request->buffer = tmp;
3692  }
3694  if (!WinHttpReadData( request->hrequest, request->buffer + request->offset,
3695  request->bytes_available, &request->bytes_read ))
3696  {
3697  err = get_last_error();
3698  goto error;
3699  }
3700  if ((err = wait_for_completion( request ))) goto error;
3701  request->offset += request->bytes_read;
3702  } while (request->bytes_read);
3703 
3705  return S_OK;
3706 
3707 error:
3708  heap_free( request->buffer );
3709  request->buffer = NULL;
3710  return HRESULT_FROM_WIN32( err );
3711 }
3712 
3714 {
3715  if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_PROXY, &request->proxy,
3716  sizeof(request->proxy) )) return get_last_error();
3717 
3718  if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_AUTOLOGON_POLICY, &request->logon_policy,
3719  sizeof(request->logon_policy) )) return get_last_error();
3720 
3721  if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_DISABLE_FEATURE, &request->disable_feature,
3722  sizeof(request->disable_feature) )) return get_last_error();
3723 
3724  if (!WinHttpSetTimeouts( request->hrequest,
3725  request->resolve_timeout,
<