Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrequest.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2004 Mike McCormack for CodeWeavers 00003 * Copyright 2006 Rob Shearman for CodeWeavers 00004 * Copyright 2008 Hans Leidekker for CodeWeavers 00005 * Copyright 2009 Juan Lang 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include "config.h" 00023 #include "wine/port.h" 00024 #include "wine/debug.h" 00025 00026 #include <stdarg.h> 00027 #ifdef HAVE_ARPA_INET_H 00028 # include <arpa/inet.h> 00029 #endif 00030 00031 #include "windef.h" 00032 #include "winbase.h" 00033 #include "winhttp.h" 00034 00035 #include "winhttp_private.h" 00036 00037 #include "inet_ntop.c" 00038 00039 WINE_DEFAULT_DEBUG_CHANNEL(winhttp); 00040 00041 static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0}; 00042 static const WCHAR attr_accept_charset[] = {'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0}; 00043 static const WCHAR attr_accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; 00044 static const WCHAR attr_accept_language[] = {'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0}; 00045 static const WCHAR attr_accept_ranges[] = {'A','c','c','e','p','t','-','R','a','n','g','e','s',0}; 00046 static const WCHAR attr_age[] = {'A','g','e',0}; 00047 static const WCHAR attr_allow[] = {'A','l','l','o','w',0}; 00048 static const WCHAR attr_authorization[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',0}; 00049 static const WCHAR attr_cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',0}; 00050 static const WCHAR attr_connection[] = {'C','o','n','n','e','c','t','i','o','n',0}; 00051 static const WCHAR attr_content_base[] = {'C','o','n','t','e','n','t','-','B','a','s','e',0}; 00052 static const WCHAR attr_content_encoding[] = {'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0}; 00053 static const WCHAR attr_content_id[] = {'C','o','n','t','e','n','t','-','I','D',0}; 00054 static const WCHAR attr_content_language[] = {'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0}; 00055 static const WCHAR attr_content_length[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; 00056 static const WCHAR attr_content_location[] = {'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0}; 00057 static const WCHAR attr_content_md5[] = {'C','o','n','t','e','n','t','-','M','D','5',0}; 00058 static const WCHAR attr_content_range[] = {'C','o','n','t','e','n','t','-','R','a','n','g','e',0}; 00059 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}; 00060 static const WCHAR attr_content_type[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; 00061 static const WCHAR attr_cookie[] = {'C','o','o','k','i','e',0}; 00062 static const WCHAR attr_date[] = {'D','a','t','e',0}; 00063 static const WCHAR attr_from[] = {'F','r','o','m',0}; 00064 static const WCHAR attr_etag[] = {'E','T','a','g',0}; 00065 static const WCHAR attr_expect[] = {'E','x','p','e','c','t',0}; 00066 static const WCHAR attr_expires[] = {'E','x','p','i','r','e','s',0}; 00067 static const WCHAR attr_host[] = {'H','o','s','t',0}; 00068 static const WCHAR attr_if_match[] = {'I','f','-','M','a','t','c','h',0}; 00069 static const WCHAR attr_if_modified_since[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0}; 00070 static const WCHAR attr_if_none_match[] = {'I','f','-','N','o','n','e','-','M','a','t','c','h',0}; 00071 static const WCHAR attr_if_range[] = {'I','f','-','R','a','n','g','e',0}; 00072 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}; 00073 static const WCHAR attr_last_modified[] = {'L','a','s','t','-','M','o','d','i','f','i','e','d',0}; 00074 static const WCHAR attr_location[] = {'L','o','c','a','t','i','o','n',0}; 00075 static const WCHAR attr_max_forwards[] = {'M','a','x','-','F','o','r','w','a','r','d','s',0}; 00076 static const WCHAR attr_mime_version[] = {'M','i','m','e','-','V','e','r','s','i','o','n',0}; 00077 static const WCHAR attr_pragma[] = {'P','r','a','g','m','a',0}; 00078 static const WCHAR attr_proxy_authenticate[] = {'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0}; 00079 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}; 00080 static const WCHAR attr_proxy_connection[] = {'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0}; 00081 static const WCHAR attr_public[] = {'P','u','b','l','i','c',0}; 00082 static const WCHAR attr_range[] = {'R','a','n','g','e',0}; 00083 static const WCHAR attr_referer[] = {'R','e','f','e','r','e','r',0}; 00084 static const WCHAR attr_retry_after[] = {'R','e','t','r','y','-','A','f','t','e','r',0}; 00085 static const WCHAR attr_server[] = {'S','e','r','v','e','r',0}; 00086 static const WCHAR attr_set_cookie[] = {'S','e','t','-','C','o','o','k','i','e',0}; 00087 static const WCHAR attr_status[] = {'S','t','a','t','u','s',0}; 00088 static const WCHAR attr_transfer_encoding[] = {'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0}; 00089 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}; 00090 static const WCHAR attr_upgrade[] = {'U','p','g','r','a','d','e',0}; 00091 static const WCHAR attr_uri[] = {'U','R','I',0}; 00092 static const WCHAR attr_user_agent[] = {'U','s','e','r','-','A','g','e','n','t',0}; 00093 static const WCHAR attr_vary[] = {'V','a','r','y',0}; 00094 static const WCHAR attr_via[] = {'V','i','a',0}; 00095 static const WCHAR attr_warning[] = {'W','a','r','n','i','n','g',0}; 00096 static const WCHAR attr_www_authenticate[] = {'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0}; 00097 00098 static const WCHAR *attribute_table[] = 00099 { 00100 attr_mime_version, /* WINHTTP_QUERY_MIME_VERSION = 0 */ 00101 attr_content_type, /* WINHTTP_QUERY_CONTENT_TYPE = 1 */ 00102 attr_content_transfer_encoding, /* WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */ 00103 attr_content_id, /* WINHTTP_QUERY_CONTENT_ID = 3 */ 00104 NULL, /* WINHTTP_QUERY_CONTENT_DESCRIPTION = 4 */ 00105 attr_content_length, /* WINHTTP_QUERY_CONTENT_LENGTH = 5 */ 00106 attr_content_language, /* WINHTTP_QUERY_CONTENT_LANGUAGE = 6 */ 00107 attr_allow, /* WINHTTP_QUERY_ALLOW = 7 */ 00108 attr_public, /* WINHTTP_QUERY_PUBLIC = 8 */ 00109 attr_date, /* WINHTTP_QUERY_DATE = 9 */ 00110 attr_expires, /* WINHTTP_QUERY_EXPIRES = 10 */ 00111 attr_last_modified, /* WINHTTP_QUERY_LAST_MODIFIEDcw = 11 */ 00112 NULL, /* WINHTTP_QUERY_MESSAGE_ID = 12 */ 00113 attr_uri, /* WINHTTP_QUERY_URI = 13 */ 00114 attr_from, /* WINHTTP_QUERY_DERIVED_FROM = 14 */ 00115 NULL, /* WINHTTP_QUERY_COST = 15 */ 00116 NULL, /* WINHTTP_QUERY_LINK = 16 */ 00117 attr_pragma, /* WINHTTP_QUERY_PRAGMA = 17 */ 00118 NULL, /* WINHTTP_QUERY_VERSION = 18 */ 00119 attr_status, /* WINHTTP_QUERY_STATUS_CODE = 19 */ 00120 NULL, /* WINHTTP_QUERY_STATUS_TEXT = 20 */ 00121 NULL, /* WINHTTP_QUERY_RAW_HEADERS = 21 */ 00122 NULL, /* WINHTTP_QUERY_RAW_HEADERS_CRLF = 22 */ 00123 attr_connection, /* WINHTTP_QUERY_CONNECTION = 23 */ 00124 attr_accept, /* WINHTTP_QUERY_ACCEPT = 24 */ 00125 attr_accept_charset, /* WINHTTP_QUERY_ACCEPT_CHARSET = 25 */ 00126 attr_accept_encoding, /* WINHTTP_QUERY_ACCEPT_ENCODING = 26 */ 00127 attr_accept_language, /* WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 */ 00128 attr_authorization, /* WINHTTP_QUERY_AUTHORIZATION = 28 */ 00129 attr_content_encoding, /* WINHTTP_QUERY_CONTENT_ENCODING = 29 */ 00130 NULL, /* WINHTTP_QUERY_FORWARDED = 30 */ 00131 NULL, /* WINHTTP_QUERY_FROM = 31 */ 00132 attr_if_modified_since, /* WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 */ 00133 attr_location, /* WINHTTP_QUERY_LOCATION = 33 */ 00134 NULL, /* WINHTTP_QUERY_ORIG_URI = 34 */ 00135 attr_referer, /* WINHTTP_QUERY_REFERER = 35 */ 00136 attr_retry_after, /* WINHTTP_QUERY_RETRY_AFTER = 36 */ 00137 attr_server, /* WINHTTP_QUERY_SERVER = 37 */ 00138 NULL, /* WINHTTP_TITLE = 38 */ 00139 attr_user_agent, /* WINHTTP_QUERY_USER_AGENT = 39 */ 00140 attr_www_authenticate, /* WINHTTP_QUERY_WWW_AUTHENTICATE = 40 */ 00141 attr_proxy_authenticate, /* WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 */ 00142 attr_accept_ranges, /* WINHTTP_QUERY_ACCEPT_RANGES = 42 */ 00143 attr_set_cookie, /* WINHTTP_QUERY_SET_COOKIE = 43 */ 00144 attr_cookie, /* WINHTTP_QUERY_COOKIE = 44 */ 00145 NULL, /* WINHTTP_QUERY_REQUEST_METHOD = 45 */ 00146 NULL, /* WINHTTP_QUERY_REFRESH = 46 */ 00147 NULL, /* WINHTTP_QUERY_CONTENT_DISPOSITION = 47 */ 00148 attr_age, /* WINHTTP_QUERY_AGE = 48 */ 00149 attr_cache_control, /* WINHTTP_QUERY_CACHE_CONTROL = 49 */ 00150 attr_content_base, /* WINHTTP_QUERY_CONTENT_BASE = 50 */ 00151 attr_content_location, /* WINHTTP_QUERY_CONTENT_LOCATION = 51 */ 00152 attr_content_md5, /* WINHTTP_QUERY_CONTENT_MD5 = 52 */ 00153 attr_content_range, /* WINHTTP_QUERY_CONTENT_RANGE = 53 */ 00154 attr_etag, /* WINHTTP_QUERY_ETAG = 54 */ 00155 attr_host, /* WINHTTP_QUERY_HOST = 55 */ 00156 attr_if_match, /* WINHTTP_QUERY_IF_MATCH = 56 */ 00157 attr_if_none_match, /* WINHTTP_QUERY_IF_NONE_MATCH = 57 */ 00158 attr_if_range, /* WINHTTP_QUERY_IF_RANGE = 58 */ 00159 attr_if_unmodified_since, /* WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */ 00160 attr_max_forwards, /* WINHTTP_QUERY_MAX_FORWARDS = 60 */ 00161 attr_proxy_authorization, /* WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 */ 00162 attr_range, /* WINHTTP_QUERY_RANGE = 62 */ 00163 attr_transfer_encoding, /* WINHTTP_QUERY_TRANSFER_ENCODING = 63 */ 00164 attr_upgrade, /* WINHTTP_QUERY_UPGRADE = 64 */ 00165 attr_vary, /* WINHTTP_QUERY_VARY = 65 */ 00166 attr_via, /* WINHTTP_QUERY_VIA = 66 */ 00167 attr_warning, /* WINHTTP_QUERY_WARNING = 67 */ 00168 attr_expect, /* WINHTTP_QUERY_EXPECT = 68 */ 00169 attr_proxy_connection, /* WINHTTP_QUERY_PROXY_CONNECTION = 69 */ 00170 attr_unless_modified_since, /* WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */ 00171 NULL, /* WINHTTP_QUERY_PROXY_SUPPORT = 75 */ 00172 NULL, /* WINHTTP_QUERY_AUTHENTICATION_INFO = 76 */ 00173 NULL, /* WINHTTP_QUERY_PASSPORT_URLS = 77 */ 00174 NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */ 00175 }; 00176 00177 static DWORD CALLBACK task_thread( LPVOID param ) 00178 { 00179 task_header_t *task = param; 00180 00181 task->proc( task ); 00182 00183 release_object( &task->request->hdr ); 00184 heap_free( task ); 00185 return ERROR_SUCCESS; 00186 } 00187 00188 static BOOL queue_task( task_header_t *task ) 00189 { 00190 return QueueUserWorkItem( task_thread, task, WT_EXECUTELONGFUNCTION ); 00191 } 00192 00193 static void free_header( header_t *header ) 00194 { 00195 heap_free( header->field ); 00196 heap_free( header->value ); 00197 heap_free( header ); 00198 } 00199 00200 static BOOL valid_token_char( WCHAR c ) 00201 { 00202 if (c < 32 || c == 127) return FALSE; 00203 switch (c) 00204 { 00205 case '(': case ')': 00206 case '<': case '>': 00207 case '@': case ',': 00208 case ';': case ':': 00209 case '\\': case '\"': 00210 case '/': case '[': 00211 case ']': case '?': 00212 case '=': case '{': 00213 case '}': case ' ': 00214 case '\t': 00215 return FALSE; 00216 default: 00217 return TRUE; 00218 } 00219 } 00220 00221 static header_t *parse_header( LPCWSTR string ) 00222 { 00223 const WCHAR *p, *q; 00224 header_t *header; 00225 int len; 00226 00227 p = string; 00228 if (!(q = strchrW( p, ':' ))) 00229 { 00230 WARN("no ':' in line %s\n", debugstr_w(string)); 00231 return NULL; 00232 } 00233 if (q == string) 00234 { 00235 WARN("empty field name in line %s\n", debugstr_w(string)); 00236 return NULL; 00237 } 00238 while (*p != ':') 00239 { 00240 if (!valid_token_char( *p )) 00241 { 00242 WARN("invalid character in field name %s\n", debugstr_w(string)); 00243 return NULL; 00244 } 00245 p++; 00246 } 00247 len = q - string; 00248 if (!(header = heap_alloc_zero( sizeof(header_t) ))) return NULL; 00249 if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) ))) 00250 { 00251 heap_free( header ); 00252 return NULL; 00253 } 00254 memcpy( header->field, string, len * sizeof(WCHAR) ); 00255 header->field[len] = 0; 00256 00257 q++; /* skip past colon */ 00258 while (*q == ' ') q++; 00259 if (!*q) 00260 { 00261 WARN("no value in line %s\n", debugstr_w(string)); 00262 return header; 00263 } 00264 len = strlenW( q ); 00265 if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) 00266 { 00267 free_header( header ); 00268 return NULL; 00269 } 00270 memcpy( header->value, q, len * sizeof(WCHAR) ); 00271 header->value[len] = 0; 00272 00273 return header; 00274 } 00275 00276 static int get_header_index( request_t *request, LPCWSTR field, int requested_index, BOOL request_only ) 00277 { 00278 int index; 00279 00280 TRACE("%s\n", debugstr_w(field)); 00281 00282 for (index = 0; index < request->num_headers; index++) 00283 { 00284 if (strcmpiW( request->headers[index].field, field )) continue; 00285 if (request_only && !request->headers[index].is_request) continue; 00286 if (!request_only && request->headers[index].is_request) continue; 00287 00288 if (!requested_index) break; 00289 requested_index--; 00290 } 00291 if (index >= request->num_headers) index = -1; 00292 TRACE("returning %d\n", index); 00293 return index; 00294 } 00295 00296 static BOOL insert_header( request_t *request, header_t *header ) 00297 { 00298 DWORD count; 00299 header_t *hdrs; 00300 00301 count = request->num_headers + 1; 00302 if (count > 1) 00303 hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count ); 00304 else 00305 hdrs = heap_alloc_zero( sizeof(header_t) * count ); 00306 00307 if (hdrs) 00308 { 00309 request->headers = hdrs; 00310 request->headers[count - 1].field = strdupW( header->field ); 00311 request->headers[count - 1].value = strdupW( header->value ); 00312 request->headers[count - 1].is_request = header->is_request; 00313 request->num_headers++; 00314 return TRUE; 00315 } 00316 return FALSE; 00317 } 00318 00319 static BOOL delete_header( request_t *request, DWORD index ) 00320 { 00321 if (!request->num_headers) return FALSE; 00322 if (index >= request->num_headers) return FALSE; 00323 request->num_headers--; 00324 00325 heap_free( request->headers[index].field ); 00326 heap_free( request->headers[index].value ); 00327 00328 memmove( &request->headers[index], &request->headers[index + 1], (request->num_headers - index) * sizeof(header_t) ); 00329 memset( &request->headers[request->num_headers], 0, sizeof(header_t) ); 00330 return TRUE; 00331 } 00332 00333 static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only ) 00334 { 00335 int index; 00336 header_t *header; 00337 00338 TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags); 00339 00340 /* replace wins out over add */ 00341 if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) flags &= ~WINHTTP_ADDREQ_FLAG_ADD; 00342 00343 if (flags & WINHTTP_ADDREQ_FLAG_ADD) index = -1; 00344 else 00345 index = get_header_index( request, field, 0, request_only ); 00346 00347 if (index >= 0) 00348 { 00349 if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE; 00350 header = &request->headers[index]; 00351 } 00352 else if (value) 00353 { 00354 header_t hdr; 00355 00356 hdr.field = (LPWSTR)field; 00357 hdr.value = (LPWSTR)value; 00358 hdr.is_request = request_only; 00359 00360 return insert_header( request, &hdr ); 00361 } 00362 /* no value to delete */ 00363 else return TRUE; 00364 00365 if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) 00366 { 00367 delete_header( request, index ); 00368 if (value) 00369 { 00370 header_t hdr; 00371 00372 hdr.field = (LPWSTR)field; 00373 hdr.value = (LPWSTR)value; 00374 hdr.is_request = request_only; 00375 00376 return insert_header( request, &hdr ); 00377 } 00378 return TRUE; 00379 } 00380 else if (flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON)) 00381 { 00382 WCHAR sep, *tmp; 00383 int len, orig_len, value_len; 00384 00385 orig_len = strlenW( header->value ); 00386 value_len = strlenW( value ); 00387 00388 if (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) sep = ','; 00389 else sep = ';'; 00390 00391 len = orig_len + value_len + 2; 00392 if ((tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) 00393 { 00394 header->value = tmp; 00395 00396 header->value[orig_len] = sep; 00397 orig_len++; 00398 header->value[orig_len] = ' '; 00399 orig_len++; 00400 00401 memcpy( &header->value[orig_len], value, value_len * sizeof(WCHAR) ); 00402 header->value[len] = 0; 00403 return TRUE; 00404 } 00405 } 00406 return TRUE; 00407 } 00408 00409 BOOL add_request_headers( request_t *request, LPCWSTR headers, DWORD len, DWORD flags ) 00410 { 00411 BOOL ret = FALSE; 00412 WCHAR *buffer, *p, *q; 00413 header_t *header; 00414 00415 if (len == ~0u) len = strlenW( headers ); 00416 if (!len) return TRUE; 00417 if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; 00418 strcpyW( buffer, headers ); 00419 00420 p = buffer; 00421 do 00422 { 00423 q = p; 00424 while (*q) 00425 { 00426 if (q[0] == '\r' && q[1] == '\n') break; 00427 q++; 00428 } 00429 if (!*p) break; 00430 if (*q == '\r') 00431 { 00432 *q = 0; 00433 q += 2; /* jump over \r\n */ 00434 } 00435 if ((header = parse_header( p ))) 00436 { 00437 ret = process_header( request, header->field, header->value, flags, TRUE ); 00438 free_header( header ); 00439 } 00440 p = q; 00441 } while (ret); 00442 00443 heap_free( buffer ); 00444 return ret; 00445 } 00446 00447 /*********************************************************************** 00448 * WinHttpAddRequestHeaders (winhttp.@) 00449 */ 00450 BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD len, DWORD flags ) 00451 { 00452 BOOL ret; 00453 request_t *request; 00454 00455 TRACE("%p, %s, 0x%x, 0x%08x\n", hrequest, debugstr_w(headers), len, flags); 00456 00457 if (!headers) 00458 { 00459 set_last_error( ERROR_INVALID_PARAMETER ); 00460 return FALSE; 00461 } 00462 if (!(request = (request_t *)grab_object( hrequest ))) 00463 { 00464 set_last_error( ERROR_INVALID_HANDLE ); 00465 return FALSE; 00466 } 00467 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 00468 { 00469 release_object( &request->hdr ); 00470 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 00471 return FALSE; 00472 } 00473 00474 ret = add_request_headers( request, headers, len, flags ); 00475 00476 release_object( &request->hdr ); 00477 return ret; 00478 } 00479 00480 static WCHAR *build_request_path( request_t *request ) 00481 { 00482 WCHAR *ret; 00483 00484 if (strcmpiW( request->connect->hostname, request->connect->servername )) 00485 { 00486 static const WCHAR http[] = { 'h','t','t','p',0 }; 00487 static const WCHAR https[] = { 'h','t','t','p','s',0 }; 00488 static const WCHAR fmt[] = { '%','s',':','/','/','%','s',0 }; 00489 LPCWSTR scheme = request->netconn.secure ? https : http; 00490 int len; 00491 00492 len = strlenW( scheme ) + strlenW( request->connect->hostname ); 00493 /* 3 characters for '://', 1 for NUL. */ 00494 len += 4; 00495 if (request->connect->hostport) 00496 { 00497 /* 1 for ':' between host and port, up to 5 for port */ 00498 len += 6; 00499 } 00500 if (request->path) 00501 len += strlenW( request->path ); 00502 if ((ret = heap_alloc( len * sizeof(WCHAR) ))) 00503 { 00504 sprintfW( ret, fmt, scheme, request->connect->hostname ); 00505 if (request->connect->hostport) 00506 { 00507 static const WCHAR colonFmt[] = { ':','%','u',0 }; 00508 00509 sprintfW( ret + strlenW( ret ), colonFmt, 00510 request->connect->hostport ); 00511 } 00512 if (request->path) 00513 strcatW( ret, request->path ); 00514 } 00515 } 00516 else 00517 ret = request->path; 00518 return ret; 00519 } 00520 00521 static WCHAR *build_request_string( request_t *request ) 00522 { 00523 static const WCHAR space[] = {' ',0}; 00524 static const WCHAR crlf[] = {'\r','\n',0}; 00525 static const WCHAR colon[] = {':',' ',0}; 00526 static const WCHAR twocrlf[] = {'\r','\n','\r','\n',0}; 00527 00528 WCHAR *path, *ret; 00529 const WCHAR **headers, **p; 00530 unsigned int len, i = 0, j; 00531 00532 /* allocate space for an array of all the string pointers to be added */ 00533 len = request->num_headers * 4 + 7; 00534 if (!(headers = heap_alloc( len * sizeof(LPCWSTR) ))) return NULL; 00535 00536 path = build_request_path( request ); 00537 headers[i++] = request->verb; 00538 headers[i++] = space; 00539 headers[i++] = path; 00540 headers[i++] = space; 00541 headers[i++] = request->version; 00542 00543 for (j = 0; j < request->num_headers; j++) 00544 { 00545 if (request->headers[j].is_request) 00546 { 00547 headers[i++] = crlf; 00548 headers[i++] = request->headers[j].field; 00549 headers[i++] = colon; 00550 headers[i++] = request->headers[j].value; 00551 00552 TRACE("adding header %s (%s)\n", debugstr_w(request->headers[j].field), 00553 debugstr_w(request->headers[j].value)); 00554 } 00555 } 00556 headers[i++] = twocrlf; 00557 headers[i] = NULL; 00558 00559 len = 0; 00560 for (p = headers; *p; p++) len += strlenW( *p ); 00561 len++; 00562 00563 if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) 00564 goto out; 00565 *ret = 0; 00566 for (p = headers; *p; p++) strcatW( ret, *p ); 00567 00568 out: 00569 if (path != request->path) 00570 heap_free( path ); 00571 heap_free( headers ); 00572 return ret; 00573 } 00574 00575 #define QUERY_MODIFIER_MASK (WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_FLAG_SYSTEMTIME | WINHTTP_QUERY_FLAG_NUMBER) 00576 00577 static BOOL query_headers( request_t *request, DWORD level, LPCWSTR name, LPVOID buffer, LPDWORD buflen, LPDWORD index ) 00578 { 00579 header_t *header = NULL; 00580 BOOL request_only, ret = FALSE; 00581 int requested_index, header_index = -1; 00582 DWORD attr, len; 00583 00584 request_only = level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS; 00585 requested_index = index ? *index : 0; 00586 00587 attr = level & ~QUERY_MODIFIER_MASK; 00588 switch (attr) 00589 { 00590 case WINHTTP_QUERY_CUSTOM: 00591 { 00592 header_index = get_header_index( request, name, requested_index, request_only ); 00593 break; 00594 } 00595 case WINHTTP_QUERY_RAW_HEADERS: 00596 { 00597 WCHAR *headers, *p, *q; 00598 00599 if (request_only) 00600 headers = build_request_string( request ); 00601 else 00602 headers = request->raw_headers; 00603 00604 if (!(p = headers)) return FALSE; 00605 for (len = 0; *p; p++) if (*p != '\r') len++; 00606 00607 if (!buffer || (len + 1) * sizeof(WCHAR) > *buflen) 00608 { 00609 len++; 00610 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00611 } 00612 else 00613 { 00614 for (p = headers, q = buffer; *p; p++, q++) 00615 { 00616 if (*p != '\r') *q = *p; 00617 else 00618 { 00619 *q = 0; 00620 p++; /* skip '\n' */ 00621 } 00622 } 00623 *q = 0; 00624 TRACE("returning data: %s\n", debugstr_wn(buffer, len)); 00625 ret = TRUE; 00626 } 00627 *buflen = len * sizeof(WCHAR); 00628 if (request_only) heap_free( headers ); 00629 return ret; 00630 } 00631 case WINHTTP_QUERY_RAW_HEADERS_CRLF: 00632 { 00633 WCHAR *headers; 00634 00635 if (request_only) 00636 headers = build_request_string( request ); 00637 else 00638 headers = request->raw_headers; 00639 00640 if (!headers) return FALSE; 00641 len = strlenW( headers ) * sizeof(WCHAR); 00642 if (!buffer || len + sizeof(WCHAR) > *buflen) 00643 { 00644 len += sizeof(WCHAR); 00645 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00646 } 00647 else 00648 { 00649 memcpy( buffer, headers, len + sizeof(WCHAR) ); 00650 TRACE("returning data: %s\n", debugstr_wn(buffer, len / sizeof(WCHAR))); 00651 ret = TRUE; 00652 } 00653 *buflen = len; 00654 if (request_only) heap_free( headers ); 00655 return ret; 00656 } 00657 case WINHTTP_QUERY_VERSION: 00658 len = strlenW( request->version ) * sizeof(WCHAR); 00659 if (!buffer || len + sizeof(WCHAR) > *buflen) 00660 { 00661 len += sizeof(WCHAR); 00662 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00663 } 00664 else 00665 { 00666 strcpyW( buffer, request->version ); 00667 TRACE("returning string: %s\n", debugstr_w(buffer)); 00668 ret = TRUE; 00669 } 00670 *buflen = len; 00671 return ret; 00672 00673 case WINHTTP_QUERY_STATUS_TEXT: 00674 len = strlenW( request->status_text ) * sizeof(WCHAR); 00675 if (!buffer || len + sizeof(WCHAR) > *buflen) 00676 { 00677 len += sizeof(WCHAR); 00678 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00679 } 00680 else 00681 { 00682 strcpyW( buffer, request->status_text ); 00683 TRACE("returning string: %s\n", debugstr_w(buffer)); 00684 ret = TRUE; 00685 } 00686 *buflen = len; 00687 return ret; 00688 00689 default: 00690 if (attr >= sizeof(attribute_table)/sizeof(attribute_table[0]) || !attribute_table[attr]) 00691 { 00692 FIXME("attribute %u not implemented\n", attr); 00693 return FALSE; 00694 } 00695 TRACE("attribute %s\n", debugstr_w(attribute_table[attr])); 00696 header_index = get_header_index( request, attribute_table[attr], requested_index, request_only ); 00697 break; 00698 } 00699 00700 if (header_index >= 0) 00701 { 00702 header = &request->headers[header_index]; 00703 } 00704 if (!header || (request_only && !header->is_request)) 00705 { 00706 set_last_error( ERROR_WINHTTP_HEADER_NOT_FOUND ); 00707 return FALSE; 00708 } 00709 if (index) *index += 1; 00710 if (level & WINHTTP_QUERY_FLAG_NUMBER) 00711 { 00712 if (!buffer || sizeof(int) > *buflen) 00713 { 00714 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00715 } 00716 else 00717 { 00718 int *number = buffer; 00719 *number = atoiW( header->value ); 00720 TRACE("returning number: %d\n", *number); 00721 ret = TRUE; 00722 } 00723 *buflen = sizeof(int); 00724 } 00725 else if (level & WINHTTP_QUERY_FLAG_SYSTEMTIME) 00726 { 00727 SYSTEMTIME *st = buffer; 00728 if (!buffer || sizeof(SYSTEMTIME) > *buflen) 00729 { 00730 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00731 } 00732 else if ((ret = WinHttpTimeToSystemTime( header->value, st ))) 00733 { 00734 TRACE("returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", 00735 st->wYear, st->wMonth, st->wDay, st->wDayOfWeek, 00736 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds); 00737 } 00738 *buflen = sizeof(SYSTEMTIME); 00739 } 00740 else if (header->value) 00741 { 00742 len = strlenW( header->value ) * sizeof(WCHAR); 00743 if (!buffer || len + sizeof(WCHAR) > *buflen) 00744 { 00745 len += sizeof(WCHAR); 00746 set_last_error( ERROR_INSUFFICIENT_BUFFER ); 00747 } 00748 else 00749 { 00750 strcpyW( buffer, header->value ); 00751 TRACE("returning string: %s\n", debugstr_w(buffer)); 00752 ret = TRUE; 00753 } 00754 *buflen = len; 00755 } 00756 return ret; 00757 } 00758 00759 /*********************************************************************** 00760 * WinHttpQueryHeaders (winhttp.@) 00761 */ 00762 BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, LPVOID buffer, LPDWORD buflen, LPDWORD index ) 00763 { 00764 BOOL ret; 00765 request_t *request; 00766 00767 TRACE("%p, 0x%08x, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index); 00768 00769 if (!(request = (request_t *)grab_object( hrequest ))) 00770 { 00771 set_last_error( ERROR_INVALID_HANDLE ); 00772 return FALSE; 00773 } 00774 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 00775 { 00776 release_object( &request->hdr ); 00777 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 00778 return FALSE; 00779 } 00780 00781 ret = query_headers( request, level, name, buffer, buflen, index ); 00782 00783 release_object( &request->hdr ); 00784 return ret; 00785 } 00786 00787 static LPWSTR concatenate_string_list( LPCWSTR *list, int len ) 00788 { 00789 LPCWSTR *t; 00790 LPWSTR str; 00791 00792 for( t = list; *t ; t++ ) 00793 len += strlenW( *t ); 00794 len++; 00795 00796 str = heap_alloc( len * sizeof(WCHAR) ); 00797 if (!str) return NULL; 00798 *str = 0; 00799 00800 for( t = list; *t ; t++ ) 00801 strcatW( str, *t ); 00802 00803 return str; 00804 } 00805 00806 static LPWSTR build_header_request_string( request_t *request, LPCWSTR verb, 00807 LPCWSTR path, LPCWSTR version ) 00808 { 00809 static const WCHAR crlf[] = {'\r','\n',0}; 00810 static const WCHAR space[] = { ' ',0 }; 00811 static const WCHAR colon[] = { ':',' ',0 }; 00812 static const WCHAR twocrlf[] = {'\r','\n','\r','\n', 0}; 00813 LPWSTR requestString; 00814 DWORD len, n; 00815 LPCWSTR *req; 00816 UINT i; 00817 LPWSTR p; 00818 00819 /* allocate space for an array of all the string pointers to be added */ 00820 len = (request->num_headers) * 4 + 10; 00821 req = heap_alloc( len * sizeof(LPCWSTR) ); 00822 if (!req) return NULL; 00823 00824 /* add the verb, path and HTTP version string */ 00825 n = 0; 00826 req[n++] = verb; 00827 req[n++] = space; 00828 req[n++] = path; 00829 req[n++] = space; 00830 req[n++] = version; 00831 00832 /* Append custom request headers */ 00833 for (i = 0; i < request->num_headers; i++) 00834 { 00835 if (request->headers[i].is_request) 00836 { 00837 req[n++] = crlf; 00838 req[n++] = request->headers[i].field; 00839 req[n++] = colon; 00840 req[n++] = request->headers[i].value; 00841 00842 TRACE("Adding custom header %s (%s)\n", 00843 debugstr_w(request->headers[i].field), 00844 debugstr_w(request->headers[i].value)); 00845 } 00846 } 00847 00848 if( n >= len ) 00849 ERR("oops. buffer overrun\n"); 00850 00851 req[n] = NULL; 00852 requestString = concatenate_string_list( req, 4 ); 00853 heap_free( req ); 00854 if (!requestString) return NULL; 00855 00856 /* 00857 * Set (header) termination string for request 00858 * Make sure there's exactly two new lines at the end of the request 00859 */ 00860 p = &requestString[strlenW(requestString)-1]; 00861 while ( (*p == '\n') || (*p == '\r') ) 00862 p--; 00863 strcpyW( p+1, twocrlf ); 00864 00865 return requestString; 00866 } 00867 00868 static BOOL read_reply( request_t *request ); 00869 00870 static BOOL secure_proxy_connect( request_t *request ) 00871 { 00872 static const WCHAR verbConnect[] = {'C','O','N','N','E','C','T',0}; 00873 static const WCHAR fmt[] = {'%','s',':','%','u',0}; 00874 BOOL ret = FALSE; 00875 LPWSTR path; 00876 connect_t *connect = request->connect; 00877 00878 path = heap_alloc( (strlenW( connect->hostname ) + 13) * sizeof(WCHAR) ); 00879 if (path) 00880 { 00881 LPWSTR requestString; 00882 00883 sprintfW( path, fmt, connect->hostname, connect->hostport ); 00884 requestString = build_header_request_string( request, verbConnect, 00885 path, http1_1 ); 00886 heap_free( path ); 00887 if (requestString) 00888 { 00889 LPSTR req_ascii = strdupWA( requestString ); 00890 00891 heap_free( requestString ); 00892 if (req_ascii) 00893 { 00894 int len = strlen( req_ascii ), bytes_sent; 00895 00896 ret = netconn_send( &request->netconn, req_ascii, len, 0, &bytes_sent ); 00897 heap_free( req_ascii ); 00898 if (ret) 00899 ret = read_reply( request ); 00900 } 00901 } 00902 } 00903 return ret; 00904 } 00905 00906 #ifndef INET6_ADDRSTRLEN 00907 #define INET6_ADDRSTRLEN 46 00908 #endif 00909 00910 static BOOL open_connection( request_t *request ) 00911 { 00912 connect_t *connect; 00913 const void *addr; 00914 char address[INET6_ADDRSTRLEN]; 00915 WCHAR *addressW; 00916 INTERNET_PORT port; 00917 socklen_t slen; 00918 00919 if (netconn_connected( &request->netconn )) return TRUE; 00920 00921 connect = request->connect; 00922 port = connect->serverport ? connect->serverport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); 00923 00924 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, connect->servername, strlenW(connect->servername) + 1 ); 00925 00926 slen = sizeof(connect->sockaddr); 00927 if (!netconn_resolve( connect->servername, port, (struct sockaddr *)&connect->sockaddr, &slen, request->resolve_timeout )) return FALSE; 00928 switch (connect->sockaddr.ss_family) 00929 { 00930 case AF_INET: 00931 addr = &((struct sockaddr_in *)&connect->sockaddr)->sin_addr; 00932 break; 00933 case AF_INET6: 00934 addr = &((struct sockaddr_in6 *)&connect->sockaddr)->sin6_addr; 00935 break; 00936 default: 00937 WARN("unsupported address family %d\n", connect->sockaddr.ss_family); 00938 return FALSE; 00939 } 00940 inet_ntop( connect->sockaddr.ss_family, addr, address, sizeof(address) ); 00941 addressW = strdupAW( address ); 00942 00943 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, addressW, strlenW(addressW) + 1 ); 00944 00945 TRACE("connecting to %s:%u\n", address, port); 00946 00947 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 ); 00948 00949 if (!netconn_create( &request->netconn, connect->sockaddr.ss_family, SOCK_STREAM, 0 )) 00950 { 00951 heap_free( addressW ); 00952 return FALSE; 00953 } 00954 netconn_set_timeout( &request->netconn, TRUE, request->send_timeout ); 00955 netconn_set_timeout( &request->netconn, FALSE, request->recv_timeout ); 00956 if (!netconn_connect( &request->netconn, (struct sockaddr *)&connect->sockaddr, slen, request->connect_timeout )) 00957 { 00958 netconn_close( &request->netconn ); 00959 heap_free( addressW ); 00960 return FALSE; 00961 } 00962 if (request->hdr.flags & WINHTTP_FLAG_SECURE) 00963 { 00964 if (connect->session->proxy_server && 00965 strcmpiW( connect->hostname, connect->servername )) 00966 { 00967 if (!secure_proxy_connect( request )) 00968 { 00969 heap_free( addressW ); 00970 return FALSE; 00971 } 00972 } 00973 if (!netconn_secure_connect( &request->netconn, connect->servername )) 00974 { 00975 netconn_close( &request->netconn ); 00976 heap_free( addressW ); 00977 return FALSE; 00978 } 00979 } 00980 00981 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, strlenW(addressW) + 1 ); 00982 00983 heap_free( addressW ); 00984 return TRUE; 00985 } 00986 00987 void close_connection( request_t *request ) 00988 { 00989 if (!netconn_connected( &request->netconn )) return; 00990 00991 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); 00992 netconn_close( &request->netconn ); 00993 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); 00994 } 00995 00996 static BOOL add_host_header( request_t *request, DWORD modifier ) 00997 { 00998 BOOL ret; 00999 DWORD len; 01000 WCHAR *host; 01001 static const WCHAR fmt[] = {'%','s',':','%','u',0}; 01002 connect_t *connect = request->connect; 01003 INTERNET_PORT port; 01004 01005 port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); 01006 01007 if (port == INTERNET_DEFAULT_HTTP_PORT || port == INTERNET_DEFAULT_HTTPS_PORT) 01008 { 01009 return process_header( request, attr_host, connect->hostname, modifier, TRUE ); 01010 } 01011 len = strlenW( connect->hostname ) + 7; /* sizeof(":65335") */ 01012 if (!(host = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; 01013 sprintfW( host, fmt, connect->hostname, port ); 01014 ret = process_header( request, attr_host, host, modifier, TRUE ); 01015 heap_free( host ); 01016 return ret; 01017 } 01018 01019 static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional, 01020 DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) 01021 { 01022 static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0}; 01023 static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0}; 01024 static const WCHAR length_fmt[] = {'%','l','d',0}; 01025 01026 BOOL ret = FALSE; 01027 connect_t *connect = request->connect; 01028 session_t *session = connect->session; 01029 WCHAR *req = NULL; 01030 char *req_ascii; 01031 int bytes_sent; 01032 DWORD len; 01033 01034 if (session->agent) 01035 process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); 01036 01037 if (connect->hostname) 01038 add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW ); 01039 01040 if (total_len || (request->verb && !strcmpW( request->verb, postW ))) 01041 { 01042 WCHAR length[21]; /* decimal long int + null */ 01043 sprintfW( length, length_fmt, total_len ); 01044 process_header( request, attr_content_length, length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); 01045 } 01046 if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE)) 01047 { 01048 process_header( request, attr_connection, keep_alive, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); 01049 } 01050 if (request->hdr.flags & WINHTTP_FLAG_REFRESH) 01051 { 01052 process_header( request, attr_pragma, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); 01053 process_header( request, attr_cache_control, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); 01054 } 01055 if (headers && !add_request_headers( request, headers, headers_len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) 01056 { 01057 TRACE("failed to add request headers\n"); 01058 return FALSE; 01059 } 01060 if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request )) 01061 { 01062 WARN("failed to add cookie headers\n"); 01063 return FALSE; 01064 } 01065 01066 if (!(ret = open_connection( request ))) goto end; 01067 if (!(req = build_request_string( request ))) goto end; 01068 01069 if (!(req_ascii = strdupWA( req ))) goto end; 01070 TRACE("full request: %s\n", debugstr_a(req_ascii)); 01071 len = strlen(req_ascii); 01072 01073 if (context) request->hdr.context = context; 01074 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); 01075 01076 ret = netconn_send( &request->netconn, req_ascii, len, 0, &bytes_sent ); 01077 heap_free( req_ascii ); 01078 if (!ret) goto end; 01079 01080 if (optional_len && !netconn_send( &request->netconn, optional, optional_len, 0, &bytes_sent )) goto end; 01081 len += optional_len; 01082 01083 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(DWORD) ); 01084 01085 end: 01086 if (async) 01087 { 01088 if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 ); 01089 else 01090 { 01091 WINHTTP_ASYNC_RESULT result; 01092 result.dwResult = API_SEND_REQUEST; 01093 result.dwError = get_last_error(); 01094 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); 01095 } 01096 } 01097 heap_free( req ); 01098 return ret; 01099 } 01100 01101 static void task_send_request( task_header_t *task ) 01102 { 01103 send_request_t *s = (send_request_t *)task; 01104 send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE ); 01105 heap_free( s->headers ); 01106 } 01107 01108 /*********************************************************************** 01109 * WinHttpSendRequest (winhttp.@) 01110 */ 01111 BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD headers_len, 01112 LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) 01113 { 01114 BOOL ret; 01115 request_t *request; 01116 01117 TRACE("%p, %s, 0x%x, %u, %u, %lx\n", 01118 hrequest, debugstr_w(headers), headers_len, optional_len, total_len, context); 01119 01120 if (!(request = (request_t *)grab_object( hrequest ))) 01121 { 01122 set_last_error( ERROR_INVALID_HANDLE ); 01123 return FALSE; 01124 } 01125 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 01126 { 01127 release_object( &request->hdr ); 01128 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 01129 return FALSE; 01130 } 01131 01132 if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) 01133 { 01134 send_request_t *s; 01135 01136 if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE; 01137 s->hdr.request = request; 01138 s->hdr.proc = task_send_request; 01139 s->headers = strdupW( headers ); 01140 s->headers_len = headers_len; 01141 s->optional = optional; 01142 s->optional_len = optional_len; 01143 s->total_len = total_len; 01144 s->context = context; 01145 01146 addref_object( &request->hdr ); 01147 ret = queue_task( (task_header_t *)s ); 01148 } 01149 else 01150 ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE ); 01151 01152 release_object( &request->hdr ); 01153 return ret; 01154 } 01155 01156 #define ARRAYSIZE(array) (sizeof(array) / sizeof((array)[0])) 01157 01158 static DWORD auth_scheme_from_header( WCHAR *header ) 01159 { 01160 static const WCHAR basic[] = {'B','a','s','i','c'}; 01161 static const WCHAR ntlm[] = {'N','T','L','M'}; 01162 static const WCHAR passport[] = {'P','a','s','s','p','o','r','t'}; 01163 static const WCHAR digest[] = {'D','i','g','e','s','t'}; 01164 static const WCHAR negotiate[] = {'N','e','g','o','t','i','a','t','e'}; 01165 01166 if (!strncmpiW( header, basic, ARRAYSIZE(basic) ) && 01167 (header[ARRAYSIZE(basic)] == ' ' || !header[ARRAYSIZE(basic)])) return WINHTTP_AUTH_SCHEME_BASIC; 01168 01169 if (!strncmpiW( header, ntlm, ARRAYSIZE(ntlm) ) && 01170 (header[ARRAYSIZE(ntlm)] == ' ' || !header[ARRAYSIZE(ntlm)])) return WINHTTP_AUTH_SCHEME_NTLM; 01171 01172 if (!strncmpiW( header, passport, ARRAYSIZE(passport) ) && 01173 (header[ARRAYSIZE(passport)] == ' ' || !header[ARRAYSIZE(passport)])) return WINHTTP_AUTH_SCHEME_PASSPORT; 01174 01175 if (!strncmpiW( header, digest, ARRAYSIZE(digest) ) && 01176 (header[ARRAYSIZE(digest)] == ' ' || !header[ARRAYSIZE(digest)])) return WINHTTP_AUTH_SCHEME_DIGEST; 01177 01178 if (!strncmpiW( header, negotiate, ARRAYSIZE(negotiate) ) && 01179 (header[ARRAYSIZE(negotiate)] == ' ' || !header[ARRAYSIZE(negotiate)])) return WINHTTP_AUTH_SCHEME_NEGOTIATE; 01180 01181 return 0; 01182 } 01183 01184 static BOOL query_auth_schemes( request_t *request, DWORD level, LPDWORD supported, LPDWORD first ) 01185 { 01186 DWORD index = 0; 01187 BOOL ret = FALSE; 01188 01189 for (;;) 01190 { 01191 WCHAR *buffer; 01192 DWORD size, scheme; 01193 01194 size = 0; 01195 query_headers( request, level, NULL, NULL, &size, &index ); 01196 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break; 01197 01198 index--; 01199 if (!(buffer = heap_alloc( size ))) return FALSE; 01200 if (!query_headers( request, level, NULL, buffer, &size, &index )) 01201 { 01202 heap_free( buffer ); 01203 return FALSE; 01204 } 01205 scheme = auth_scheme_from_header( buffer ); 01206 if (first && index == 1) *first = scheme; 01207 *supported |= scheme; 01208 01209 heap_free( buffer ); 01210 ret = TRUE; 01211 } 01212 return ret; 01213 } 01214 01215 /*********************************************************************** 01216 * WinHttpQueryAuthSchemes (winhttp.@) 01217 */ 01218 BOOL WINAPI WinHttpQueryAuthSchemes( HINTERNET hrequest, LPDWORD supported, LPDWORD first, LPDWORD target ) 01219 { 01220 BOOL ret = FALSE; 01221 request_t *request; 01222 01223 TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target); 01224 01225 if (!(request = (request_t *)grab_object( hrequest ))) 01226 { 01227 set_last_error( ERROR_INVALID_HANDLE ); 01228 return FALSE; 01229 } 01230 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 01231 { 01232 release_object( &request->hdr ); 01233 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 01234 return FALSE; 01235 } 01236 01237 if (query_auth_schemes( request, WINHTTP_QUERY_WWW_AUTHENTICATE, supported, first )) 01238 { 01239 *target = WINHTTP_AUTH_TARGET_SERVER; 01240 ret = TRUE; 01241 } 01242 else if (query_auth_schemes( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, supported, first )) 01243 { 01244 *target = WINHTTP_AUTH_TARGET_PROXY; 01245 ret = TRUE; 01246 } 01247 01248 release_object( &request->hdr ); 01249 return ret; 01250 } 01251 01252 static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 ) 01253 { 01254 UINT n = 0, x; 01255 static const char base64enc[] = 01256 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 01257 01258 while (len > 0) 01259 { 01260 /* first 6 bits, all from bin[0] */ 01261 base64[n++] = base64enc[(bin[0] & 0xfc) >> 2]; 01262 x = (bin[0] & 3) << 4; 01263 01264 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ 01265 if (len == 1) 01266 { 01267 base64[n++] = base64enc[x]; 01268 base64[n++] = '='; 01269 base64[n++] = '='; 01270 break; 01271 } 01272 base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)]; 01273 x = (bin[1] & 0x0f) << 2; 01274 01275 /* next 6 bits 4 from bin[1] and 2 from bin[2] */ 01276 if (len == 2) 01277 { 01278 base64[n++] = base64enc[x]; 01279 base64[n++] = '='; 01280 break; 01281 } 01282 base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)]; 01283 01284 /* last 6 bits, all from bin [2] */ 01285 base64[n++] = base64enc[bin[2] & 0x3f]; 01286 bin += 3; 01287 len -= 3; 01288 } 01289 base64[n] = 0; 01290 return n; 01291 } 01292 01293 static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, LPCWSTR username, LPCWSTR password ) 01294 { 01295 static const WCHAR basic[] = {'B','a','s','i','c',' ',0}; 01296 const WCHAR *auth_scheme, *auth_target; 01297 WCHAR *auth_header; 01298 DWORD len, auth_data_len; 01299 char *auth_data; 01300 BOOL ret; 01301 01302 if (!username || !password) 01303 { 01304 set_last_error( ERROR_INVALID_PARAMETER ); 01305 return FALSE; 01306 } 01307 01308 switch (target) 01309 { 01310 case WINHTTP_AUTH_TARGET_SERVER: auth_target = attr_authorization; break; 01311 case WINHTTP_AUTH_TARGET_PROXY: auth_target = attr_proxy_authorization; break; 01312 default: 01313 WARN("unknown target %x\n", target); 01314 return FALSE; 01315 } 01316 switch (scheme) 01317 { 01318 case WINHTTP_AUTH_SCHEME_BASIC: 01319 { 01320 int userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL ); 01321 int passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL ); 01322 01323 TRACE("basic authentication\n"); 01324 01325 auth_scheme = basic; 01326 auth_data_len = userlen + 1 + passlen; 01327 if (!(auth_data = heap_alloc( auth_data_len ))) return FALSE; 01328 01329 WideCharToMultiByte( CP_UTF8, 0, username, -1, auth_data, userlen, NULL, NULL ); 01330 auth_data[userlen] = ':'; 01331 WideCharToMultiByte( CP_UTF8, 0, password, -1, auth_data + userlen + 1, passlen, NULL, NULL ); 01332 break; 01333 } 01334 case WINHTTP_AUTH_SCHEME_NTLM: 01335 case WINHTTP_AUTH_SCHEME_PASSPORT: 01336 case WINHTTP_AUTH_SCHEME_DIGEST: 01337 case WINHTTP_AUTH_SCHEME_NEGOTIATE: 01338 FIXME("unimplemented authentication scheme %x\n", scheme); 01339 return FALSE; 01340 default: 01341 WARN("unknown authentication scheme %x\n", scheme); 01342 return FALSE; 01343 } 01344 01345 len = strlenW( auth_scheme ) + ((auth_data_len + 2) * 4) / 3; 01346 if (!(auth_header = heap_alloc( (len + 1) * sizeof(WCHAR) ))) 01347 { 01348 heap_free( auth_data ); 01349 return FALSE; 01350 } 01351 strcpyW( auth_header, auth_scheme ); 01352 encode_base64( auth_data, auth_data_len, auth_header + strlenW( auth_header ) ); 01353 01354 ret = process_header( request, auth_target, auth_header, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, TRUE ); 01355 01356 heap_free( auth_data ); 01357 heap_free( auth_header ); 01358 return ret; 01359 } 01360 01361 /*********************************************************************** 01362 * WinHttpSetCredentials (winhttp.@) 01363 */ 01364 BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD scheme, LPCWSTR username, 01365 LPCWSTR password, LPVOID params ) 01366 { 01367 BOOL ret; 01368 request_t *request; 01369 01370 TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params); 01371 01372 if (!(request = (request_t *)grab_object( hrequest ))) 01373 { 01374 set_last_error( ERROR_INVALID_HANDLE ); 01375 return FALSE; 01376 } 01377 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 01378 { 01379 release_object( &request->hdr ); 01380 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 01381 return FALSE; 01382 } 01383 01384 ret = set_credentials( request, target, scheme, username, password ); 01385 01386 release_object( &request->hdr ); 01387 return ret; 01388 } 01389 01390 static BOOL handle_authorization( request_t *request, DWORD status ) 01391 { 01392 DWORD schemes, level, target; 01393 const WCHAR *username, *password; 01394 01395 switch (status) 01396 { 01397 case 401: 01398 target = WINHTTP_AUTH_TARGET_SERVER; 01399 level = WINHTTP_QUERY_WWW_AUTHENTICATE; 01400 break; 01401 01402 case 407: 01403 target = WINHTTP_AUTH_TARGET_PROXY; 01404 level = WINHTTP_QUERY_PROXY_AUTHENTICATE; 01405 break; 01406 01407 default: 01408 WARN("unhandled status %u\n", status); 01409 return FALSE; 01410 } 01411 01412 if (!query_auth_schemes( request, level, &schemes, NULL )) return FALSE; 01413 01414 if (target == WINHTTP_AUTH_TARGET_SERVER) 01415 { 01416 username = request->connect->username; 01417 password = request->connect->password; 01418 } 01419 else 01420 { 01421 username = request->connect->session->proxy_username; 01422 password = request->connect->session->proxy_password; 01423 } 01424 01425 if (schemes & WINHTTP_AUTH_SCHEME_BASIC) 01426 return set_credentials( request, target, WINHTTP_AUTH_SCHEME_BASIC, username, password ); 01427 01428 FIXME("unsupported authentication scheme\n"); 01429 return FALSE; 01430 } 01431 01432 static void clear_response_headers( request_t *request ) 01433 { 01434 unsigned int i; 01435 01436 for (i = 0; i < request->num_headers; i++) 01437 { 01438 if (!request->headers[i].field) continue; 01439 if (!request->headers[i].value) continue; 01440 if (request->headers[i].is_request) continue; 01441 delete_header( request, i ); 01442 i--; 01443 } 01444 } 01445 01446 #define MAX_REPLY_LEN 1460 01447 #define INITIAL_HEADER_BUFFER_LEN 512 01448 01449 static BOOL read_reply( request_t *request ) 01450 { 01451 static const WCHAR crlf[] = {'\r','\n',0}; 01452 01453 char buffer[MAX_REPLY_LEN]; 01454 DWORD buflen, len, offset, received_len, crlf_len = 2; /* strlenW(crlf) */ 01455 char *status_code, *status_text; 01456 WCHAR *versionW, *status_textW, *raw_headers; 01457 WCHAR status_codeW[4]; /* sizeof("nnn") */ 01458 01459 if (!netconn_connected( &request->netconn )) return FALSE; 01460 01461 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); 01462 01463 received_len = 0; 01464 do 01465 { 01466 buflen = MAX_REPLY_LEN; 01467 if (!netconn_get_next_line( &request->netconn, buffer, &buflen )) return FALSE; 01468 received_len += buflen; 01469 01470 /* first line should look like 'HTTP/1.x nnn OK' where nnn is the status code */ 01471 if (!(status_code = strchr( buffer, ' ' ))) return FALSE; 01472 status_code++; 01473 if (!(status_text = strchr( status_code, ' ' ))) return FALSE; 01474 if ((len = status_text - status_code) != sizeof("nnn") - 1) return FALSE; 01475 status_text++; 01476 01477 TRACE("version [%s] status code [%s] status text [%s]\n", 01478 debugstr_an(buffer, status_code - buffer - 1), 01479 debugstr_an(status_code, len), 01480 debugstr_a(status_text)); 01481 01482 } while (!memcmp( status_code, "100", len )); /* ignore "100 Continue" responses */ 01483 01484 /* we rely on the fact that the protocol is ascii */ 01485 MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len ); 01486 status_codeW[len] = 0; 01487 if (!(process_header( request, attr_status, status_codeW, WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) return FALSE; 01488 01489 len = status_code - buffer; 01490 if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; 01491 MultiByteToWideChar( CP_ACP, 0, buffer, len - 1, versionW, len -1 ); 01492 versionW[len - 1] = 0; 01493 01494 heap_free( request->version ); 01495 request->version = versionW; 01496 01497 len = buflen - (status_text - buffer); 01498 if (!(status_textW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; 01499 MultiByteToWideChar( CP_ACP, 0, status_text, len, status_textW, len ); 01500 01501 heap_free( request->status_text ); 01502 request->status_text = status_textW; 01503 01504 len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN ); 01505 if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; 01506 MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen ); 01507 memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) ); 01508 01509 heap_free( request->raw_headers ); 01510 request->raw_headers = raw_headers; 01511 01512 offset = buflen + crlf_len - 1; 01513 for (;;) 01514 { 01515 header_t *header; 01516 01517 buflen = MAX_REPLY_LEN; 01518 if (!netconn_get_next_line( &request->netconn, buffer, &buflen )) goto end; 01519 received_len += buflen; 01520 if (!*buffer) break; 01521 01522 while (len - offset < buflen + crlf_len) 01523 { 01524 WCHAR *tmp; 01525 len *= 2; 01526 if (!(tmp = heap_realloc( raw_headers, len * sizeof(WCHAR) ))) return FALSE; 01527 request->raw_headers = raw_headers = tmp; 01528 } 01529 MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen ); 01530 01531 if (!(header = parse_header( raw_headers + offset ))) break; 01532 if (!(process_header( request, header->field, header->value, WINHTTP_ADDREQ_FLAG_ADD, FALSE ))) 01533 { 01534 free_header( header ); 01535 break; 01536 } 01537 free_header( header ); 01538 memcpy( raw_headers + offset + buflen - 1, crlf, sizeof(crlf) ); 01539 offset += buflen + crlf_len - 1; 01540 } 01541 01542 TRACE("raw headers: %s\n", debugstr_w(raw_headers)); 01543 01544 end: 01545 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &received_len, sizeof(DWORD) ); 01546 return TRUE; 01547 } 01548 01549 static BOOL handle_redirect( request_t *request ) 01550 { 01551 BOOL ret = FALSE; 01552 DWORD size, len; 01553 URL_COMPONENTS uc; 01554 connect_t *connect = request->connect; 01555 INTERNET_PORT port; 01556 WCHAR *hostname = NULL, *location = NULL; 01557 int index; 01558 01559 size = 0; 01560 query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL ); 01561 if (!(location = heap_alloc( size ))) return FALSE; 01562 if (!query_headers( request, WINHTTP_QUERY_LOCATION, NULL, location, &size, NULL )) goto end; 01563 01564 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, size / sizeof(WCHAR) + 1 ); 01565 01566 memset( &uc, 0, sizeof(uc) ); 01567 uc.dwStructSize = sizeof(uc); 01568 uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = ~0u; 01569 01570 if (!WinHttpCrackUrl( location, size / sizeof(WCHAR), 0, &uc )) /* assume relative redirect */ 01571 { 01572 WCHAR *path, *p; 01573 01574 len = strlenW( location ) + 1; 01575 if (location[0] != '/') len++; 01576 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end; 01577 01578 if (location[0] != '/') *p++ = '/'; 01579 strcpyW( p, location ); 01580 01581 heap_free( request->path ); 01582 request->path = path; 01583 } 01584 else 01585 { 01586 if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE) 01587 { 01588 TRACE("redirect from secure page to non-secure page\n"); 01589 request->hdr.flags &= ~WINHTTP_FLAG_SECURE; 01590 } 01591 else if (uc.nScheme == INTERNET_SCHEME_HTTPS && !(request->hdr.flags & WINHTTP_FLAG_SECURE)) 01592 { 01593 TRACE("redirect from non-secure page to secure page\n"); 01594 request->hdr.flags |= WINHTTP_FLAG_SECURE; 01595 } 01596 01597 len = uc.dwHostNameLength; 01598 if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; 01599 memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) ); 01600 hostname[len] = 0; 01601 01602 port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80); 01603 if (strcmpiW( connect->hostname, hostname ) || connect->serverport != port) 01604 { 01605 heap_free( connect->hostname ); 01606 connect->hostname = hostname; 01607 connect->hostport = port; 01608 if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end; 01609 01610 netconn_close( &request->netconn ); 01611 if (!(ret = netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE ))) goto end; 01612 } 01613 if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; 01614 if (!(ret = open_connection( request ))) goto end; 01615 01616 heap_free( request->path ); 01617 request->path = NULL; 01618 if (uc.dwUrlPathLength) 01619 { 01620 len = uc.dwUrlPathLength + uc.dwExtraInfoLength; 01621 if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; 01622 strcpyW( request->path, uc.lpszUrlPath ); 01623 } 01624 else request->path = strdupW( slashW ); 01625 } 01626 01627 /* remove content-type/length headers */ 01628 if ((index = get_header_index( request, attr_content_type, 0, TRUE )) >= 0) delete_header( request, index ); 01629 if ((index = get_header_index( request, attr_content_length, 0, TRUE )) >= 0 ) delete_header( request, index ); 01630 01631 /* redirects are always GET requests */ 01632 heap_free( request->verb ); 01633 request->verb = strdupW( getW ); 01634 ret = TRUE; 01635 01636 end: 01637 if (!ret) heap_free( hostname ); 01638 heap_free( location ); 01639 return ret; 01640 } 01641 01642 static BOOL receive_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) 01643 { 01644 DWORD to_read; 01645 int bytes_read; 01646 01647 to_read = min( size, request->content_length - request->content_read ); 01648 if (!netconn_recv( &request->netconn, buffer, to_read, async ? 0 : MSG_WAITALL, &bytes_read )) 01649 { 01650 if (bytes_read != to_read) 01651 { 01652 ERR("not all data received %d/%d\n", bytes_read, to_read); 01653 } 01654 /* always return success, even if the network layer returns an error */ 01655 *read = 0; 01656 return TRUE; 01657 } 01658 request->content_read += bytes_read; 01659 *read = bytes_read; 01660 return TRUE; 01661 } 01662 01663 static DWORD get_chunk_size( const char *buffer ) 01664 { 01665 const char *p; 01666 DWORD size = 0; 01667 01668 for (p = buffer; *p; p++) 01669 { 01670 if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0'; 01671 else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10; 01672 else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10; 01673 else if (*p == ';') break; 01674 } 01675 return size; 01676 } 01677 01678 static BOOL receive_data_chunked( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) 01679 { 01680 char reply[MAX_REPLY_LEN], *p = buffer; 01681 DWORD buflen, to_read, to_write = size; 01682 int bytes_read; 01683 01684 *read = 0; 01685 for (;;) 01686 { 01687 if (*read == size) break; 01688 01689 if (request->content_length == ~0u) /* new chunk */ 01690 { 01691 buflen = sizeof(reply); 01692 if (!netconn_get_next_line( &request->netconn, reply, &buflen )) break; 01693 01694 if (!(request->content_length = get_chunk_size( reply ))) 01695 { 01696 /* zero sized chunk marks end of transfer; read any trailing headers and return */ 01697 read_reply( request ); 01698 break; 01699 } 01700 } 01701 to_read = min( to_write, request->content_length - request->content_read ); 01702 01703 if (!netconn_recv( &request->netconn, p, to_read, async ? 0 : MSG_WAITALL, &bytes_read )) 01704 { 01705 if (bytes_read != to_read) 01706 { 01707 ERR("Not all data received %d/%d\n", bytes_read, to_read); 01708 } 01709 /* always return success, even if the network layer returns an error */ 01710 *read = 0; 01711 break; 01712 } 01713 if (!bytes_read) break; 01714 01715 request->content_read += bytes_read; 01716 to_write -= bytes_read; 01717 *read += bytes_read; 01718 p += bytes_read; 01719 01720 if (request->content_read == request->content_length) /* chunk complete */ 01721 { 01722 request->content_read = 0; 01723 request->content_length = ~0u; 01724 01725 buflen = sizeof(reply); 01726 if (!netconn_get_next_line( &request->netconn, reply, &buflen )) 01727 { 01728 ERR("Malformed chunk\n"); 01729 *read = 0; 01730 break; 01731 } 01732 } 01733 } 01734 return TRUE; 01735 } 01736 01737 static void finished_reading( request_t *request ) 01738 { 01739 static const WCHAR closeW[] = {'c','l','o','s','e',0}; 01740 01741 BOOL close = FALSE; 01742 WCHAR connection[20]; 01743 DWORD size = sizeof(connection); 01744 01745 if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE; 01746 else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) || 01747 query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL )) 01748 { 01749 if (!strcmpiW( connection, closeW )) close = TRUE; 01750 } 01751 else if (!strcmpW( request->version, http1_0 )) close = TRUE; 01752 01753 if (close) close_connection( request ); 01754 request->content_length = ~0u; 01755 request->content_read = 0; 01756 } 01757 01758 static BOOL read_data( request_t *request, void *buffer, DWORD to_read, DWORD *read, BOOL async ) 01759 { 01760 static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0}; 01761 01762 BOOL ret; 01763 WCHAR encoding[20]; 01764 DWORD num_bytes, buflen = sizeof(encoding); 01765 01766 if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) && 01767 !strcmpiW( encoding, chunked )) 01768 { 01769 ret = receive_data_chunked( request, buffer, to_read, &num_bytes, async ); 01770 } 01771 else 01772 ret = receive_data( request, buffer, to_read, &num_bytes, async ); 01773 01774 if (async) 01775 { 01776 if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, num_bytes ); 01777 else 01778 { 01779 WINHTTP_ASYNC_RESULT result; 01780 result.dwResult = API_READ_DATA; 01781 result.dwError = get_last_error(); 01782 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); 01783 } 01784 } 01785 if (ret) 01786 { 01787 if (read) *read = num_bytes; 01788 if (!num_bytes) finished_reading( request ); 01789 } 01790 return ret; 01791 } 01792 01793 /* read any content returned by the server so that the connection can be reused */ 01794 static void drain_content( request_t *request ) 01795 { 01796 DWORD bytes_read; 01797 char buffer[2048]; 01798 01799 if (!request->content_length) return; 01800 for (;;) 01801 { 01802 if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return; 01803 } 01804 } 01805 01806 static void record_cookies( request_t *request ) 01807 { 01808 unsigned int i; 01809 01810 for (i = 0; i < request->num_headers; i++) 01811 { 01812 header_t *set_cookie = &request->headers[i]; 01813 if (!strcmpiW( set_cookie->field, attr_set_cookie ) && !set_cookie->is_request) 01814 { 01815 set_cookies( request, set_cookie->value ); 01816 } 01817 } 01818 } 01819 01820 static BOOL receive_response( request_t *request, BOOL async ) 01821 { 01822 BOOL ret; 01823 DWORD size, query, status; 01824 01825 for (;;) 01826 { 01827 if (!(ret = read_reply( request ))) break; 01828 01829 size = sizeof(DWORD); 01830 query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; 01831 if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break; 01832 01833 size = sizeof(DWORD); 01834 query = WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER; 01835 if (!query_headers( request, query, NULL, &request->content_length, &size, NULL )) 01836 request->content_length = ~0u; 01837 01838 if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request ); 01839 01840 if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB) 01841 { 01842 if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS) break; 01843 01844 drain_content( request ); 01845 if (!(ret = handle_redirect( request ))) break; 01846 01847 clear_response_headers( request ); 01848 ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); /* recurse synchronously */ 01849 continue; 01850 } 01851 else if (status == 401 || status == 407) 01852 { 01853 if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break; 01854 01855 drain_content( request ); 01856 if (!handle_authorization( request, status )) 01857 { 01858 ret = TRUE; 01859 break; 01860 } 01861 clear_response_headers( request ); 01862 ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); 01863 continue; 01864 } 01865 break; 01866 } 01867 01868 if (async) 01869 { 01870 if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 ); 01871 else 01872 { 01873 WINHTTP_ASYNC_RESULT result; 01874 result.dwResult = API_RECEIVE_RESPONSE; 01875 result.dwError = get_last_error(); 01876 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); 01877 } 01878 } 01879 return ret; 01880 } 01881 01882 static void task_receive_response( task_header_t *task ) 01883 { 01884 receive_response_t *r = (receive_response_t *)task; 01885 receive_response( r->hdr.request, TRUE ); 01886 } 01887 01888 /*********************************************************************** 01889 * WinHttpReceiveResponse (winhttp.@) 01890 */ 01891 BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) 01892 { 01893 BOOL ret; 01894 request_t *request; 01895 01896 TRACE("%p, %p\n", hrequest, reserved); 01897 01898 if (!(request = (request_t *)grab_object( hrequest ))) 01899 { 01900 set_last_error( ERROR_INVALID_HANDLE ); 01901 return FALSE; 01902 } 01903 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 01904 { 01905 release_object( &request->hdr ); 01906 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 01907 return FALSE; 01908 } 01909 01910 if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) 01911 { 01912 receive_response_t *r; 01913 01914 if (!(r = heap_alloc( sizeof(receive_response_t) ))) return FALSE; 01915 r->hdr.request = request; 01916 r->hdr.proc = task_receive_response; 01917 01918 addref_object( &request->hdr ); 01919 ret = queue_task( (task_header_t *)r ); 01920 } 01921 else 01922 ret = receive_response( request, FALSE ); 01923 01924 release_object( &request->hdr ); 01925 return ret; 01926 } 01927 01928 static BOOL query_data( request_t *request, LPDWORD available, BOOL async ) 01929 { 01930 BOOL ret; 01931 DWORD num_bytes; 01932 01933 if ((ret = netconn_query_data_available( &request->netconn, &num_bytes ))) 01934 { 01935 if (request->content_read < request->content_length) 01936 { 01937 if (!num_bytes) 01938 { 01939 char buffer[4096]; 01940 size_t to_read = min( sizeof(buffer), request->content_length - request->content_read ); 01941 01942 ret = netconn_recv( &request->netconn, buffer, to_read, MSG_PEEK, (int *)&num_bytes ); 01943 if (ret && !num_bytes) WARN("expected more data to be available\n"); 01944 } 01945 } 01946 else if (num_bytes) 01947 { 01948 WARN("extra data available %u\n", num_bytes); 01949 ret = FALSE; 01950 } 01951 } 01952 TRACE("%u bytes available\n", num_bytes); 01953 01954 if (async) 01955 { 01956 if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, &num_bytes, sizeof(DWORD) ); 01957 else 01958 { 01959 WINHTTP_ASYNC_RESULT result; 01960 result.dwResult = API_QUERY_DATA_AVAILABLE; 01961 result.dwError = get_last_error(); 01962 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); 01963 } 01964 } 01965 if (ret && available) *available = num_bytes; 01966 return ret; 01967 } 01968 01969 static void task_query_data( task_header_t *task ) 01970 { 01971 query_data_t *q = (query_data_t *)task; 01972 query_data( q->hdr.request, q->available, TRUE ); 01973 } 01974 01975 /*********************************************************************** 01976 * WinHttpQueryDataAvailable (winhttp.@) 01977 */ 01978 BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) 01979 { 01980 BOOL ret; 01981 request_t *request; 01982 01983 TRACE("%p, %p\n", hrequest, available); 01984 01985 if (!(request = (request_t *)grab_object( hrequest ))) 01986 { 01987 set_last_error( ERROR_INVALID_HANDLE ); 01988 return FALSE; 01989 } 01990 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 01991 { 01992 release_object( &request->hdr ); 01993 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 01994 return FALSE; 01995 } 01996 01997 if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) 01998 { 01999 query_data_t *q; 02000 02001 if (!(q = heap_alloc( sizeof(query_data_t) ))) return FALSE; 02002 q->hdr.request = request; 02003 q->hdr.proc = task_query_data; 02004 q->available = available; 02005 02006 addref_object( &request->hdr ); 02007 ret = queue_task( (task_header_t *)q ); 02008 } 02009 else 02010 ret = query_data( request, available, FALSE ); 02011 02012 release_object( &request->hdr ); 02013 return ret; 02014 } 02015 02016 static void task_read_data( task_header_t *task ) 02017 { 02018 read_data_t *r = (read_data_t *)task; 02019 read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE ); 02020 } 02021 02022 /*********************************************************************** 02023 * WinHttpReadData (winhttp.@) 02024 */ 02025 BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, LPDWORD read ) 02026 { 02027 BOOL ret; 02028 request_t *request; 02029 02030 TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read); 02031 02032 if (!(request = (request_t *)grab_object( hrequest ))) 02033 { 02034 set_last_error( ERROR_INVALID_HANDLE ); 02035 return FALSE; 02036 } 02037 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 02038 { 02039 release_object( &request->hdr ); 02040 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 02041 return FALSE; 02042 } 02043 02044 if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) 02045 { 02046 read_data_t *r; 02047 02048 if (!(r = heap_alloc( sizeof(read_data_t) ))) return FALSE; 02049 r->hdr.request = request; 02050 r->hdr.proc = task_read_data; 02051 r->buffer = buffer; 02052 r->to_read = to_read; 02053 r->read = read; 02054 02055 addref_object( &request->hdr ); 02056 ret = queue_task( (task_header_t *)r ); 02057 } 02058 else 02059 ret = read_data( request, buffer, to_read, read, FALSE ); 02060 02061 release_object( &request->hdr ); 02062 return ret; 02063 } 02064 02065 static BOOL write_data( request_t *request, LPCVOID buffer, DWORD to_write, LPDWORD written, BOOL async ) 02066 { 02067 BOOL ret; 02068 int num_bytes; 02069 02070 ret = netconn_send( &request->netconn, buffer, to_write, 0, &num_bytes ); 02071 02072 if (async) 02073 { 02074 if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &num_bytes, sizeof(DWORD) ); 02075 else 02076 { 02077 WINHTTP_ASYNC_RESULT result; 02078 result.dwResult = API_WRITE_DATA; 02079 result.dwError = get_last_error(); 02080 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); 02081 } 02082 } 02083 if (ret && written) *written = num_bytes; 02084 return ret; 02085 } 02086 02087 static void task_write_data( task_header_t *task ) 02088 { 02089 write_data_t *w = (write_data_t *)task; 02090 write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE ); 02091 } 02092 02093 /*********************************************************************** 02094 * WinHttpWriteData (winhttp.@) 02095 */ 02096 BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write, LPDWORD written ) 02097 { 02098 BOOL ret; 02099 request_t *request; 02100 02101 TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_write, written); 02102 02103 if (!(request = (request_t *)grab_object( hrequest ))) 02104 { 02105 set_last_error( ERROR_INVALID_HANDLE ); 02106 return FALSE; 02107 } 02108 if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) 02109 { 02110 release_object( &request->hdr ); 02111 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); 02112 return FALSE; 02113 } 02114 02115 if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) 02116 { 02117 write_data_t *w; 02118 02119 if (!(w = heap_alloc( sizeof(write_data_t) ))) return FALSE; 02120 w->hdr.request = request; 02121 w->hdr.proc = task_write_data; 02122 w->buffer = buffer; 02123 w->to_write = to_write; 02124 w->written = written; 02125 02126 addref_object( &request->hdr ); 02127 ret = queue_task( (task_header_t *)w ); 02128 } 02129 else 02130 ret = write_data( request, buffer, to_write, written, FALSE ); 02131 02132 release_object( &request->hdr ); 02133 return ret; 02134 } Generated on Sun May 27 2012 04:26:56 for ReactOS by
1.7.6.1
|