Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhttp.c
Go to the documentation of this file.
00001 /* 00002 * Wininet - Http Implementation 00003 * 00004 * Copyright 1999 Corel Corporation 00005 * Copyright 2002 CodeWeavers Inc. 00006 * Copyright 2002 TransGaming Technologies Inc. 00007 * Copyright 2004 Mike McCormack for CodeWeavers 00008 * Copyright 2005 Aric Stewart for CodeWeavers 00009 * Copyright 2006 Robert Shearman for CodeWeavers 00010 * Copyright 2011 Jacek Caban for CodeWeavers 00011 * 00012 * Ulrich Czekalla 00013 * David Hammerton 00014 * 00015 * This library is free software; you can redistribute it and/or 00016 * modify it under the terms of the GNU Lesser General Public 00017 * License as published by the Free Software Foundation; either 00018 * version 2.1 of the License, or (at your option) any later version. 00019 * 00020 * This library is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00023 * Lesser General Public License for more details. 00024 * 00025 * You should have received a copy of the GNU Lesser General Public 00026 * License along with this library; if not, write to the Free Software 00027 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00028 */ 00029 00030 #include "config.h" 00031 #include "wine/port.h" 00032 00033 #if defined(__MINGW32__) || defined (_MSC_VER) 00034 #include <ws2tcpip.h> 00035 #endif 00036 00037 #include <sys/types.h> 00038 #ifdef HAVE_SYS_SOCKET_H 00039 # include <sys/socket.h> 00040 #endif 00041 #ifdef HAVE_ARPA_INET_H 00042 # include <arpa/inet.h> 00043 #endif 00044 #include <stdarg.h> 00045 #include <stdio.h> 00046 #include <stdlib.h> 00047 #ifdef HAVE_UNISTD_H 00048 # include <unistd.h> 00049 #endif 00050 #include <time.h> 00051 #include <assert.h> 00052 #ifdef HAVE_ZLIB 00053 # include <zlib.h> 00054 #endif 00055 00056 #include "windef.h" 00057 #include "winbase.h" 00058 #include "wininet.h" 00059 #include "winerror.h" 00060 #include "winternl.h" 00061 #define NO_SHLWAPI_STREAM 00062 #define NO_SHLWAPI_REG 00063 #define NO_SHLWAPI_STRFCNS 00064 #define NO_SHLWAPI_GDI 00065 #include "shlwapi.h" 00066 #include "sspi.h" 00067 #include "wincrypt.h" 00068 00069 #include "internet.h" 00070 #include "wine/debug.h" 00071 #include "wine/exception.h" 00072 #include "wine/unicode.h" 00073 00074 #include "inet_ntop.c" 00075 00076 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 00077 00078 static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0}; 00079 static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0}; 00080 static const WCHAR szOK[] = {'O','K',0}; 00081 static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0}; 00082 static const WCHAR hostW[] = { 'H','o','s','t',0 }; 00083 static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; 00084 static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; 00085 static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 }; 00086 static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; 00087 static const WCHAR szGET[] = { 'G','E','T', 0 }; 00088 static const WCHAR szHEAD[] = { 'H','E','A','D', 0 }; 00089 static const WCHAR szCrLf[] = {'\r','\n', 0}; 00090 00091 static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; 00092 static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; 00093 static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; 00094 static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; 00095 static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; 00096 static const WCHAR szAge[] = { 'A','g','e',0 }; 00097 static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; 00098 static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; 00099 static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; 00100 static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; 00101 static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; 00102 static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; 00103 static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; 00104 static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; 00105 static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; 00106 static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; 00107 static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; 00108 static const WCHAR szContent_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 }; 00109 static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; 00110 static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; 00111 static const WCHAR szDate[] = { 'D','a','t','e',0 }; 00112 static const WCHAR szFrom[] = { 'F','r','o','m',0 }; 00113 static const WCHAR szETag[] = { 'E','T','a','g',0 }; 00114 static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; 00115 static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; 00116 static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; 00117 static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; 00118 static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; 00119 static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; 00120 static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; 00121 static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; 00122 static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; 00123 static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; 00124 static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; 00125 static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; 00126 static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; 00127 static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; 00128 static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; 00129 static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; 00130 static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; 00131 static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; 00132 static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; 00133 static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; 00134 static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; 00135 static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; 00136 static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; 00137 static const WCHAR szURI[] = { 'U','R','I',0 }; 00138 static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; 00139 static const WCHAR szVary[] = { 'V','a','r','y',0 }; 00140 static const WCHAR szVia[] = { 'V','i','a',0 }; 00141 static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; 00142 static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; 00143 00144 #define MAXHOSTNAME 100 00145 #define MAX_FIELD_VALUE_LEN 256 00146 #define MAX_FIELD_LEN 256 00147 00148 #define HTTP_REFERER szReferer 00149 #define HTTP_ACCEPT szAccept 00150 #define HTTP_USERAGENT szUser_Agent 00151 00152 #define HTTP_ADDHDR_FLAG_ADD 0x20000000 00153 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000 00154 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000 00155 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000 00156 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000 00157 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000 00158 #define HTTP_ADDHDR_FLAG_REQ 0x02000000 00159 00160 #define COLLECT_TIME 60000 00161 00162 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0])) 00163 00164 struct HttpAuthInfo 00165 { 00166 LPWSTR scheme; 00167 CredHandle cred; 00168 CtxtHandle ctx; 00169 TimeStamp exp; 00170 ULONG attr; 00171 ULONG max_token; 00172 void *auth_data; 00173 unsigned int auth_data_len; 00174 BOOL finished; /* finished authenticating */ 00175 }; 00176 00177 00178 typedef struct _basicAuthorizationData 00179 { 00180 struct list entry; 00181 00182 LPWSTR host; 00183 LPWSTR realm; 00184 LPSTR authorization; 00185 UINT authorizationLen; 00186 } basicAuthorizationData; 00187 00188 typedef struct _authorizationData 00189 { 00190 struct list entry; 00191 00192 LPWSTR host; 00193 LPWSTR scheme; 00194 LPWSTR domain; 00195 UINT domain_len; 00196 LPWSTR user; 00197 UINT user_len; 00198 LPWSTR password; 00199 UINT password_len; 00200 } authorizationData; 00201 00202 static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache); 00203 static struct list authorizationCache = LIST_INIT(authorizationCache); 00204 00205 static CRITICAL_SECTION authcache_cs; 00206 static CRITICAL_SECTION_DEBUG critsect_debug = 00207 { 00208 0, 0, &authcache_cs, 00209 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00210 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") } 00211 }; 00212 static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; 00213 00214 static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); 00215 static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); 00216 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); 00217 static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); 00218 static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request); 00219 static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index); 00220 static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); 00221 static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD); 00222 static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl); 00223 static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); 00224 static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field); 00225 00226 static CRITICAL_SECTION connection_pool_cs; 00227 static CRITICAL_SECTION_DEBUG connection_pool_debug = 00228 { 00229 0, 0, &connection_pool_cs, 00230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00231 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") } 00232 }; 00233 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 }; 00234 00235 static struct list connection_pool = LIST_INIT(connection_pool); 00236 static BOOL collector_running; 00237 00238 void server_addref(server_t *server) 00239 { 00240 InterlockedIncrement(&server->ref); 00241 } 00242 00243 void server_release(server_t *server) 00244 { 00245 if(InterlockedDecrement(&server->ref)) 00246 return; 00247 00248 #ifndef __REACTOS__ 00249 if(!server->ref) 00250 server->keep_until = (DWORD64)GetTickCount() + COLLECT_TIME; 00251 #else 00252 EnterCriticalSection(&connection_pool_cs); 00253 list_remove(&server->entry); 00254 LeaveCriticalSection(&connection_pool_cs); 00255 00256 heap_free(server->name); 00257 heap_free(server); 00258 #endif 00259 } 00260 00261 static server_t *get_server(const WCHAR *name, INTERNET_PORT port) 00262 { 00263 server_t *iter, *server = NULL; 00264 00265 EnterCriticalSection(&connection_pool_cs); 00266 00267 LIST_FOR_EACH_ENTRY(iter, &connection_pool, server_t, entry) { 00268 if(iter->port == port && !strcmpW(iter->name, name)) { 00269 server = iter; 00270 server_addref(server); 00271 break; 00272 } 00273 } 00274 00275 if(!server) { 00276 server = heap_alloc(sizeof(*server)); 00277 if(server) { 00278 server->addr_len = 0; 00279 server->ref = 1; 00280 server->port = port; 00281 list_init(&server->conn_pool); 00282 server->name = heap_strdupW(name); 00283 if(server->name) { 00284 list_add_head(&connection_pool, &server->entry); 00285 }else { 00286 heap_free(server); 00287 server = NULL; 00288 } 00289 } 00290 } 00291 00292 LeaveCriticalSection(&connection_pool_cs); 00293 00294 return server; 00295 } 00296 00297 BOOL collect_connections(BOOL collect_all) 00298 { 00299 netconn_t *netconn, *netconn_safe; 00300 server_t *server, *server_safe; 00301 BOOL remaining = FALSE; 00302 DWORD64 now; 00303 00304 now = GetTickCount(); 00305 00306 LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) { 00307 LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) { 00308 if(collect_all || netconn->keep_until < now) { 00309 TRACE("freeing %p\n", netconn); 00310 list_remove(&netconn->pool_entry); 00311 free_netconn(netconn); 00312 }else { 00313 remaining = TRUE; 00314 } 00315 } 00316 00317 if(!server->ref) { 00318 if(collect_all || server->keep_until < now) { 00319 list_remove(&server->entry); 00320 00321 heap_free(server->name); 00322 heap_free(server); 00323 }else { 00324 remaining = TRUE; 00325 } 00326 } 00327 } 00328 00329 return remaining; 00330 } 00331 00332 static DWORD WINAPI collect_connections_proc(void *arg) 00333 { 00334 BOOL remaining_conns; 00335 00336 do { 00337 /* FIXME: Use more sophisticated method */ 00338 Sleep(5000); 00339 00340 EnterCriticalSection(&connection_pool_cs); 00341 00342 remaining_conns = collect_connections(FALSE); 00343 if(!remaining_conns) 00344 collector_running = FALSE; 00345 00346 LeaveCriticalSection(&connection_pool_cs); 00347 }while(remaining_conns); 00348 00349 FreeLibraryAndExitThread(WININET_hModule, 0); 00350 } 00351 00352 static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) 00353 { 00354 int HeaderIndex = 0; 00355 HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE); 00356 if (HeaderIndex == -1) 00357 return NULL; 00358 else 00359 return &req->custHeaders[HeaderIndex]; 00360 } 00361 00362 typedef enum { 00363 READMODE_SYNC, 00364 READMODE_ASYNC, 00365 READMODE_NOBLOCK 00366 } read_mode_t; 00367 00368 struct data_stream_vtbl_t { 00369 DWORD (*get_avail_data)(data_stream_t*,http_request_t*); 00370 BOOL (*end_of_data)(data_stream_t*,http_request_t*); 00371 DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,read_mode_t); 00372 BOOL (*drain_content)(data_stream_t*,http_request_t*); 00373 void (*destroy)(data_stream_t*); 00374 }; 00375 00376 typedef struct { 00377 data_stream_t data_stream; 00378 00379 BYTE buf[READ_BUFFER_SIZE]; 00380 DWORD buf_size; 00381 DWORD buf_pos; 00382 DWORD chunk_size; 00383 } chunked_stream_t; 00384 00385 static inline void destroy_data_stream(data_stream_t *stream) 00386 { 00387 stream->vtbl->destroy(stream); 00388 } 00389 00390 static void reset_data_stream(http_request_t *req) 00391 { 00392 destroy_data_stream(req->data_stream); 00393 req->data_stream = &req->netconn_stream.data_stream; 00394 req->read_pos = req->read_size = req->netconn_stream.content_read = 0; 00395 req->read_chunked = req->read_gzip = FALSE; 00396 } 00397 00398 #ifdef HAVE_ZLIB 00399 00400 typedef struct { 00401 data_stream_t stream; 00402 data_stream_t *parent_stream; 00403 z_stream zstream; 00404 BYTE buf[READ_BUFFER_SIZE]; 00405 DWORD buf_size; 00406 DWORD buf_pos; 00407 BOOL end_of_data; 00408 } gzip_stream_t; 00409 00410 static DWORD gzip_get_avail_data(data_stream_t *stream, http_request_t *req) 00411 { 00412 /* Allow reading only from read buffer */ 00413 return 0; 00414 } 00415 00416 static BOOL gzip_end_of_data(data_stream_t *stream, http_request_t *req) 00417 { 00418 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; 00419 return gzip_stream->end_of_data; 00420 } 00421 00422 static DWORD gzip_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, 00423 DWORD *read, read_mode_t read_mode) 00424 { 00425 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; 00426 z_stream *zstream = &gzip_stream->zstream; 00427 DWORD current_read, ret_read = 0; 00428 BOOL end; 00429 int zres; 00430 DWORD res = ERROR_SUCCESS; 00431 00432 while(size && !gzip_stream->end_of_data) { 00433 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req); 00434 00435 if(gzip_stream->buf_size <= 64 && !end) { 00436 if(gzip_stream->buf_pos) { 00437 if(gzip_stream->buf_size) 00438 memmove(gzip_stream->buf, gzip_stream->buf+gzip_stream->buf_pos, gzip_stream->buf_size); 00439 gzip_stream->buf_pos = 0; 00440 } 00441 res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size, 00442 sizeof(gzip_stream->buf)-gzip_stream->buf_size, ¤t_read, read_mode); 00443 gzip_stream->buf_size += current_read; 00444 if(res != ERROR_SUCCESS) 00445 break; 00446 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req); 00447 if(!current_read && !end) { 00448 if(read_mode != READMODE_NOBLOCK) { 00449 WARN("unexpected end of data\n"); 00450 gzip_stream->end_of_data = TRUE; 00451 } 00452 break; 00453 } 00454 if(gzip_stream->buf_size <= 64 && !end) 00455 continue; 00456 } 00457 00458 zstream->next_in = gzip_stream->buf+gzip_stream->buf_pos; 00459 zstream->avail_in = gzip_stream->buf_size-(end ? 0 : 64); 00460 zstream->next_out = buf+ret_read; 00461 zstream->avail_out = size; 00462 zres = inflate(&gzip_stream->zstream, 0); 00463 current_read = size - zstream->avail_out; 00464 size -= current_read; 00465 ret_read += current_read; 00466 gzip_stream->buf_size -= zstream->next_in - (gzip_stream->buf+gzip_stream->buf_pos); 00467 gzip_stream->buf_pos = zstream->next_in-gzip_stream->buf; 00468 if(zres == Z_STREAM_END) { 00469 TRACE("end of data\n"); 00470 gzip_stream->end_of_data = TRUE; 00471 inflateEnd(zstream); 00472 }else if(zres != Z_OK) { 00473 WARN("inflate failed %d: %s\n", zres, debugstr_a(zstream->msg)); 00474 if(!ret_read) 00475 res = ERROR_INTERNET_DECODING_FAILED; 00476 break; 00477 } 00478 00479 if(ret_read && read_mode == READMODE_ASYNC) 00480 read_mode = READMODE_NOBLOCK; 00481 } 00482 00483 TRACE("read %u bytes\n", ret_read); 00484 *read = ret_read; 00485 return res; 00486 } 00487 00488 static BOOL gzip_drain_content(data_stream_t *stream, http_request_t *req) 00489 { 00490 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; 00491 return gzip_stream->parent_stream->vtbl->drain_content(gzip_stream->parent_stream, req); 00492 } 00493 00494 static void gzip_destroy(data_stream_t *stream) 00495 { 00496 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; 00497 00498 destroy_data_stream(gzip_stream->parent_stream); 00499 00500 if(!gzip_stream->end_of_data) 00501 inflateEnd(&gzip_stream->zstream); 00502 heap_free(gzip_stream); 00503 } 00504 00505 static const data_stream_vtbl_t gzip_stream_vtbl = { 00506 gzip_get_avail_data, 00507 gzip_end_of_data, 00508 gzip_read, 00509 gzip_drain_content, 00510 gzip_destroy 00511 }; 00512 00513 static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size) 00514 { 00515 return heap_alloc(items*size); 00516 } 00517 00518 static void wininet_zfree(voidpf opaque, voidpf address) 00519 { 00520 HeapFree(GetProcessHeap(), 0, address); 00521 } 00522 00523 static DWORD init_gzip_stream(http_request_t *req) 00524 { 00525 gzip_stream_t *gzip_stream; 00526 int index, zres; 00527 00528 gzip_stream = heap_alloc_zero(sizeof(gzip_stream_t)); 00529 if(!gzip_stream) 00530 return ERROR_OUTOFMEMORY; 00531 00532 gzip_stream->stream.vtbl = &gzip_stream_vtbl; 00533 gzip_stream->zstream.zalloc = wininet_zalloc; 00534 gzip_stream->zstream.zfree = wininet_zfree; 00535 00536 zres = inflateInit2(&gzip_stream->zstream, 0x1f); 00537 if(zres != Z_OK) { 00538 ERR("inflateInit failed: %d\n", zres); 00539 HeapFree(GetProcessHeap(), 0, gzip_stream); 00540 return ERROR_OUTOFMEMORY; 00541 } 00542 00543 index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE); 00544 if(index != -1) 00545 HTTP_DeleteCustomHeader(req, index); 00546 00547 if(req->read_size) { 00548 memcpy(gzip_stream->buf, req->read_buf+req->read_pos, req->read_size); 00549 gzip_stream->buf_size = req->read_size; 00550 req->read_pos = req->read_size = 0; 00551 } 00552 00553 req->read_gzip = TRUE; 00554 gzip_stream->parent_stream = req->data_stream; 00555 req->data_stream = &gzip_stream->stream; 00556 return ERROR_SUCCESS; 00557 } 00558 00559 #else 00560 00561 static DWORD init_gzip_stream(http_request_t *req) 00562 { 00563 ERR("gzip stream not supported, missing zlib.\n"); 00564 return ERROR_SUCCESS; 00565 } 00566 00567 #endif 00568 00569 /*********************************************************************** 00570 * HTTP_Tokenize (internal) 00571 * 00572 * Tokenize a string, allocating memory for the tokens. 00573 */ 00574 static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) 00575 { 00576 LPWSTR * token_array; 00577 int tokens = 0; 00578 int i; 00579 LPCWSTR next_token; 00580 00581 if (string) 00582 { 00583 /* empty string has no tokens */ 00584 if (*string) 00585 tokens++; 00586 /* count tokens */ 00587 for (i = 0; string[i]; i++) 00588 { 00589 if (!strncmpW(string+i, token_string, strlenW(token_string))) 00590 { 00591 DWORD j; 00592 tokens++; 00593 /* we want to skip over separators, but not the null terminator */ 00594 for (j = 0; j < strlenW(token_string) - 1; j++) 00595 if (!string[i+j]) 00596 break; 00597 i += j; 00598 } 00599 } 00600 } 00601 00602 /* add 1 for terminating NULL */ 00603 token_array = heap_alloc((tokens+1) * sizeof(*token_array)); 00604 token_array[tokens] = NULL; 00605 if (!tokens) 00606 return token_array; 00607 for (i = 0; i < tokens; i++) 00608 { 00609 int len; 00610 next_token = strstrW(string, token_string); 00611 if (!next_token) next_token = string+strlenW(string); 00612 len = next_token - string; 00613 token_array[i] = heap_alloc((len+1)*sizeof(WCHAR)); 00614 memcpy(token_array[i], string, len*sizeof(WCHAR)); 00615 token_array[i][len] = '\0'; 00616 string = next_token+strlenW(token_string); 00617 } 00618 return token_array; 00619 } 00620 00621 /*********************************************************************** 00622 * HTTP_FreeTokens (internal) 00623 * 00624 * Frees memory returned from HTTP_Tokenize. 00625 */ 00626 static void HTTP_FreeTokens(LPWSTR * token_array) 00627 { 00628 int i; 00629 for (i = 0; token_array[i]; i++) 00630 HeapFree(GetProcessHeap(), 0, token_array[i]); 00631 HeapFree(GetProcessHeap(), 0, token_array); 00632 } 00633 00634 static void HTTP_FixURL(http_request_t *request) 00635 { 00636 static const WCHAR szSlash[] = { '/',0 }; 00637 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 }; 00638 00639 /* If we don't have a path we set it to root */ 00640 if (NULL == request->path) 00641 request->path = heap_strdupW(szSlash); 00642 else /* remove \r and \n*/ 00643 { 00644 int nLen = strlenW(request->path); 00645 while ((nLen >0 ) && ((request->path[nLen-1] == '\r')||(request->path[nLen-1] == '\n'))) 00646 { 00647 nLen--; 00648 request->path[nLen]='\0'; 00649 } 00650 /* Replace '\' with '/' */ 00651 while (nLen>0) { 00652 nLen--; 00653 if (request->path[nLen] == '\\') request->path[nLen]='/'; 00654 } 00655 } 00656 00657 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, 00658 request->path, strlenW(request->path), szHttp, strlenW(szHttp) ) 00659 && request->path[0] != '/') /* not an absolute path ?? --> fix it !! */ 00660 { 00661 WCHAR *fixurl = heap_alloc((strlenW(request->path) + 2)*sizeof(WCHAR)); 00662 *fixurl = '/'; 00663 strcpyW(fixurl + 1, request->path); 00664 HeapFree( GetProcessHeap(), 0, request->path ); 00665 request->path = fixurl; 00666 } 00667 } 00668 00669 static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) 00670 { 00671 LPWSTR requestString; 00672 DWORD len, n; 00673 LPCWSTR *req; 00674 UINT i; 00675 LPWSTR p; 00676 00677 static const WCHAR szSpace[] = { ' ',0 }; 00678 static const WCHAR szColon[] = { ':',' ',0 }; 00679 static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; 00680 00681 /* allocate space for an array of all the string pointers to be added */ 00682 len = (request->nCustHeaders)*4 + 10; 00683 req = heap_alloc(len*sizeof(LPCWSTR)); 00684 00685 /* add the verb, path and HTTP version string */ 00686 n = 0; 00687 req[n++] = verb; 00688 req[n++] = szSpace; 00689 req[n++] = path; 00690 req[n++] = szSpace; 00691 req[n++] = version; 00692 00693 /* Append custom request headers */ 00694 for (i = 0; i < request->nCustHeaders; i++) 00695 { 00696 if (request->custHeaders[i].wFlags & HDR_ISREQUEST) 00697 { 00698 req[n++] = szCrLf; 00699 req[n++] = request->custHeaders[i].lpszField; 00700 req[n++] = szColon; 00701 req[n++] = request->custHeaders[i].lpszValue; 00702 00703 TRACE("Adding custom header %s (%s)\n", 00704 debugstr_w(request->custHeaders[i].lpszField), 00705 debugstr_w(request->custHeaders[i].lpszValue)); 00706 } 00707 } 00708 00709 if( n >= len ) 00710 ERR("oops. buffer overrun\n"); 00711 00712 req[n] = NULL; 00713 requestString = HTTP_build_req( req, 4 ); 00714 HeapFree( GetProcessHeap(), 0, req ); 00715 00716 /* 00717 * Set (header) termination string for request 00718 * Make sure there's exactly two new lines at the end of the request 00719 */ 00720 p = &requestString[strlenW(requestString)-1]; 00721 while ( (*p == '\n') || (*p == '\r') ) 00722 p--; 00723 strcpyW( p+1, sztwocrlf ); 00724 00725 return requestString; 00726 } 00727 00728 static void HTTP_ProcessCookies( http_request_t *request ) 00729 { 00730 int HeaderIndex; 00731 int numCookies = 0; 00732 LPHTTPHEADERW setCookieHeader; 00733 00734 if(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) 00735 return; 00736 00737 while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, szSet_Cookie, numCookies++, FALSE)) != -1) 00738 { 00739 HTTPHEADERW *host; 00740 const WCHAR *data; 00741 WCHAR *name; 00742 00743 setCookieHeader = &request->custHeaders[HeaderIndex]; 00744 00745 if (!setCookieHeader->lpszValue) 00746 continue; 00747 00748 host = HTTP_GetHeader(request, hostW); 00749 if(!host) 00750 continue; 00751 00752 data = strchrW(setCookieHeader->lpszValue, '='); 00753 if(!data) 00754 continue; 00755 00756 name = heap_strndupW(setCookieHeader->lpszValue, data-setCookieHeader->lpszValue); 00757 if(!name) 00758 continue; 00759 00760 data++; 00761 set_cookie(host->lpszValue, request->path, name, data); 00762 heap_free(name); 00763 } 00764 } 00765 00766 static void strip_spaces(LPWSTR start) 00767 { 00768 LPWSTR str = start; 00769 LPWSTR end; 00770 00771 while (*str == ' ' && *str != '\0') 00772 str++; 00773 00774 if (str != start) 00775 memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); 00776 00777 end = start + strlenW(start) - 1; 00778 while (end >= start && *end == ' ') 00779 { 00780 *end = '\0'; 00781 end--; 00782 } 00783 } 00784 00785 static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm ) 00786 { 00787 static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ 00788 static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */ 00789 BOOL is_basic; 00790 is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && 00791 ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); 00792 if (is_basic && pszRealm) 00793 { 00794 LPCWSTR token; 00795 LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)]; 00796 LPCWSTR realm; 00797 ptr++; 00798 *pszRealm=NULL; 00799 token = strchrW(ptr,'='); 00800 if (!token) 00801 return TRUE; 00802 realm = ptr; 00803 while (*realm == ' ' && *realm != '\0') 00804 realm++; 00805 if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) && 00806 (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '=')) 00807 { 00808 token++; 00809 while (*token == ' ' && *token != '\0') 00810 token++; 00811 if (*token == '\0') 00812 return TRUE; 00813 *pszRealm = heap_strdupW(token); 00814 strip_spaces(*pszRealm); 00815 } 00816 } 00817 00818 return is_basic; 00819 } 00820 00821 static void destroy_authinfo( struct HttpAuthInfo *authinfo ) 00822 { 00823 if (!authinfo) return; 00824 00825 if (SecIsValidHandle(&authinfo->ctx)) 00826 DeleteSecurityContext(&authinfo->ctx); 00827 if (SecIsValidHandle(&authinfo->cred)) 00828 FreeCredentialsHandle(&authinfo->cred); 00829 00830 HeapFree(GetProcessHeap(), 0, authinfo->auth_data); 00831 HeapFree(GetProcessHeap(), 0, authinfo->scheme); 00832 HeapFree(GetProcessHeap(), 0, authinfo); 00833 } 00834 00835 static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data) 00836 { 00837 basicAuthorizationData *ad; 00838 UINT rc = 0; 00839 00840 TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm)); 00841 00842 EnterCriticalSection(&authcache_cs); 00843 LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, basicAuthorizationData, entry) 00844 { 00845 if (!strcmpiW(host,ad->host) && !strcmpW(realm,ad->realm)) 00846 { 00847 TRACE("Authorization found in cache\n"); 00848 *auth_data = heap_alloc(ad->authorizationLen); 00849 memcpy(*auth_data,ad->authorization,ad->authorizationLen); 00850 rc = ad->authorizationLen; 00851 break; 00852 } 00853 } 00854 LeaveCriticalSection(&authcache_cs); 00855 return rc; 00856 } 00857 00858 static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len) 00859 { 00860 struct list *cursor; 00861 basicAuthorizationData* ad = NULL; 00862 00863 TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len)); 00864 00865 EnterCriticalSection(&authcache_cs); 00866 LIST_FOR_EACH(cursor, &basicAuthorizationCache) 00867 { 00868 basicAuthorizationData *check = LIST_ENTRY(cursor,basicAuthorizationData,entry); 00869 if (!strcmpiW(host,check->host) && !strcmpW(realm,check->realm)) 00870 { 00871 ad = check; 00872 break; 00873 } 00874 } 00875 00876 if (ad) 00877 { 00878 TRACE("Found match in cache, replacing\n"); 00879 HeapFree(GetProcessHeap(),0,ad->authorization); 00880 ad->authorization = heap_alloc(auth_data_len); 00881 memcpy(ad->authorization, auth_data, auth_data_len); 00882 ad->authorizationLen = auth_data_len; 00883 } 00884 else 00885 { 00886 ad = heap_alloc(sizeof(basicAuthorizationData)); 00887 ad->host = heap_strdupW(host); 00888 ad->host = heap_strdupW(realm); 00889 ad->authorization = heap_alloc(auth_data_len); 00890 memcpy(ad->authorization, auth_data, auth_data_len); 00891 ad->authorizationLen = auth_data_len; 00892 list_add_head(&basicAuthorizationCache,&ad->entry); 00893 TRACE("authorization cached\n"); 00894 } 00895 LeaveCriticalSection(&authcache_cs); 00896 } 00897 00898 static BOOL retrieve_cached_authorization(LPWSTR host, LPWSTR scheme, 00899 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity) 00900 { 00901 authorizationData *ad; 00902 00903 TRACE("Looking for authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme)); 00904 00905 EnterCriticalSection(&authcache_cs); 00906 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry) { 00907 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) { 00908 TRACE("Authorization found in cache\n"); 00909 00910 nt_auth_identity->User = heap_strdupW(ad->user); 00911 nt_auth_identity->Password = heap_strdupW(ad->password); 00912 nt_auth_identity->Domain = heap_alloc(sizeof(WCHAR)*ad->domain_len); 00913 if(!nt_auth_identity->User || !nt_auth_identity->Password || 00914 (!nt_auth_identity->Domain && ad->domain_len)) { 00915 HeapFree(GetProcessHeap(), 0, nt_auth_identity->User); 00916 HeapFree(GetProcessHeap(), 0, nt_auth_identity->Password); 00917 HeapFree(GetProcessHeap(), 0, nt_auth_identity->Domain); 00918 break; 00919 } 00920 00921 nt_auth_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; 00922 nt_auth_identity->UserLength = ad->user_len; 00923 nt_auth_identity->PasswordLength = ad->password_len; 00924 memcpy(nt_auth_identity->Domain, ad->domain, sizeof(WCHAR)*ad->domain_len); 00925 nt_auth_identity->DomainLength = ad->domain_len; 00926 LeaveCriticalSection(&authcache_cs); 00927 return TRUE; 00928 } 00929 } 00930 LeaveCriticalSection(&authcache_cs); 00931 00932 return FALSE; 00933 } 00934 00935 static void cache_authorization(LPWSTR host, LPWSTR scheme, 00936 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity) 00937 { 00938 authorizationData *ad; 00939 BOOL found = FALSE; 00940 00941 TRACE("Caching authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme)); 00942 00943 EnterCriticalSection(&authcache_cs); 00944 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry) 00945 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) { 00946 found = TRUE; 00947 break; 00948 } 00949 00950 if(found) { 00951 HeapFree(GetProcessHeap(), 0, ad->user); 00952 HeapFree(GetProcessHeap(), 0, ad->password); 00953 HeapFree(GetProcessHeap(), 0, ad->domain); 00954 } else { 00955 ad = heap_alloc(sizeof(authorizationData)); 00956 if(!ad) { 00957 LeaveCriticalSection(&authcache_cs); 00958 return; 00959 } 00960 00961 ad->host = heap_strdupW(host); 00962 ad->scheme = heap_strdupW(scheme); 00963 list_add_head(&authorizationCache, &ad->entry); 00964 } 00965 00966 ad->user = heap_strndupW(nt_auth_identity->User, nt_auth_identity->UserLength); 00967 ad->password = heap_strndupW(nt_auth_identity->Password, nt_auth_identity->PasswordLength); 00968 ad->domain = heap_strndupW(nt_auth_identity->Domain, nt_auth_identity->DomainLength); 00969 ad->user_len = nt_auth_identity->UserLength; 00970 ad->password_len = nt_auth_identity->PasswordLength; 00971 ad->domain_len = nt_auth_identity->DomainLength; 00972 00973 if(!ad->host || !ad->scheme || !ad->user || !ad->password 00974 || (nt_auth_identity->Domain && !ad->domain)) { 00975 HeapFree(GetProcessHeap(), 0, ad->host); 00976 HeapFree(GetProcessHeap(), 0, ad->scheme); 00977 HeapFree(GetProcessHeap(), 0, ad->user); 00978 HeapFree(GetProcessHeap(), 0, ad->password); 00979 HeapFree(GetProcessHeap(), 0, ad->domain); 00980 list_remove(&ad->entry); 00981 HeapFree(GetProcessHeap(), 0, ad); 00982 } 00983 00984 LeaveCriticalSection(&authcache_cs); 00985 } 00986 00987 static BOOL HTTP_DoAuthorization( http_request_t *request, LPCWSTR pszAuthValue, 00988 struct HttpAuthInfo **ppAuthInfo, 00989 LPWSTR domain_and_username, LPWSTR password, 00990 LPWSTR host ) 00991 { 00992 SECURITY_STATUS sec_status; 00993 struct HttpAuthInfo *pAuthInfo = *ppAuthInfo; 00994 BOOL first = FALSE; 00995 LPWSTR szRealm = NULL; 00996 00997 TRACE("%s\n", debugstr_w(pszAuthValue)); 00998 00999 if (!pAuthInfo) 01000 { 01001 TimeStamp exp; 01002 01003 first = TRUE; 01004 pAuthInfo = heap_alloc(sizeof(*pAuthInfo)); 01005 if (!pAuthInfo) 01006 return FALSE; 01007 01008 SecInvalidateHandle(&pAuthInfo->cred); 01009 SecInvalidateHandle(&pAuthInfo->ctx); 01010 memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp)); 01011 pAuthInfo->attr = 0; 01012 pAuthInfo->auth_data = NULL; 01013 pAuthInfo->auth_data_len = 0; 01014 pAuthInfo->finished = FALSE; 01015 01016 if (is_basic_auth_value(pszAuthValue,NULL)) 01017 { 01018 static const WCHAR szBasic[] = {'B','a','s','i','c',0}; 01019 pAuthInfo->scheme = heap_strdupW(szBasic); 01020 if (!pAuthInfo->scheme) 01021 { 01022 HeapFree(GetProcessHeap(), 0, pAuthInfo); 01023 return FALSE; 01024 } 01025 } 01026 else 01027 { 01028 PVOID pAuthData; 01029 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity; 01030 01031 pAuthInfo->scheme = heap_strdupW(pszAuthValue); 01032 if (!pAuthInfo->scheme) 01033 { 01034 HeapFree(GetProcessHeap(), 0, pAuthInfo); 01035 return FALSE; 01036 } 01037 01038 if (domain_and_username) 01039 { 01040 WCHAR *user = strchrW(domain_and_username, '\\'); 01041 WCHAR *domain = domain_and_username; 01042 01043 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */ 01044 01045 pAuthData = &nt_auth_identity; 01046 01047 if (user) user++; 01048 else 01049 { 01050 user = domain_and_username; 01051 domain = NULL; 01052 } 01053 01054 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; 01055 nt_auth_identity.User = user; 01056 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User); 01057 nt_auth_identity.Domain = domain; 01058 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0; 01059 nt_auth_identity.Password = password; 01060 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password); 01061 01062 cache_authorization(host, pAuthInfo->scheme, &nt_auth_identity); 01063 } 01064 else if(retrieve_cached_authorization(host, pAuthInfo->scheme, &nt_auth_identity)) 01065 pAuthData = &nt_auth_identity; 01066 else 01067 /* use default credentials */ 01068 pAuthData = NULL; 01069 01070 sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme, 01071 SECPKG_CRED_OUTBOUND, NULL, 01072 pAuthData, NULL, 01073 NULL, &pAuthInfo->cred, 01074 &exp); 01075 01076 if(pAuthData && !domain_and_username) { 01077 HeapFree(GetProcessHeap(), 0, nt_auth_identity.User); 01078 HeapFree(GetProcessHeap(), 0, nt_auth_identity.Domain); 01079 HeapFree(GetProcessHeap(), 0, nt_auth_identity.Password); 01080 } 01081 01082 if (sec_status == SEC_E_OK) 01083 { 01084 PSecPkgInfoW sec_pkg_info; 01085 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info); 01086 if (sec_status == SEC_E_OK) 01087 { 01088 pAuthInfo->max_token = sec_pkg_info->cbMaxToken; 01089 FreeContextBuffer(sec_pkg_info); 01090 } 01091 } 01092 if (sec_status != SEC_E_OK) 01093 { 01094 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n", 01095 debugstr_w(pAuthInfo->scheme), sec_status); 01096 HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme); 01097 HeapFree(GetProcessHeap(), 0, pAuthInfo); 01098 return FALSE; 01099 } 01100 } 01101 *ppAuthInfo = pAuthInfo; 01102 } 01103 else if (pAuthInfo->finished) 01104 return FALSE; 01105 01106 if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) || 01107 strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme))) 01108 { 01109 ERR("authentication scheme changed from %s to %s\n", 01110 debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue)); 01111 return FALSE; 01112 } 01113 01114 if (is_basic_auth_value(pszAuthValue,&szRealm)) 01115 { 01116 int userlen; 01117 int passlen; 01118 char *auth_data = NULL; 01119 UINT auth_data_len = 0; 01120 01121 TRACE("basic authentication realm %s\n",debugstr_w(szRealm)); 01122 01123 if (!domain_and_username) 01124 { 01125 if (host && szRealm) 01126 auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data); 01127 if (auth_data_len == 0) 01128 { 01129 HeapFree(GetProcessHeap(),0,szRealm); 01130 return FALSE; 01131 } 01132 } 01133 else 01134 { 01135 userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); 01136 passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); 01137 01138 /* length includes a nul terminator, which will be re-used for the ':' */ 01139 auth_data = heap_alloc(userlen + 1 + passlen); 01140 if (!auth_data) 01141 { 01142 HeapFree(GetProcessHeap(),0,szRealm); 01143 return FALSE; 01144 } 01145 01146 WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); 01147 auth_data[userlen] = ':'; 01148 WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); 01149 auth_data_len = userlen + 1 + passlen; 01150 if (host && szRealm) 01151 cache_basic_authorization(host, szRealm, auth_data, auth_data_len); 01152 } 01153 01154 pAuthInfo->auth_data = auth_data; 01155 pAuthInfo->auth_data_len = auth_data_len; 01156 pAuthInfo->finished = TRUE; 01157 HeapFree(GetProcessHeap(),0,szRealm); 01158 01159 return TRUE; 01160 } 01161 else 01162 { 01163 LPCWSTR pszAuthData; 01164 SecBufferDesc out_desc, in_desc; 01165 SecBuffer out, in; 01166 unsigned char *buffer; 01167 ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | 01168 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; 01169 01170 in.BufferType = SECBUFFER_TOKEN; 01171 in.cbBuffer = 0; 01172 in.pvBuffer = NULL; 01173 01174 in_desc.ulVersion = 0; 01175 in_desc.cBuffers = 1; 01176 in_desc.pBuffers = ∈ 01177 01178 pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme); 01179 if (*pszAuthData == ' ') 01180 { 01181 pszAuthData++; 01182 in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL); 01183 in.pvBuffer = heap_alloc(in.cbBuffer); 01184 HTTP_DecodeBase64(pszAuthData, in.pvBuffer); 01185 } 01186 01187 buffer = heap_alloc(pAuthInfo->max_token); 01188 01189 out.BufferType = SECBUFFER_TOKEN; 01190 out.cbBuffer = pAuthInfo->max_token; 01191 out.pvBuffer = buffer; 01192 01193 out_desc.ulVersion = 0; 01194 out_desc.cBuffers = 1; 01195 out_desc.pBuffers = &out; 01196 01197 sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL, 01198 first ? NULL : &pAuthInfo->ctx, 01199 first ? request->session->serverName : NULL, 01200 context_req, 0, SECURITY_NETWORK_DREP, 01201 in.pvBuffer ? &in_desc : NULL, 01202 0, &pAuthInfo->ctx, &out_desc, 01203 &pAuthInfo->attr, &pAuthInfo->exp); 01204 if (sec_status == SEC_E_OK) 01205 { 01206 pAuthInfo->finished = TRUE; 01207 pAuthInfo->auth_data = out.pvBuffer; 01208 pAuthInfo->auth_data_len = out.cbBuffer; 01209 TRACE("sending last auth packet\n"); 01210 } 01211 else if (sec_status == SEC_I_CONTINUE_NEEDED) 01212 { 01213 pAuthInfo->auth_data = out.pvBuffer; 01214 pAuthInfo->auth_data_len = out.cbBuffer; 01215 TRACE("sending next auth packet\n"); 01216 } 01217 else 01218 { 01219 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); 01220 HeapFree(GetProcessHeap(), 0, out.pvBuffer); 01221 destroy_authinfo(pAuthInfo); 01222 *ppAuthInfo = NULL; 01223 return FALSE; 01224 } 01225 } 01226 01227 return TRUE; 01228 } 01229 01230 /*********************************************************************** 01231 * HTTP_HttpAddRequestHeadersW (internal) 01232 */ 01233 static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *request, 01234 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) 01235 { 01236 LPWSTR lpszStart; 01237 LPWSTR lpszEnd; 01238 LPWSTR buffer; 01239 DWORD len, res = ERROR_HTTP_INVALID_HEADER; 01240 01241 TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength)); 01242 01243 if( dwHeaderLength == ~0U ) 01244 len = strlenW(lpszHeader); 01245 else 01246 len = dwHeaderLength; 01247 buffer = heap_alloc(sizeof(WCHAR)*(len+1)); 01248 lstrcpynW( buffer, lpszHeader, len + 1); 01249 01250 lpszStart = buffer; 01251 01252 do 01253 { 01254 LPWSTR * pFieldAndValue; 01255 01256 lpszEnd = lpszStart; 01257 01258 while (*lpszEnd != '\0') 01259 { 01260 if (*lpszEnd == '\r' || *lpszEnd == '\n') 01261 break; 01262 lpszEnd++; 01263 } 01264 01265 if (*lpszStart == '\0') 01266 break; 01267 01268 if (*lpszEnd == '\r' || *lpszEnd == '\n') 01269 { 01270 *lpszEnd = '\0'; 01271 lpszEnd++; /* Jump over newline */ 01272 } 01273 TRACE("interpreting header %s\n", debugstr_w(lpszStart)); 01274 if (*lpszStart == '\0') 01275 { 01276 /* Skip 0-length headers */ 01277 lpszStart = lpszEnd; 01278 res = ERROR_SUCCESS; 01279 continue; 01280 } 01281 pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart); 01282 if (pFieldAndValue) 01283 { 01284 res = HTTP_VerifyValidHeader(request, pFieldAndValue[0]); 01285 if (res == ERROR_SUCCESS) 01286 res = HTTP_ProcessHeader(request, pFieldAndValue[0], 01287 pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ); 01288 HTTP_FreeTokens(pFieldAndValue); 01289 } 01290 01291 lpszStart = lpszEnd; 01292 } while (res == ERROR_SUCCESS); 01293 01294 HeapFree(GetProcessHeap(), 0, buffer); 01295 01296 return res; 01297 } 01298 01299 /*********************************************************************** 01300 * HttpAddRequestHeadersW (WININET.@) 01301 * 01302 * Adds one or more HTTP header to the request handler 01303 * 01304 * NOTE 01305 * On Windows if dwHeaderLength includes the trailing '\0', then 01306 * HttpAddRequestHeadersW() adds it too. However this results in an 01307 * invalid Http header which is rejected by some servers so we probably 01308 * don't need to match Windows on that point. 01309 * 01310 * RETURNS 01311 * TRUE on success 01312 * FALSE on failure 01313 * 01314 */ 01315 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest, 01316 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) 01317 { 01318 http_request_t *request; 01319 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 01320 01321 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier); 01322 01323 if (!lpszHeader) 01324 return TRUE; 01325 01326 request = (http_request_t*) get_handle_object( hHttpRequest ); 01327 if (request && request->hdr.htype == WH_HHTTPREQ) 01328 res = HTTP_HttpAddRequestHeadersW( request, lpszHeader, dwHeaderLength, dwModifier ); 01329 if( request ) 01330 WININET_Release( &request->hdr ); 01331 01332 if(res != ERROR_SUCCESS) 01333 SetLastError(res); 01334 return res == ERROR_SUCCESS; 01335 } 01336 01337 /*********************************************************************** 01338 * HttpAddRequestHeadersA (WININET.@) 01339 * 01340 * Adds one or more HTTP header to the request handler 01341 * 01342 * RETURNS 01343 * TRUE on success 01344 * FALSE on failure 01345 * 01346 */ 01347 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, 01348 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) 01349 { 01350 DWORD len; 01351 LPWSTR hdr; 01352 BOOL r; 01353 01354 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier); 01355 01356 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 ); 01357 hdr = heap_alloc(len*sizeof(WCHAR)); 01358 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len ); 01359 if( dwHeaderLength != ~0U ) 01360 dwHeaderLength = len; 01361 01362 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier ); 01363 01364 HeapFree( GetProcessHeap(), 0, hdr ); 01365 01366 return r; 01367 } 01368 01369 /*********************************************************************** 01370 * HttpOpenRequestA (WININET.@) 01371 * 01372 * Open a HTTP request handle 01373 * 01374 * RETURNS 01375 * HINTERNET a HTTP request handle on success 01376 * NULL on failure 01377 * 01378 */ 01379 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, 01380 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion, 01381 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes, 01382 DWORD dwFlags, DWORD_PTR dwContext) 01383 { 01384 LPWSTR szVerb = NULL, szObjectName = NULL; 01385 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; 01386 INT acceptTypesCount; 01387 HINTERNET rc = FALSE; 01388 LPCSTR *types; 01389 01390 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, 01391 debugstr_a(lpszVerb), debugstr_a(lpszObjectName), 01392 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes, 01393 dwFlags, dwContext); 01394 01395 if (lpszVerb) 01396 { 01397 szVerb = heap_strdupAtoW(lpszVerb); 01398 if ( !szVerb ) 01399 goto end; 01400 } 01401 01402 if (lpszObjectName) 01403 { 01404 szObjectName = heap_strdupAtoW(lpszObjectName); 01405 if ( !szObjectName ) 01406 goto end; 01407 } 01408 01409 if (lpszVersion) 01410 { 01411 szVersion = heap_strdupAtoW(lpszVersion); 01412 if ( !szVersion ) 01413 goto end; 01414 } 01415 01416 if (lpszReferrer) 01417 { 01418 szReferrer = heap_strdupAtoW(lpszReferrer); 01419 if ( !szReferrer ) 01420 goto end; 01421 } 01422 01423 if (lpszAcceptTypes) 01424 { 01425 acceptTypesCount = 0; 01426 types = lpszAcceptTypes; 01427 while (*types) 01428 { 01429 __TRY 01430 { 01431 /* find out how many there are */ 01432 if (*types && **types) 01433 { 01434 TRACE("accept type: %s\n", debugstr_a(*types)); 01435 acceptTypesCount++; 01436 } 01437 } 01438 __EXCEPT_PAGE_FAULT 01439 { 01440 WARN("invalid accept type pointer\n"); 01441 } 01442 __ENDTRY; 01443 types++; 01444 } 01445 szAcceptTypes = heap_alloc(sizeof(WCHAR *) * (acceptTypesCount+1)); 01446 if (!szAcceptTypes) goto end; 01447 01448 acceptTypesCount = 0; 01449 types = lpszAcceptTypes; 01450 while (*types) 01451 { 01452 __TRY 01453 { 01454 if (*types && **types) 01455 szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types); 01456 } 01457 __EXCEPT_PAGE_FAULT 01458 { 01459 /* ignore invalid pointer */ 01460 } 01461 __ENDTRY; 01462 types++; 01463 } 01464 szAcceptTypes[acceptTypesCount] = NULL; 01465 } 01466 01467 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, 01468 szVersion, szReferrer, 01469 (LPCWSTR*)szAcceptTypes, dwFlags, dwContext); 01470 01471 end: 01472 if (szAcceptTypes) 01473 { 01474 acceptTypesCount = 0; 01475 while (szAcceptTypes[acceptTypesCount]) 01476 { 01477 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]); 01478 acceptTypesCount++; 01479 } 01480 HeapFree(GetProcessHeap(), 0, szAcceptTypes); 01481 } 01482 HeapFree(GetProcessHeap(), 0, szReferrer); 01483 HeapFree(GetProcessHeap(), 0, szVersion); 01484 HeapFree(GetProcessHeap(), 0, szObjectName); 01485 HeapFree(GetProcessHeap(), 0, szVerb); 01486 01487 return rc; 01488 } 01489 01490 /*********************************************************************** 01491 * HTTP_EncodeBase64 01492 */ 01493 static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 ) 01494 { 01495 UINT n = 0, x; 01496 static const CHAR HTTP_Base64Enc[] = 01497 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 01498 01499 while( len > 0 ) 01500 { 01501 /* first 6 bits, all from bin[0] */ 01502 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2]; 01503 x = (bin[0] & 3) << 4; 01504 01505 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ 01506 if( len == 1 ) 01507 { 01508 base64[n++] = HTTP_Base64Enc[x]; 01509 base64[n++] = '='; 01510 base64[n++] = '='; 01511 break; 01512 } 01513 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ]; 01514 x = ( bin[1] & 0x0f ) << 2; 01515 01516 /* next 6 bits 4 from bin[1] and 2 from bin[2] */ 01517 if( len == 2 ) 01518 { 01519 base64[n++] = HTTP_Base64Enc[x]; 01520 base64[n++] = '='; 01521 break; 01522 } 01523 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ]; 01524 01525 /* last 6 bits, all from bin [2] */ 01526 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ]; 01527 bin += 3; 01528 len -= 3; 01529 } 01530 base64[n] = 0; 01531 return n; 01532 } 01533 01534 #define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \ 01535 ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \ 01536 ((x) >= '0' && (x) <= '9') ? (x) - '0' + 52 : \ 01537 ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1) 01538 static const signed char HTTP_Base64Dec[256] = 01539 { 01540 CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9), 01541 CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19), 01542 CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29), 01543 CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39), 01544 CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49), 01545 CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59), 01546 CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69), 01547 CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79), 01548 CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89), 01549 CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99), 01550 CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109), 01551 CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119), 01552 CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129), 01553 CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139), 01554 CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149), 01555 CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159), 01556 CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169), 01557 CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179), 01558 CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189), 01559 CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199), 01560 CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209), 01561 CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219), 01562 CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229), 01563 CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239), 01564 CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249), 01565 CH(250),CH(251),CH(252),CH(253),CH(254),CH(255), 01566 }; 01567 #undef CH 01568 01569 /*********************************************************************** 01570 * HTTP_DecodeBase64 01571 */ 01572 static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) 01573 { 01574 unsigned int n = 0; 01575 01576 while(*base64) 01577 { 01578 signed char in[4]; 01579 01580 if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) || 01581 ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) || 01582 base64[1] >= ARRAYSIZE(HTTP_Base64Dec) || 01583 ((in[1] = HTTP_Base64Dec[base64[1]]) == -1)) 01584 { 01585 WARN("invalid base64: %s\n", debugstr_w(base64)); 01586 return 0; 01587 } 01588 if (bin) 01589 bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4); 01590 n++; 01591 01592 if ((base64[2] == '=') && (base64[3] == '=')) 01593 break; 01594 if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) || 01595 ((in[2] = HTTP_Base64Dec[base64[2]]) == -1)) 01596 { 01597 WARN("invalid base64: %s\n", debugstr_w(&base64[2])); 01598 return 0; 01599 } 01600 if (bin) 01601 bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2); 01602 n++; 01603 01604 if (base64[3] == '=') 01605 break; 01606 if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) || 01607 ((in[3] = HTTP_Base64Dec[base64[3]]) == -1)) 01608 { 01609 WARN("invalid base64: %s\n", debugstr_w(&base64[3])); 01610 return 0; 01611 } 01612 if (bin) 01613 bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]); 01614 n++; 01615 01616 base64 += 4; 01617 } 01618 01619 return n; 01620 } 01621 01622 /*********************************************************************** 01623 * HTTP_InsertAuthorization 01624 * 01625 * Insert or delete the authorization field in the request header. 01626 */ 01627 static BOOL HTTP_InsertAuthorization( http_request_t *request, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) 01628 { 01629 if (pAuthInfo) 01630 { 01631 static const WCHAR wszSpace[] = {' ',0}; 01632 static const WCHAR wszBasic[] = {'B','a','s','i','c',0}; 01633 unsigned int len; 01634 WCHAR *authorization = NULL; 01635 01636 if (pAuthInfo->auth_data_len) 01637 { 01638 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */ 01639 len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3; 01640 authorization = heap_alloc((len+1)*sizeof(WCHAR)); 01641 if (!authorization) 01642 return FALSE; 01643 01644 strcpyW(authorization, pAuthInfo->scheme); 01645 strcatW(authorization, wszSpace); 01646 HTTP_EncodeBase64(pAuthInfo->auth_data, 01647 pAuthInfo->auth_data_len, 01648 authorization+strlenW(authorization)); 01649 01650 /* clear the data as it isn't valid now that it has been sent to the 01651 * server, unless it's Basic authentication which doesn't do 01652 * connection tracking */ 01653 if (strcmpiW(pAuthInfo->scheme, wszBasic)) 01654 { 01655 HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data); 01656 pAuthInfo->auth_data = NULL; 01657 pAuthInfo->auth_data_len = 0; 01658 } 01659 } 01660 01661 TRACE("Inserting authorization: %s\n", debugstr_w(authorization)); 01662 01663 HTTP_ProcessHeader(request, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE); 01664 01665 HeapFree(GetProcessHeap(), 0, authorization); 01666 } 01667 return TRUE; 01668 } 01669 01670 static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req) 01671 { 01672 WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url; 01673 DWORD size; 01674 01675 size = sizeof(new_location); 01676 if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS) 01677 { 01678 if (!(url = heap_alloc(size + sizeof(WCHAR)))) return NULL; 01679 strcpyW( url, new_location ); 01680 } 01681 else 01682 { 01683 static const WCHAR slash[] = { '/',0 }; 01684 static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 }; 01685 static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','u',0 }; 01686 http_session_t *session = req->session; 01687 01688 size = 16; /* "https://" + sizeof(port#) + ":/\0" */ 01689 size += strlenW( session->hostName ) + strlenW( req->path ); 01690 01691 if (!(url = heap_alloc(size * sizeof(WCHAR)))) return NULL; 01692 01693 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) 01694 sprintfW( url, formatSSL, session->hostName, session->hostPort ); 01695 else 01696 sprintfW( url, format, session->hostName, session->hostPort ); 01697 if (req->path[0] != '/') strcatW( url, slash ); 01698 strcatW( url, req->path ); 01699 } 01700 TRACE("url=%s\n", debugstr_w(url)); 01701 return url; 01702 } 01703 01704 /*********************************************************************** 01705 * HTTP_DealWithProxy 01706 */ 01707 static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *session, http_request_t *request) 01708 { 01709 WCHAR buf[MAXHOSTNAME]; 01710 WCHAR protoProxy[MAXHOSTNAME + 15]; 01711 DWORD protoProxyLen = sizeof(protoProxy) / sizeof(protoProxy[0]); 01712 WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ 01713 static WCHAR szNul[] = { 0 }; 01714 URL_COMPONENTSW UrlComponents; 01715 static const WCHAR protoHttp[] = { 'h','t','t','p',0 }; 01716 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }; 01717 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 }; 01718 01719 memset( &UrlComponents, 0, sizeof UrlComponents ); 01720 UrlComponents.dwStructSize = sizeof UrlComponents; 01721 UrlComponents.lpszHostName = buf; 01722 UrlComponents.dwHostNameLength = MAXHOSTNAME; 01723 01724 if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen)) 01725 return FALSE; 01726 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, 01727 protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) ) 01728 sprintfW(proxy, szFormat, protoProxy); 01729 else 01730 strcpyW(proxy, protoProxy); 01731 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) ) 01732 return FALSE; 01733 if( UrlComponents.dwHostNameLength == 0 ) 01734 return FALSE; 01735 01736 if( !request->path ) 01737 request->path = szNul; 01738 01739 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) 01740 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; 01741 01742 HeapFree(GetProcessHeap(), 0, session->serverName); 01743 session->serverName = heap_strdupW(UrlComponents.lpszHostName); 01744 session->serverPort = UrlComponents.nPort; 01745 01746 TRACE("proxy server=%s port=%d\n", debugstr_w(session->serverName), session->serverPort); 01747 return TRUE; 01748 } 01749 01750 static DWORD HTTP_ResolveName(http_request_t *request, server_t *server) 01751 { 01752 socklen_t addr_len; 01753 const void *addr; 01754 01755 if(server->addr_len) 01756 return ERROR_SUCCESS; 01757 01758 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 01759 INTERNET_STATUS_RESOLVING_NAME, 01760 server->name, 01761 (strlenW(server->name)+1) * sizeof(WCHAR)); 01762 01763 addr_len = sizeof(server->addr); 01764 if (!GetAddress(server->name, server->port, (struct sockaddr *)&server->addr, &addr_len)) 01765 return ERROR_INTERNET_NAME_NOT_RESOLVED; 01766 01767 switch(server->addr.ss_family) { 01768 case AF_INET: 01769 addr = &((struct sockaddr_in *)&server->addr)->sin_addr; 01770 break; 01771 case AF_INET6: 01772 addr = &((struct sockaddr_in6 *)&server->addr)->sin6_addr; 01773 break; 01774 default: 01775 WARN("unsupported family %d\n", server->addr.ss_family); 01776 return ERROR_INTERNET_NAME_NOT_RESOLVED; 01777 } 01778 01779 server->addr_len = addr_len; 01780 inet_ntop(server->addr.ss_family, addr, server->addr_str, sizeof(server->addr_str)); 01781 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 01782 INTERNET_STATUS_NAME_RESOLVED, 01783 server->addr_str, strlen(server->addr_str)+1); 01784 01785 TRACE("resolved %s to %s\n", debugstr_w(server->name), server->addr_str); 01786 return ERROR_SUCCESS; 01787 } 01788 01789 static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) 01790 { 01791 static const WCHAR http[] = { 'h','t','t','p',':','/','/',0 }; 01792 static const WCHAR https[] = { 'h','t','t','p','s',':','/','/',0 }; 01793 static const WCHAR slash[] = { '/',0 }; 01794 LPHTTPHEADERW host_header; 01795 LPCWSTR scheme; 01796 01797 host_header = HTTP_GetHeader(req, hostW); 01798 if(!host_header) 01799 return FALSE; 01800 01801 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) 01802 scheme = https; 01803 else 01804 scheme = http; 01805 strcpyW(buf, scheme); 01806 strcatW(buf, host_header->lpszValue); 01807 if (req->path[0] != '/') 01808 strcatW(buf, slash); 01809 strcatW(buf, req->path); 01810 return TRUE; 01811 } 01812 01813 01814 /*********************************************************************** 01815 * HTTPREQ_Destroy (internal) 01816 * 01817 * Deallocate request handle 01818 * 01819 */ 01820 static void HTTPREQ_Destroy(object_header_t *hdr) 01821 { 01822 http_request_t *request = (http_request_t*) hdr; 01823 DWORD i; 01824 01825 TRACE("\n"); 01826 01827 if(request->hCacheFile) { 01828 WCHAR url[INTERNET_MAX_URL_LENGTH]; 01829 01830 CloseHandle(request->hCacheFile); 01831 01832 if(HTTP_GetRequestURL(request, url)) { 01833 DWORD headersLen; 01834 01835 headersLen = request->rawHeaders ? strlenW(request->rawHeaders) : 0; 01836 CommitUrlCacheEntryW(url, request->cacheFile, request->expires, 01837 request->last_modified, NORMAL_CACHE_ENTRY, 01838 request->rawHeaders, headersLen, NULL, 0); 01839 } 01840 } 01841 01842 HeapFree(GetProcessHeap(), 0, request->cacheFile); 01843 01844 DeleteCriticalSection( &request->read_section ); 01845 WININET_Release(&request->session->hdr); 01846 01847 destroy_authinfo(request->authInfo); 01848 destroy_authinfo(request->proxyAuthInfo); 01849 01850 HeapFree(GetProcessHeap(), 0, request->path); 01851 HeapFree(GetProcessHeap(), 0, request->verb); 01852 HeapFree(GetProcessHeap(), 0, request->rawHeaders); 01853 HeapFree(GetProcessHeap(), 0, request->version); 01854 HeapFree(GetProcessHeap(), 0, request->statusText); 01855 01856 for (i = 0; i < request->nCustHeaders; i++) 01857 { 01858 HeapFree(GetProcessHeap(), 0, request->custHeaders[i].lpszField); 01859 HeapFree(GetProcessHeap(), 0, request->custHeaders[i].lpszValue); 01860 } 01861 01862 destroy_data_stream(request->data_stream); 01863 HeapFree(GetProcessHeap(), 0, request->custHeaders); 01864 } 01865 01866 static void http_release_netconn(http_request_t *req, BOOL reuse) 01867 { 01868 TRACE("%p %p\n",req, req->netconn); 01869 01870 if(!req->netconn) 01871 return; 01872 01873 #ifndef __REACTOS__ 01874 if(reuse && req->netconn->keep_alive) { 01875 BOOL run_collector; 01876 01877 EnterCriticalSection(&connection_pool_cs); 01878 01879 list_add_head(&req->netconn->server->conn_pool, &req->netconn->pool_entry); 01880 req->netconn->keep_until = (DWORD64)GetTickCount() + COLLECT_TIME; 01881 req->netconn = NULL; 01882 01883 run_collector = !collector_running; 01884 collector_running = TRUE; 01885 01886 LeaveCriticalSection(&connection_pool_cs); 01887 01888 if(run_collector) { 01889 HANDLE thread = NULL; 01890 HMODULE module; 01891 01892 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)WININET_hModule, &module); 01893 if(module) 01894 thread = CreateThread(NULL, 0, collect_connections_proc, NULL, 0, NULL); 01895 if(!thread) { 01896 EnterCriticalSection(&connection_pool_cs); 01897 collector_running = FALSE; 01898 LeaveCriticalSection(&connection_pool_cs); 01899 01900 if(module) 01901 FreeLibrary(module); 01902 } 01903 else 01904 CloseHandle(thread); 01905 } 01906 return; 01907 } 01908 #endif 01909 01910 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 01911 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); 01912 01913 free_netconn(req->netconn); 01914 req->netconn = NULL; 01915 01916 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 01917 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); 01918 } 01919 01920 static void drain_content(http_request_t *req) 01921 { 01922 BOOL try_reuse; 01923 01924 if (!req->netconn) return; 01925 01926 if (req->contentLength == -1) 01927 try_reuse = FALSE; 01928 else if(!strcmpW(req->verb, szHEAD)) 01929 try_reuse = TRUE; 01930 else 01931 try_reuse = req->data_stream->vtbl->drain_content(req->data_stream, req); 01932 01933 http_release_netconn(req, try_reuse); 01934 } 01935 01936 static BOOL HTTP_KeepAlive(http_request_t *request) 01937 { 01938 WCHAR szVersion[10]; 01939 WCHAR szConnectionResponse[20]; 01940 DWORD dwBufferSize = sizeof(szVersion); 01941 BOOL keepalive = FALSE; 01942 01943 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that 01944 * the connection is keep-alive by default */ 01945 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS 01946 && !strcmpiW(szVersion, g_szHttp1_1)) 01947 { 01948 keepalive = TRUE; 01949 } 01950 01951 dwBufferSize = sizeof(szConnectionResponse); 01952 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS 01953 || HTTP_HttpQueryInfoW(request, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS) 01954 { 01955 keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); 01956 } 01957 01958 return keepalive; 01959 } 01960 01961 static void HTTPREQ_CloseConnection(object_header_t *hdr) 01962 { 01963 http_request_t *req = (http_request_t*)hdr; 01964 01965 drain_content(req); 01966 } 01967 01968 static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 01969 { 01970 http_request_t *req = (http_request_t*)hdr; 01971 01972 switch(option) { 01973 case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO: 01974 { 01975 http_session_t *session = req->session; 01976 INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer; 01977 01978 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n"); 01979 01980 if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO)) 01981 return ERROR_INSUFFICIENT_BUFFER; 01982 *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO); 01983 /* FIXME: can't get a SOCKET from our connection since we don't use 01984 * winsock 01985 */ 01986 info->Socket = 0; 01987 /* FIXME: get source port from req->netConnection */ 01988 info->SourcePort = 0; 01989 info->DestPort = session->hostPort; 01990 info->Flags = 0; 01991 if (HTTP_KeepAlive(req)) 01992 info->Flags |= IDSI_FLAG_KEEP_ALIVE; 01993 if (session->appInfo->proxy && session->appInfo->proxy[0] != 0) 01994 info->Flags |= IDSI_FLAG_PROXY; 01995 if (req->netconn->useSSL) 01996 info->Flags |= IDSI_FLAG_SECURE; 01997 01998 return ERROR_SUCCESS; 01999 } 02000 02001 case INTERNET_OPTION_SECURITY_FLAGS: 02002 { 02003 DWORD flags; 02004 02005 if (*size < sizeof(ULONG)) 02006 return ERROR_INSUFFICIENT_BUFFER; 02007 02008 *size = sizeof(DWORD); 02009 flags = 0; 02010 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) 02011 flags |= SECURITY_FLAG_SECURE; 02012 flags |= req->security_flags; 02013 if(req->netconn) { 02014 int bits = NETCON_GetCipherStrength(req->netconn); 02015 if (bits >= 128) 02016 flags |= SECURITY_FLAG_STRENGTH_STRONG; 02017 else if (bits >= 56) 02018 flags |= SECURITY_FLAG_STRENGTH_MEDIUM; 02019 else 02020 flags |= SECURITY_FLAG_STRENGTH_WEAK; 02021 } 02022 *(DWORD *)buffer = flags; 02023 return ERROR_SUCCESS; 02024 } 02025 02026 case INTERNET_OPTION_HANDLE_TYPE: 02027 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 02028 02029 if (*size < sizeof(ULONG)) 02030 return ERROR_INSUFFICIENT_BUFFER; 02031 02032 *size = sizeof(DWORD); 02033 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST; 02034 return ERROR_SUCCESS; 02035 02036 case INTERNET_OPTION_URL: { 02037 WCHAR url[INTERNET_MAX_URL_LENGTH]; 02038 HTTPHEADERW *host; 02039 DWORD len; 02040 WCHAR *pch; 02041 02042 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; 02043 02044 TRACE("INTERNET_OPTION_URL\n"); 02045 02046 host = HTTP_GetHeader(req, hostW); 02047 strcpyW(url, httpW); 02048 strcatW(url, host->lpszValue); 02049 if (NULL != (pch = strchrW(url + strlenW(httpW), ':'))) 02050 *pch = 0; 02051 strcatW(url, req->path); 02052 02053 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url)); 02054 02055 if(unicode) { 02056 len = (strlenW(url)+1) * sizeof(WCHAR); 02057 if(*size < len) 02058 return ERROR_INSUFFICIENT_BUFFER; 02059 02060 *size = len; 02061 strcpyW(buffer, url); 02062 return ERROR_SUCCESS; 02063 }else { 02064 len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL); 02065 if(len > *size) 02066 return ERROR_INSUFFICIENT_BUFFER; 02067 02068 *size = len; 02069 return ERROR_SUCCESS; 02070 } 02071 } 02072 02073 case INTERNET_OPTION_CACHE_TIMESTAMPS: { 02074 INTERNET_CACHE_ENTRY_INFOW *info; 02075 INTERNET_CACHE_TIMESTAMPS *ts = buffer; 02076 WCHAR url[INTERNET_MAX_URL_LENGTH]; 02077 DWORD nbytes, error; 02078 BOOL ret; 02079 02080 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n"); 02081 02082 if (*size < sizeof(*ts)) 02083 { 02084 *size = sizeof(*ts); 02085 return ERROR_INSUFFICIENT_BUFFER; 02086 } 02087 nbytes = 0; 02088 HTTP_GetRequestURL(req, url); 02089 ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes); 02090 error = GetLastError(); 02091 if (!ret && error == ERROR_INSUFFICIENT_BUFFER) 02092 { 02093 if (!(info = heap_alloc(nbytes))) 02094 return ERROR_OUTOFMEMORY; 02095 02096 GetUrlCacheEntryInfoW(url, info, &nbytes); 02097 02098 ts->ftExpires = info->ExpireTime; 02099 ts->ftLastModified = info->LastModifiedTime; 02100 02101 HeapFree(GetProcessHeap(), 0, info); 02102 *size = sizeof(*ts); 02103 return ERROR_SUCCESS; 02104 } 02105 return error; 02106 } 02107 02108 case INTERNET_OPTION_DATAFILE_NAME: { 02109 DWORD req_size; 02110 02111 TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); 02112 02113 if(!req->cacheFile) { 02114 *size = 0; 02115 return ERROR_INTERNET_ITEM_NOT_FOUND; 02116 } 02117 02118 if(unicode) { 02119 req_size = (lstrlenW(req->cacheFile)+1) * sizeof(WCHAR); 02120 if(*size < req_size) 02121 return ERROR_INSUFFICIENT_BUFFER; 02122 02123 *size = req_size; 02124 memcpy(buffer, req->cacheFile, *size); 02125 return ERROR_SUCCESS; 02126 }else { 02127 req_size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile, -1, NULL, 0, NULL, NULL); 02128 if (req_size > *size) 02129 return ERROR_INSUFFICIENT_BUFFER; 02130 02131 *size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile, 02132 -1, buffer, *size, NULL, NULL); 02133 return ERROR_SUCCESS; 02134 } 02135 } 02136 02137 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: { 02138 PCCERT_CONTEXT context; 02139 02140 if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) { 02141 *size = sizeof(INTERNET_CERTIFICATE_INFOA); 02142 return ERROR_INSUFFICIENT_BUFFER; 02143 } 02144 02145 context = (PCCERT_CONTEXT)NETCON_GetCert(req->netconn); 02146 if(context) { 02147 INTERNET_CERTIFICATE_INFOA *info = (INTERNET_CERTIFICATE_INFOA*)buffer; 02148 DWORD len; 02149 02150 memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW)); 02151 info->ftExpiry = context->pCertInfo->NotAfter; 02152 info->ftStart = context->pCertInfo->NotBefore; 02153 len = CertNameToStrA(context->dwCertEncodingType, 02154 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0); 02155 info->lpszSubjectInfo = LocalAlloc(0, len); 02156 if(info->lpszSubjectInfo) 02157 CertNameToStrA(context->dwCertEncodingType, 02158 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, 02159 info->lpszSubjectInfo, len); 02160 len = CertNameToStrA(context->dwCertEncodingType, 02161 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0); 02162 info->lpszIssuerInfo = LocalAlloc(0, len); 02163 if(info->lpszIssuerInfo) 02164 CertNameToStrA(context->dwCertEncodingType, 02165 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, 02166 info->lpszIssuerInfo, len); 02167 info->dwKeySize = NETCON_GetCipherStrength(req->netconn); 02168 CertFreeCertificateContext(context); 02169 return ERROR_SUCCESS; 02170 } 02171 } 02172 } 02173 02174 return INET_QueryOption(hdr, option, buffer, size, unicode); 02175 } 02176 02177 static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) 02178 { 02179 http_request_t *req = (http_request_t*)hdr; 02180 02181 switch(option) { 02182 case INTERNET_OPTION_SECURITY_FLAGS: 02183 { 02184 DWORD flags; 02185 02186 if (!buffer || size != sizeof(DWORD)) 02187 return ERROR_INVALID_PARAMETER; 02188 flags = *(DWORD *)buffer; 02189 TRACE("%08x\n", flags); 02190 req->security_flags = flags; 02191 if(req->netconn) 02192 req->netconn->security_flags = flags; 02193 return ERROR_SUCCESS; 02194 } 02195 case INTERNET_OPTION_SEND_TIMEOUT: 02196 case INTERNET_OPTION_RECEIVE_TIMEOUT: 02197 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n"); 02198 02199 if (size != sizeof(DWORD)) 02200 return ERROR_INVALID_PARAMETER; 02201 02202 if(!req->netconn) { 02203 FIXME("unsupported without active connection\n"); 02204 return ERROR_SUCCESS; 02205 } 02206 02207 return NETCON_set_timeout(req->netconn, option == INTERNET_OPTION_SEND_TIMEOUT, 02208 *(DWORD*)buffer); 02209 02210 case INTERNET_OPTION_USERNAME: 02211 HeapFree(GetProcessHeap(), 0, req->session->userName); 02212 if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; 02213 return ERROR_SUCCESS; 02214 02215 case INTERNET_OPTION_PASSWORD: 02216 HeapFree(GetProcessHeap(), 0, req->session->password); 02217 if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; 02218 return ERROR_SUCCESS; 02219 case INTERNET_OPTION_HTTP_DECODING: 02220 if(size != sizeof(BOOL)) 02221 return ERROR_INVALID_PARAMETER; 02222 req->decoding = *(BOOL*)buffer; 02223 return ERROR_SUCCESS; 02224 } 02225 02226 return ERROR_INTERNET_INVALID_OPTION; 02227 } 02228 02229 /* read some more data into the read buffer (the read section must be held) */ 02230 static DWORD read_more_data( http_request_t *req, int maxlen ) 02231 { 02232 DWORD res; 02233 int len; 02234 02235 if (req->read_pos) 02236 { 02237 /* move existing data to the start of the buffer */ 02238 if(req->read_size) 02239 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size ); 02240 req->read_pos = 0; 02241 } 02242 02243 if (maxlen == -1) maxlen = sizeof(req->read_buf); 02244 02245 res = NETCON_recv( req->netconn, req->read_buf + req->read_size, 02246 maxlen - req->read_size, 0, &len ); 02247 if(res == ERROR_SUCCESS) 02248 req->read_size += len; 02249 02250 return res; 02251 } 02252 02253 /* remove some amount of data from the read buffer (the read section must be held) */ 02254 static void remove_data( http_request_t *req, int count ) 02255 { 02256 if (!(req->read_size -= count)) req->read_pos = 0; 02257 else req->read_pos += count; 02258 } 02259 02260 static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) 02261 { 02262 int count, bytes_read, pos = 0; 02263 DWORD res; 02264 02265 EnterCriticalSection( &req->read_section ); 02266 for (;;) 02267 { 02268 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); 02269 02270 if (eol) 02271 { 02272 count = eol - (req->read_buf + req->read_pos); 02273 bytes_read = count + 1; 02274 } 02275 else count = bytes_read = req->read_size; 02276 02277 count = min( count, *len - pos ); 02278 memcpy( buffer + pos, req->read_buf + req->read_pos, count ); 02279 pos += count; 02280 remove_data( req, bytes_read ); 02281 if (eol) break; 02282 02283 if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) 02284 { 02285 *len = 0; 02286 TRACE( "returning empty string %u\n", res); 02287 LeaveCriticalSection( &req->read_section ); 02288 INTERNET_SetLastError(res); 02289 return FALSE; 02290 } 02291 } 02292 LeaveCriticalSection( &req->read_section ); 02293 02294 if (pos < *len) 02295 { 02296 if (pos && buffer[pos - 1] == '\r') pos--; 02297 *len = pos + 1; 02298 } 02299 buffer[*len - 1] = 0; 02300 TRACE( "returning %s\n", debugstr_a(buffer)); 02301 return TRUE; 02302 } 02303 02304 /* check if we have reached the end of the data to read (the read section must be held) */ 02305 static BOOL end_of_read_data( http_request_t *req ) 02306 { 02307 return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req); 02308 } 02309 02310 /* fetch some more data into the read buffer (the read section must be held) */ 02311 static DWORD refill_read_buffer(http_request_t *req, read_mode_t read_mode, DWORD *read_bytes) 02312 { 02313 DWORD res, read=0; 02314 02315 if(req->read_size == sizeof(req->read_buf)) 02316 return ERROR_SUCCESS; 02317 02318 if(req->read_pos) { 02319 if(req->read_size) 02320 memmove(req->read_buf, req->read_buf+req->read_pos, req->read_size); 02321 req->read_pos = 0; 02322 } 02323 02324 res = req->data_stream->vtbl->read(req->data_stream, req, req->read_buf+req->read_size, 02325 sizeof(req->read_buf)-req->read_size, &read, read_mode); 02326 req->read_size += read; 02327 02328 TRACE("read %u bytes, read_size %u\n", read, req->read_size); 02329 if(read_bytes) 02330 *read_bytes = read; 02331 return res; 02332 } 02333 02334 /* return the size of data available to be read immediately (the read section must be held) */ 02335 static DWORD get_avail_data( http_request_t *req ) 02336 { 02337 return req->read_size + req->data_stream->vtbl->get_avail_data(req->data_stream, req); 02338 } 02339 02340 static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req) 02341 { 02342 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; 02343 DWORD avail = 0; 02344 02345 if(req->netconn) 02346 NETCON_query_data_available(req->netconn, &avail); 02347 return netconn_stream->content_length == ~0u 02348 ? avail 02349 : min(avail, netconn_stream->content_length-netconn_stream->content_read); 02350 } 02351 02352 static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req) 02353 { 02354 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; 02355 return netconn_stream->content_read == netconn_stream->content_length || !req->netconn; 02356 } 02357 02358 static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, 02359 DWORD *read, read_mode_t read_mode) 02360 { 02361 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; 02362 int len = 0; 02363 02364 size = min(size, netconn_stream->content_length-netconn_stream->content_read); 02365 02366 if(read_mode == READMODE_NOBLOCK) 02367 size = min(size, netconn_get_avail_data(stream, req)); 02368 02369 if(size && req->netconn) { 02370 if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS) 02371 len = 0; 02372 } 02373 02374 netconn_stream->content_read += *read = len; 02375 TRACE("read %u bytes\n", len); 02376 return ERROR_SUCCESS; 02377 } 02378 02379 static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req) 02380 { 02381 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; 02382 BYTE buf[1024]; 02383 DWORD avail; 02384 int len; 02385 02386 if(netconn_end_of_data(stream, req)) 02387 return TRUE; 02388 02389 do { 02390 avail = netconn_get_avail_data(stream, req); 02391 if(!avail) 02392 return FALSE; 02393 02394 if(NETCON_recv(req->netconn, buf, min(avail, sizeof(buf)), 0, &len) != ERROR_SUCCESS) 02395 return FALSE; 02396 02397 netconn_stream->content_read += len; 02398 }while(netconn_stream->content_read < netconn_stream->content_length); 02399 02400 return TRUE; 02401 } 02402 02403 static void netconn_destroy(data_stream_t *stream) 02404 { 02405 } 02406 02407 static const data_stream_vtbl_t netconn_stream_vtbl = { 02408 netconn_get_avail_data, 02409 netconn_end_of_data, 02410 netconn_read, 02411 netconn_drain_content, 02412 netconn_destroy 02413 }; 02414 02415 /* read some more data into the read buffer (the read section must be held) */ 02416 static DWORD read_more_chunked_data(chunked_stream_t *stream, http_request_t *req, int maxlen) 02417 { 02418 DWORD res; 02419 int len; 02420 02421 if (stream->buf_pos) 02422 { 02423 /* move existing data to the start of the buffer */ 02424 if(stream->buf_size) 02425 memmove(stream->buf, stream->buf + stream->buf_pos, stream->buf_size); 02426 stream->buf_pos = 0; 02427 } 02428 02429 if (maxlen == -1) maxlen = sizeof(stream->buf); 02430 02431 res = NETCON_recv( req->netconn, stream->buf + stream->buf_size, 02432 maxlen - stream->buf_size, 0, &len ); 02433 if(res == ERROR_SUCCESS) 02434 stream->buf_size += len; 02435 02436 return res; 02437 } 02438 02439 /* remove some amount of data from the read buffer (the read section must be held) */ 02440 static void remove_chunked_data(chunked_stream_t *stream, int count) 02441 { 02442 if (!(stream->buf_size -= count)) stream->buf_pos = 0; 02443 else stream->buf_pos += count; 02444 } 02445 02446 /* discard data contents until we reach end of line (the read section must be held) */ 02447 static DWORD discard_chunked_eol(chunked_stream_t *stream, http_request_t *req) 02448 { 02449 DWORD res; 02450 02451 do 02452 { 02453 BYTE *eol = memchr(stream->buf + stream->buf_pos, '\n', stream->buf_size); 02454 if (eol) 02455 { 02456 remove_chunked_data(stream, (eol + 1) - (stream->buf + stream->buf_pos)); 02457 break; 02458 } 02459 stream->buf_pos = stream->buf_size = 0; /* discard everything */ 02460 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res; 02461 } while (stream->buf_size); 02462 return ERROR_SUCCESS; 02463 } 02464 02465 /* read the size of the next chunk (the read section must be held) */ 02466 static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req) 02467 { 02468 /* TODOO */ 02469 DWORD chunk_size = 0, res; 02470 02471 if(stream->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS) 02472 return res; 02473 02474 for (;;) 02475 { 02476 while (stream->buf_size) 02477 { 02478 char ch = stream->buf[stream->buf_pos]; 02479 if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; 02480 else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; 02481 else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; 02482 else if (ch == ';' || ch == '\r' || ch == '\n') 02483 { 02484 TRACE( "reading %u byte chunk\n", chunk_size ); 02485 stream->chunk_size = chunk_size; 02486 req->contentLength += chunk_size; 02487 return discard_chunked_eol(stream, req); 02488 } 02489 remove_chunked_data(stream, 1); 02490 } 02491 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res; 02492 if (!stream->buf_size) 02493 { 02494 stream->chunk_size = 0; 02495 return ERROR_SUCCESS; 02496 } 02497 } 02498 } 02499 02500 static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req) 02501 { 02502 /* Allow reading only from read buffer */ 02503 return 0; 02504 } 02505 02506 static BOOL chunked_end_of_data(data_stream_t *stream, http_request_t *req) 02507 { 02508 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; 02509 return !chunked_stream->chunk_size; 02510 } 02511 02512 static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, 02513 DWORD *read, read_mode_t read_mode) 02514 { 02515 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; 02516 DWORD read_bytes = 0, ret_read = 0, res = ERROR_SUCCESS; 02517 02518 if(chunked_stream->chunk_size == ~0u) { 02519 res = start_next_chunk(chunked_stream, req); 02520 if(res != ERROR_SUCCESS) 02521 return res; 02522 } 02523 02524 while(size && chunked_stream->chunk_size) { 02525 if(chunked_stream->buf_size) { 02526 read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size)); 02527 02528 /* this could block */ 02529 if(read_mode == READMODE_NOBLOCK && read_bytes == chunked_stream->chunk_size) 02530 break; 02531 02532 memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes); 02533 remove_chunked_data(chunked_stream, read_bytes); 02534 }else { 02535 read_bytes = min(size, chunked_stream->chunk_size); 02536 02537 if(read_mode == READMODE_NOBLOCK) { 02538 DWORD avail; 02539 02540 if(!NETCON_query_data_available(req->netconn, &avail) || !avail) 02541 break; 02542 if(read_bytes > avail) 02543 read_bytes = avail; 02544 02545 /* this could block */ 02546 if(read_bytes == chunked_stream->chunk_size) 02547 break; 02548 } 02549 02550 res = NETCON_recv(req->netconn, (char *)buf+ret_read, read_bytes, 0, (int*)&read_bytes); 02551 if(res != ERROR_SUCCESS) 02552 break; 02553 } 02554 02555 chunked_stream->chunk_size -= read_bytes; 02556 size -= read_bytes; 02557 ret_read += read_bytes; 02558 if(!chunked_stream->chunk_size) { 02559 assert(read_mode != READMODE_NOBLOCK); 02560 res = start_next_chunk(chunked_stream, req); 02561 if(res != ERROR_SUCCESS) 02562 break; 02563 } 02564 02565 if(read_mode == READMODE_ASYNC) 02566 read_mode = READMODE_NOBLOCK; 02567 } 02568 02569 TRACE("read %u bytes\n", ret_read); 02570 *read = ret_read; 02571 return res; 02572 } 02573 02574 static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req) 02575 { 02576 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; 02577 02578 /* FIXME: we can do better */ 02579 return !chunked_stream->chunk_size; 02580 } 02581 02582 static void chunked_destroy(data_stream_t *stream) 02583 { 02584 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; 02585 heap_free(chunked_stream); 02586 } 02587 02588 static const data_stream_vtbl_t chunked_stream_vtbl = { 02589 chunked_get_avail_data, 02590 chunked_end_of_data, 02591 chunked_read, 02592 chunked_drain_content, 02593 chunked_destroy 02594 }; 02595 02596 /* set the request content length based on the headers */ 02597 static DWORD set_content_length(http_request_t *request, DWORD status_code) 02598 { 02599 static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; 02600 WCHAR encoding[20]; 02601 DWORD size; 02602 02603 if(status_code == HTTP_STATUS_NO_CONTENT) { 02604 request->contentLength = request->netconn_stream.content_length = 0; 02605 return ERROR_SUCCESS; 02606 } 02607 02608 size = sizeof(request->contentLength); 02609 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, 02610 &request->contentLength, &size, NULL) != ERROR_SUCCESS) 02611 request->contentLength = ~0u; 02612 request->netconn_stream.content_length = request->contentLength; 02613 request->netconn_stream.content_read = request->read_size; 02614 02615 size = sizeof(encoding); 02616 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS && 02617 !strcmpiW(encoding, szChunked)) 02618 { 02619 chunked_stream_t *chunked_stream; 02620 02621 chunked_stream = heap_alloc(sizeof(*chunked_stream)); 02622 if(!chunked_stream) 02623 return ERROR_OUTOFMEMORY; 02624 02625 chunked_stream->data_stream.vtbl = &chunked_stream_vtbl; 02626 chunked_stream->buf_size = chunked_stream->buf_pos = 0; 02627 chunked_stream->chunk_size = ~0u; 02628 02629 if(request->read_size) { 02630 memcpy(chunked_stream->buf, request->read_buf+request->read_pos, request->read_size); 02631 chunked_stream->buf_size = request->read_size; 02632 request->read_size = request->read_pos = 0; 02633 } 02634 02635 request->data_stream = &chunked_stream->data_stream; 02636 request->contentLength = ~0u; 02637 request->read_chunked = TRUE; 02638 } 02639 02640 if(request->decoding) { 02641 int encoding_idx; 02642 02643 static const WCHAR gzipW[] = {'g','z','i','p',0}; 02644 02645 encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE); 02646 if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) 02647 return init_gzip_stream(request); 02648 } 02649 02650 return ERROR_SUCCESS; 02651 } 02652 02653 static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif) 02654 { 02655 INTERNET_ASYNC_RESULT iar; 02656 DWORD res, read = 0; 02657 read_mode_t mode; 02658 02659 TRACE("%p\n", req); 02660 02661 EnterCriticalSection( &req->read_section ); 02662 02663 mode = first_notif && req->read_size ? READMODE_NOBLOCK : READMODE_ASYNC; 02664 res = refill_read_buffer(req, mode, &read); 02665 if(res == ERROR_SUCCESS) { 02666 iar.dwResult = (DWORD_PTR)req->hdr.hInternet; 02667 iar.dwError = first_notif ? 0 : get_avail_data(req); 02668 }else { 02669 iar.dwResult = 0; 02670 iar.dwError = res; 02671 } 02672 02673 LeaveCriticalSection( &req->read_section ); 02674 02675 if(res != ERROR_SUCCESS || (mode != READMODE_NOBLOCK && !read)) { 02676 WARN("res %u read %u, closing connection\n", res, read); 02677 http_release_netconn(req, FALSE); 02678 } 02679 02680 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, 02681 sizeof(INTERNET_ASYNC_RESULT)); 02682 } 02683 02684 /* read data from the http connection (the read section must be held) */ 02685 static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync) 02686 { 02687 DWORD current_read = 0, ret_read = 0; 02688 read_mode_t read_mode; 02689 DWORD res = ERROR_SUCCESS; 02690 02691 read_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? READMODE_ASYNC : READMODE_SYNC; 02692 02693 EnterCriticalSection( &req->read_section ); 02694 02695 if(req->read_size) { 02696 ret_read = min(size, req->read_size); 02697 memcpy(buffer, req->read_buf+req->read_pos, ret_read); 02698 req->read_size -= ret_read; 02699 req->read_pos += ret_read; 02700 if(read_mode == READMODE_ASYNC) 02701 read_mode = READMODE_NOBLOCK; 02702 } 02703 02704 if(ret_read < size) { 02705 res = req->data_stream->vtbl->read(req->data_stream, req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, read_mode); 02706 ret_read += current_read; 02707 } 02708 02709 LeaveCriticalSection( &req->read_section ); 02710 02711 *read = ret_read; 02712 TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength ); 02713 02714 if(req->hCacheFile && res == ERROR_SUCCESS && ret_read) { 02715 BOOL res; 02716 DWORD written; 02717 02718 res = WriteFile(req->hCacheFile, buffer, ret_read, &written, NULL); 02719 if(!res) 02720 WARN("WriteFile failed: %u\n", GetLastError()); 02721 } 02722 02723 if(size && !ret_read) 02724 http_release_netconn(req, res == ERROR_SUCCESS); 02725 02726 return res; 02727 } 02728 02729 02730 static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) 02731 { 02732 http_request_t *req = (http_request_t*)hdr; 02733 DWORD res; 02734 02735 EnterCriticalSection( &req->read_section ); 02736 if(hdr->dwError == INTERNET_HANDLE_IN_USE) 02737 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; 02738 02739 res = HTTPREQ_Read(req, buffer, size, read, TRUE); 02740 if(res == ERROR_SUCCESS) 02741 res = hdr->dwError; 02742 LeaveCriticalSection( &req->read_section ); 02743 02744 return res; 02745 } 02746 02747 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest) 02748 { 02749 struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA; 02750 http_request_t *req = (http_request_t*)workRequest->hdr; 02751 INTERNET_ASYNC_RESULT iar; 02752 DWORD res; 02753 02754 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr); 02755 02756 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, 02757 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); 02758 02759 iar.dwResult = res == ERROR_SUCCESS; 02760 iar.dwError = res; 02761 02762 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 02763 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 02764 sizeof(INTERNET_ASYNC_RESULT)); 02765 } 02766 02767 static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, 02768 DWORD flags, DWORD_PTR context) 02769 { 02770 http_request_t *req = (http_request_t*)hdr; 02771 DWORD res, size, read, error = ERROR_SUCCESS; 02772 02773 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) 02774 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); 02775 02776 if (buffers->dwStructSize != sizeof(*buffers)) 02777 return ERROR_INVALID_PARAMETER; 02778 02779 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 02780 02781 if (hdr->dwFlags & INTERNET_FLAG_ASYNC) 02782 { 02783 WORKREQUEST workRequest; 02784 02785 if (TryEnterCriticalSection( &req->read_section )) 02786 { 02787 if (get_avail_data(req)) 02788 { 02789 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, 02790 &buffers->dwBufferLength, FALSE); 02791 size = buffers->dwBufferLength; 02792 LeaveCriticalSection( &req->read_section ); 02793 goto done; 02794 } 02795 LeaveCriticalSection( &req->read_section ); 02796 } 02797 02798 workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc; 02799 workRequest.hdr = WININET_AddRef(&req->hdr); 02800 workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; 02801 02802 INTERNET_AsyncCall(&workRequest); 02803 02804 return ERROR_IO_PENDING; 02805 } 02806 02807 read = 0; 02808 size = buffers->dwBufferLength; 02809 02810 EnterCriticalSection( &req->read_section ); 02811 if(hdr->dwError == ERROR_SUCCESS) 02812 hdr->dwError = INTERNET_HANDLE_IN_USE; 02813 else if(hdr->dwError == INTERNET_HANDLE_IN_USE) 02814 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; 02815 02816 while(1) { 02817 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read, 02818 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT)); 02819 if(res != ERROR_SUCCESS) 02820 break; 02821 02822 read += buffers->dwBufferLength; 02823 if(read == size || end_of_read_data(req)) 02824 break; 02825 02826 LeaveCriticalSection( &req->read_section ); 02827 02828 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 02829 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength)); 02830 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 02831 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 02832 02833 EnterCriticalSection( &req->read_section ); 02834 } 02835 02836 if(hdr->dwError == INTERNET_HANDLE_IN_USE) 02837 hdr->dwError = ERROR_SUCCESS; 02838 else 02839 error = hdr->dwError; 02840 02841 LeaveCriticalSection( &req->read_section ); 02842 size = buffers->dwBufferLength; 02843 buffers->dwBufferLength = read; 02844 02845 done: 02846 if (res == ERROR_SUCCESS) { 02847 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 02848 &size, sizeof(size)); 02849 } 02850 02851 return res==ERROR_SUCCESS ? error : res; 02852 } 02853 02854 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest) 02855 { 02856 struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; 02857 http_request_t *req = (http_request_t*)workRequest->hdr; 02858 INTERNET_ASYNC_RESULT iar; 02859 DWORD res; 02860 02861 TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr); 02862 02863 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, 02864 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); 02865 02866 iar.dwResult = res == ERROR_SUCCESS; 02867 iar.dwError = res; 02868 02869 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 02870 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 02871 sizeof(INTERNET_ASYNC_RESULT)); 02872 } 02873 02874 static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, 02875 DWORD flags, DWORD_PTR context) 02876 { 02877 02878 http_request_t *req = (http_request_t*)hdr; 02879 DWORD res, size, read, error = ERROR_SUCCESS; 02880 02881 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) 02882 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); 02883 02884 if (buffers->dwStructSize != sizeof(*buffers)) 02885 return ERROR_INVALID_PARAMETER; 02886 02887 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 02888 02889 if (hdr->dwFlags & INTERNET_FLAG_ASYNC) 02890 { 02891 WORKREQUEST workRequest; 02892 02893 if (TryEnterCriticalSection( &req->read_section )) 02894 { 02895 if (get_avail_data(req)) 02896 { 02897 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, 02898 &buffers->dwBufferLength, FALSE); 02899 size = buffers->dwBufferLength; 02900 LeaveCriticalSection( &req->read_section ); 02901 goto done; 02902 } 02903 LeaveCriticalSection( &req->read_section ); 02904 } 02905 02906 workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc; 02907 workRequest.hdr = WININET_AddRef(&req->hdr); 02908 workRequest.u.InternetReadFileExW.lpBuffersOut = buffers; 02909 02910 INTERNET_AsyncCall(&workRequest); 02911 02912 return ERROR_IO_PENDING; 02913 } 02914 02915 read = 0; 02916 size = buffers->dwBufferLength; 02917 02918 EnterCriticalSection( &req->read_section ); 02919 if(hdr->dwError == ERROR_SUCCESS) 02920 hdr->dwError = INTERNET_HANDLE_IN_USE; 02921 else if(hdr->dwError == INTERNET_HANDLE_IN_USE) 02922 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; 02923 02924 while(1) { 02925 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read, 02926 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT)); 02927 if(res != ERROR_SUCCESS) 02928 break; 02929 02930 read += buffers->dwBufferLength; 02931 if(read == size || end_of_read_data(req)) 02932 break; 02933 02934 LeaveCriticalSection( &req->read_section ); 02935 02936 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 02937 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength)); 02938 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, 02939 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 02940 02941 EnterCriticalSection( &req->read_section ); 02942 } 02943 02944 if(hdr->dwError == INTERNET_HANDLE_IN_USE) 02945 hdr->dwError = ERROR_SUCCESS; 02946 else 02947 error = hdr->dwError; 02948 02949 LeaveCriticalSection( &req->read_section ); 02950 size = buffers->dwBufferLength; 02951 buffers->dwBufferLength = read; 02952 02953 done: 02954 if (res == ERROR_SUCCESS) { 02955 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 02956 &size, sizeof(size)); 02957 } 02958 02959 return res==ERROR_SUCCESS ? error : res; 02960 } 02961 02962 static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) 02963 { 02964 DWORD res; 02965 http_request_t *request = (http_request_t*)hdr; 02966 02967 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 02968 02969 *written = 0; 02970 res = NETCON_send(request->netconn, buffer, size, 0, (LPINT)written); 02971 if (res == ERROR_SUCCESS) 02972 request->bytesWritten += *written; 02973 02974 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD)); 02975 return res; 02976 } 02977 02978 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) 02979 { 02980 http_request_t *req = (http_request_t*)workRequest->hdr; 02981 02982 HTTP_ReceiveRequestData(req, FALSE); 02983 } 02984 02985 static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) 02986 { 02987 http_request_t *req = (http_request_t*)hdr; 02988 02989 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); 02990 02991 if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 02992 { 02993 WORKREQUEST workRequest; 02994 02995 /* never wait, if we can't enter the section we queue an async request right away */ 02996 if (TryEnterCriticalSection( &req->read_section )) 02997 { 02998 refill_read_buffer(req, READMODE_NOBLOCK, NULL); 02999 if ((*available = get_avail_data( req ))) goto done; 03000 if (end_of_read_data( req )) goto done; 03001 LeaveCriticalSection( &req->read_section ); 03002 } 03003 03004 workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; 03005 workRequest.hdr = WININET_AddRef( &req->hdr ); 03006 03007 INTERNET_AsyncCall(&workRequest); 03008 03009 return ERROR_IO_PENDING; 03010 } 03011 03012 EnterCriticalSection( &req->read_section ); 03013 03014 if (!(*available = get_avail_data( req )) && !end_of_read_data( req )) 03015 { 03016 refill_read_buffer( req, READMODE_ASYNC, NULL ); 03017 *available = get_avail_data( req ); 03018 } 03019 03020 done: 03021 LeaveCriticalSection( &req->read_section ); 03022 03023 TRACE( "returning %u\n", *available ); 03024 return ERROR_SUCCESS; 03025 } 03026 03027 static const object_vtbl_t HTTPREQVtbl = { 03028 HTTPREQ_Destroy, 03029 HTTPREQ_CloseConnection, 03030 HTTPREQ_QueryOption, 03031 HTTPREQ_SetOption, 03032 HTTPREQ_ReadFile, 03033 HTTPREQ_ReadFileExA, 03034 HTTPREQ_ReadFileExW, 03035 HTTPREQ_WriteFile, 03036 HTTPREQ_QueryDataAvailable, 03037 NULL 03038 }; 03039 03040 /*********************************************************************** 03041 * HTTP_HttpOpenRequestW (internal) 03042 * 03043 * Open a HTTP request handle 03044 * 03045 * RETURNS 03046 * HINTERNET a HTTP request handle on success 03047 * NULL on failure 03048 * 03049 */ 03050 static DWORD HTTP_HttpOpenRequestW(http_session_t *session, 03051 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, 03052 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, 03053 DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret) 03054 { 03055 appinfo_t *hIC = session->appInfo; 03056 http_request_t *request; 03057 DWORD len, res = ERROR_SUCCESS; 03058 03059 TRACE("-->\n"); 03060 03061 request = alloc_object(&session->hdr, &HTTPREQVtbl, sizeof(http_request_t)); 03062 if(!request) 03063 return ERROR_OUTOFMEMORY; 03064 03065 request->hdr.htype = WH_HHTTPREQ; 03066 request->hdr.dwFlags = dwFlags; 03067 request->hdr.dwContext = dwContext; 03068 request->contentLength = ~0u; 03069 03070 request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl; 03071 request->data_stream = &request->netconn_stream.data_stream; 03072 03073 InitializeCriticalSection( &request->read_section ); 03074 03075 WININET_AddRef( &session->hdr ); 03076 request->session = session; 03077 list_add_head( &session->hdr.children, &request->hdr.entry ); 03078 03079 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_CN_INVALID) 03080 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 03081 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_DATE_INVALID) 03082 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 03083 03084 if (lpszObjectName && *lpszObjectName) { 03085 HRESULT rc; 03086 03087 len = 0; 03088 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY); 03089 if (rc != E_POINTER) 03090 len = strlenW(lpszObjectName)+1; 03091 request->path = heap_alloc(len*sizeof(WCHAR)); 03092 rc = UrlEscapeW(lpszObjectName, request->path, &len, 03093 URL_ESCAPE_SPACES_ONLY); 03094 if (rc != S_OK) 03095 { 03096 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc); 03097 strcpyW(request->path,lpszObjectName); 03098 } 03099 }else { 03100 static const WCHAR slashW[] = {'/',0}; 03101 03102 request->path = heap_strdupW(slashW); 03103 } 03104 03105 if (lpszReferrer && *lpszReferrer) 03106 HTTP_ProcessHeader(request, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); 03107 03108 if (lpszAcceptTypes) 03109 { 03110 int i; 03111 for (i = 0; lpszAcceptTypes[i]; i++) 03112 { 03113 if (!*lpszAcceptTypes[i]) continue; 03114 HTTP_ProcessHeader(request, HTTP_ACCEPT, lpszAcceptTypes[i], 03115 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA | 03116 HTTP_ADDHDR_FLAG_REQ | 03117 (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0)); 03118 } 03119 } 03120 03121 request->verb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); 03122 request->version = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1); 03123 03124 if (session->hostPort != INTERNET_INVALID_PORT_NUMBER && 03125 session->hostPort != INTERNET_DEFAULT_HTTP_PORT && 03126 session->hostPort != INTERNET_DEFAULT_HTTPS_PORT) 03127 { 03128 WCHAR *host_name; 03129 03130 static const WCHAR host_formatW[] = {'%','s',':','%','u',0}; 03131 03132 host_name = heap_alloc((strlenW(session->hostName) + 7 /* length of ":65535" + 1 */) * sizeof(WCHAR)); 03133 if (!host_name) { 03134 res = ERROR_OUTOFMEMORY; 03135 goto lend; 03136 } 03137 03138 sprintfW(host_name, host_formatW, session->hostName, session->hostPort); 03139 HTTP_ProcessHeader(request, hostW, host_name, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); 03140 heap_free(host_name); 03141 } 03142 else 03143 HTTP_ProcessHeader(request, hostW, session->hostName, 03144 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); 03145 03146 if (session->serverPort == INTERNET_INVALID_PORT_NUMBER) 03147 session->serverPort = (dwFlags & INTERNET_FLAG_SECURE ? 03148 INTERNET_DEFAULT_HTTPS_PORT : 03149 INTERNET_DEFAULT_HTTP_PORT); 03150 03151 if (session->hostPort == INTERNET_INVALID_PORT_NUMBER) 03152 session->hostPort = (dwFlags & INTERNET_FLAG_SECURE ? 03153 INTERNET_DEFAULT_HTTPS_PORT : 03154 INTERNET_DEFAULT_HTTP_PORT); 03155 03156 if (hIC->proxy && hIC->proxy[0]) 03157 HTTP_DealWithProxy( hIC, session, request ); 03158 03159 INTERNET_SendCallback(&session->hdr, dwContext, 03160 INTERNET_STATUS_HANDLE_CREATED, &request->hdr.hInternet, 03161 sizeof(HINTERNET)); 03162 03163 lend: 03164 TRACE("<-- %u (%p)\n", res, request); 03165 03166 if(res != ERROR_SUCCESS) { 03167 WININET_Release( &request->hdr ); 03168 *ret = NULL; 03169 return res; 03170 } 03171 03172 *ret = request->hdr.hInternet; 03173 return ERROR_SUCCESS; 03174 } 03175 03176 /*********************************************************************** 03177 * HttpOpenRequestW (WININET.@) 03178 * 03179 * Open a HTTP request handle 03180 * 03181 * RETURNS 03182 * HINTERNET a HTTP request handle on success 03183 * NULL on failure 03184 * 03185 */ 03186 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, 03187 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, 03188 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, 03189 DWORD dwFlags, DWORD_PTR dwContext) 03190 { 03191 http_session_t *session; 03192 HINTERNET handle = NULL; 03193 DWORD res; 03194 03195 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, 03196 debugstr_w(lpszVerb), debugstr_w(lpszObjectName), 03197 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, 03198 dwFlags, dwContext); 03199 if(lpszAcceptTypes!=NULL) 03200 { 03201 int i; 03202 for(i=0;lpszAcceptTypes[i]!=NULL;i++) 03203 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); 03204 } 03205 03206 session = (http_session_t*) get_handle_object( hHttpSession ); 03207 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION) 03208 { 03209 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 03210 goto lend; 03211 } 03212 03213 /* 03214 * My tests seem to show that the windows version does not 03215 * become asynchronous until after this point. And anyhow 03216 * if this call was asynchronous then how would you get the 03217 * necessary HINTERNET pointer returned by this function. 03218 * 03219 */ 03220 res = HTTP_HttpOpenRequestW(session, lpszVerb, lpszObjectName, 03221 lpszVersion, lpszReferrer, lpszAcceptTypes, 03222 dwFlags, dwContext, &handle); 03223 lend: 03224 if( session ) 03225 WININET_Release( &session->hdr ); 03226 TRACE("returning %p\n", handle); 03227 if(res != ERROR_SUCCESS) 03228 SetLastError(res); 03229 return handle; 03230 } 03231 03232 static const LPCWSTR header_lookup[] = { 03233 szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */ 03234 szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */ 03235 szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */ 03236 szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */ 03237 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */ 03238 szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */ 03239 szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */ 03240 szAllow, /* HTTP_QUERY_ALLOW = 7 */ 03241 szPublic, /* HTTP_QUERY_PUBLIC = 8 */ 03242 szDate, /* HTTP_QUERY_DATE = 9 */ 03243 szExpires, /* HTTP_QUERY_EXPIRES = 10 */ 03244 szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */ 03245 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */ 03246 szURI, /* HTTP_QUERY_URI = 13 */ 03247 szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */ 03248 NULL, /* HTTP_QUERY_COST = 15 */ 03249 NULL, /* HTTP_QUERY_LINK = 16 */ 03250 szPragma, /* HTTP_QUERY_PRAGMA = 17 */ 03251 NULL, /* HTTP_QUERY_VERSION = 18 */ 03252 szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */ 03253 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */ 03254 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */ 03255 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */ 03256 szConnection, /* HTTP_QUERY_CONNECTION = 23 */ 03257 szAccept, /* HTTP_QUERY_ACCEPT = 24 */ 03258 szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */ 03259 szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */ 03260 szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */ 03261 szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */ 03262 szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */ 03263 NULL, /* HTTP_QUERY_FORWARDED = 30 */ 03264 NULL, /* HTTP_QUERY_FROM = 31 */ 03265 szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */ 03266 szLocation, /* HTTP_QUERY_LOCATION = 33 */ 03267 NULL, /* HTTP_QUERY_ORIG_URI = 34 */ 03268 szReferer, /* HTTP_QUERY_REFERER = 35 */ 03269 szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */ 03270 szServer, /* HTTP_QUERY_SERVER = 37 */ 03271 NULL, /* HTTP_TITLE = 38 */ 03272 szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */ 03273 szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */ 03274 szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */ 03275 szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */ 03276 szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */ 03277 szCookie, /* HTTP_QUERY_COOKIE = 44 */ 03278 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */ 03279 NULL, /* HTTP_QUERY_REFRESH = 46 */ 03280 NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */ 03281 szAge, /* HTTP_QUERY_AGE = 48 */ 03282 szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */ 03283 szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */ 03284 szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */ 03285 szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */ 03286 szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */ 03287 szETag, /* HTTP_QUERY_ETAG = 54 */ 03288 hostW, /* HTTP_QUERY_HOST = 55 */ 03289 szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */ 03290 szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */ 03291 szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */ 03292 szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */ 03293 szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */ 03294 szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */ 03295 szRange, /* HTTP_QUERY_RANGE = 62 */ 03296 szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */ 03297 szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */ 03298 szVary, /* HTTP_QUERY_VARY = 65 */ 03299 szVia, /* HTTP_QUERY_VIA = 66 */ 03300 szWarning, /* HTTP_QUERY_WARNING = 67 */ 03301 szExpect, /* HTTP_QUERY_EXPECT = 68 */ 03302 szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */ 03303 szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */ 03304 }; 03305 03306 #define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0])) 03307 03308 /*********************************************************************** 03309 * HTTP_HttpQueryInfoW (internal) 03310 */ 03311 static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, 03312 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) 03313 { 03314 LPHTTPHEADERW lphttpHdr = NULL; 03315 BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS; 03316 INT requested_index = lpdwIndex ? *lpdwIndex : 0; 03317 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); 03318 INT index = -1; 03319 03320 /* Find requested header structure */ 03321 switch (level) 03322 { 03323 case HTTP_QUERY_CUSTOM: 03324 if (!lpBuffer) return ERROR_INVALID_PARAMETER; 03325 index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only); 03326 break; 03327 case HTTP_QUERY_RAW_HEADERS_CRLF: 03328 { 03329 LPWSTR headers; 03330 DWORD len = 0; 03331 DWORD res = ERROR_INVALID_PARAMETER; 03332 03333 if (request_only) 03334 headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); 03335 else 03336 headers = request->rawHeaders; 03337 03338 if (headers) 03339 len = strlenW(headers) * sizeof(WCHAR); 03340 03341 if (len + sizeof(WCHAR) > *lpdwBufferLength) 03342 { 03343 len += sizeof(WCHAR); 03344 res = ERROR_INSUFFICIENT_BUFFER; 03345 } 03346 else if (lpBuffer) 03347 { 03348 if (headers) 03349 memcpy(lpBuffer, headers, len + sizeof(WCHAR)); 03350 else 03351 { 03352 len = strlenW(szCrLf) * sizeof(WCHAR); 03353 memcpy(lpBuffer, szCrLf, sizeof(szCrLf)); 03354 } 03355 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); 03356 res = ERROR_SUCCESS; 03357 } 03358 *lpdwBufferLength = len; 03359 03360 if (request_only) 03361 HeapFree(GetProcessHeap(), 0, headers); 03362 return res; 03363 } 03364 case HTTP_QUERY_RAW_HEADERS: 03365 { 03366 LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf); 03367 DWORD i, size = 0; 03368 LPWSTR pszString = lpBuffer; 03369 03370 for (i = 0; ppszRawHeaderLines[i]; i++) 03371 size += strlenW(ppszRawHeaderLines[i]) + 1; 03372 03373 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR)) 03374 { 03375 HTTP_FreeTokens(ppszRawHeaderLines); 03376 *lpdwBufferLength = (size + 1) * sizeof(WCHAR); 03377 return ERROR_INSUFFICIENT_BUFFER; 03378 } 03379 if (pszString) 03380 { 03381 for (i = 0; ppszRawHeaderLines[i]; i++) 03382 { 03383 DWORD len = strlenW(ppszRawHeaderLines[i]); 03384 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); 03385 pszString += len+1; 03386 } 03387 *pszString = '\0'; 03388 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size)); 03389 } 03390 *lpdwBufferLength = size * sizeof(WCHAR); 03391 HTTP_FreeTokens(ppszRawHeaderLines); 03392 03393 return ERROR_SUCCESS; 03394 } 03395 case HTTP_QUERY_STATUS_TEXT: 03396 if (request->statusText) 03397 { 03398 DWORD len = strlenW(request->statusText); 03399 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) 03400 { 03401 *lpdwBufferLength = (len + 1) * sizeof(WCHAR); 03402 return ERROR_INSUFFICIENT_BUFFER; 03403 } 03404 if (lpBuffer) 03405 { 03406 memcpy(lpBuffer, request->statusText, (len + 1) * sizeof(WCHAR)); 03407 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); 03408 } 03409 *lpdwBufferLength = len * sizeof(WCHAR); 03410 return ERROR_SUCCESS; 03411 } 03412 break; 03413 case HTTP_QUERY_VERSION: 03414 if (request->version) 03415 { 03416 DWORD len = strlenW(request->version); 03417 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) 03418 { 03419 *lpdwBufferLength = (len + 1) * sizeof(WCHAR); 03420 return ERROR_INSUFFICIENT_BUFFER; 03421 } 03422 if (lpBuffer) 03423 { 03424 memcpy(lpBuffer, request->version, (len + 1) * sizeof(WCHAR)); 03425 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); 03426 } 03427 *lpdwBufferLength = len * sizeof(WCHAR); 03428 return ERROR_SUCCESS; 03429 } 03430 break; 03431 case HTTP_QUERY_CONTENT_ENCODING: 03432 index = HTTP_GetCustomHeaderIndex(request, header_lookup[request->read_gzip ? HTTP_QUERY_CONTENT_TYPE : level], 03433 requested_index,request_only); 03434 break; 03435 default: 03436 assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1)); 03437 03438 if (level < LAST_TABLE_HEADER && header_lookup[level]) 03439 index = HTTP_GetCustomHeaderIndex(request, header_lookup[level], 03440 requested_index,request_only); 03441 } 03442 03443 if (index >= 0) 03444 lphttpHdr = &request->custHeaders[index]; 03445 03446 /* Ensure header satisfies requested attributes */ 03447 if (!lphttpHdr || 03448 ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && 03449 (~lphttpHdr->wFlags & HDR_ISREQUEST))) 03450 { 03451 return ERROR_HTTP_HEADER_NOT_FOUND; 03452 } 03453 03454 if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++; 03455 03456 /* coalesce value to requested type */ 03457 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) 03458 { 03459 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); 03460 TRACE(" returning number: %d\n", *(int *)lpBuffer); 03461 } 03462 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) 03463 { 03464 time_t tmpTime; 03465 struct tm tmpTM; 03466 SYSTEMTIME *STHook; 03467 03468 tmpTime = ConvertTimeString(lphttpHdr->lpszValue); 03469 03470 tmpTM = *gmtime(&tmpTime); 03471 STHook = (SYSTEMTIME *)lpBuffer; 03472 STHook->wDay = tmpTM.tm_mday; 03473 STHook->wHour = tmpTM.tm_hour; 03474 STHook->wMilliseconds = 0; 03475 STHook->wMinute = tmpTM.tm_min; 03476 STHook->wDayOfWeek = tmpTM.tm_wday; 03477 STHook->wMonth = tmpTM.tm_mon + 1; 03478 STHook->wSecond = tmpTM.tm_sec; 03479 STHook->wYear = tmpTM.tm_year; 03480 03481 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", 03482 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, 03483 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); 03484 } 03485 else if (lphttpHdr->lpszValue) 03486 { 03487 DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR); 03488 03489 if (len > *lpdwBufferLength) 03490 { 03491 *lpdwBufferLength = len; 03492 return ERROR_INSUFFICIENT_BUFFER; 03493 } 03494 if (lpBuffer) 03495 { 03496 memcpy(lpBuffer, lphttpHdr->lpszValue, len); 03497 TRACE("! returning string: %s\n", debugstr_w(lpBuffer)); 03498 } 03499 *lpdwBufferLength = len - sizeof(WCHAR); 03500 } 03501 return ERROR_SUCCESS; 03502 } 03503 03504 /*********************************************************************** 03505 * HttpQueryInfoW (WININET.@) 03506 * 03507 * Queries for information about an HTTP request 03508 * 03509 * RETURNS 03510 * TRUE on success 03511 * FALSE on failure 03512 * 03513 */ 03514 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, 03515 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) 03516 { 03517 http_request_t *request; 03518 DWORD res; 03519 03520 if (TRACE_ON(wininet)) { 03521 #define FE(x) { x, #x } 03522 static const wininet_flag_info query_flags[] = { 03523 FE(HTTP_QUERY_MIME_VERSION), 03524 FE(HTTP_QUERY_CONTENT_TYPE), 03525 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING), 03526 FE(HTTP_QUERY_CONTENT_ID), 03527 FE(HTTP_QUERY_CONTENT_DESCRIPTION), 03528 FE(HTTP_QUERY_CONTENT_LENGTH), 03529 FE(HTTP_QUERY_CONTENT_LANGUAGE), 03530 FE(HTTP_QUERY_ALLOW), 03531 FE(HTTP_QUERY_PUBLIC), 03532 FE(HTTP_QUERY_DATE), 03533 FE(HTTP_QUERY_EXPIRES), 03534 FE(HTTP_QUERY_LAST_MODIFIED), 03535 FE(HTTP_QUERY_MESSAGE_ID), 03536 FE(HTTP_QUERY_URI), 03537 FE(HTTP_QUERY_DERIVED_FROM), 03538 FE(HTTP_QUERY_COST), 03539 FE(HTTP_QUERY_LINK), 03540 FE(HTTP_QUERY_PRAGMA), 03541 FE(HTTP_QUERY_VERSION), 03542 FE(HTTP_QUERY_STATUS_CODE), 03543 FE(HTTP_QUERY_STATUS_TEXT), 03544 FE(HTTP_QUERY_RAW_HEADERS), 03545 FE(HTTP_QUERY_RAW_HEADERS_CRLF), 03546 FE(HTTP_QUERY_CONNECTION), 03547 FE(HTTP_QUERY_ACCEPT), 03548 FE(HTTP_QUERY_ACCEPT_CHARSET), 03549 FE(HTTP_QUERY_ACCEPT_ENCODING), 03550 FE(HTTP_QUERY_ACCEPT_LANGUAGE), 03551 FE(HTTP_QUERY_AUTHORIZATION), 03552 FE(HTTP_QUERY_CONTENT_ENCODING), 03553 FE(HTTP_QUERY_FORWARDED), 03554 FE(HTTP_QUERY_FROM), 03555 FE(HTTP_QUERY_IF_MODIFIED_SINCE), 03556 FE(HTTP_QUERY_LOCATION), 03557 FE(HTTP_QUERY_ORIG_URI), 03558 FE(HTTP_QUERY_REFERER), 03559 FE(HTTP_QUERY_RETRY_AFTER), 03560 FE(HTTP_QUERY_SERVER), 03561 FE(HTTP_QUERY_TITLE), 03562 FE(HTTP_QUERY_USER_AGENT), 03563 FE(HTTP_QUERY_WWW_AUTHENTICATE), 03564 FE(HTTP_QUERY_PROXY_AUTHENTICATE), 03565 FE(HTTP_QUERY_ACCEPT_RANGES), 03566 FE(HTTP_QUERY_SET_COOKIE), 03567 FE(HTTP_QUERY_COOKIE), 03568 FE(HTTP_QUERY_REQUEST_METHOD), 03569 FE(HTTP_QUERY_REFRESH), 03570 FE(HTTP_QUERY_CONTENT_DISPOSITION), 03571 FE(HTTP_QUERY_AGE), 03572 FE(HTTP_QUERY_CACHE_CONTROL), 03573 FE(HTTP_QUERY_CONTENT_BASE), 03574 FE(HTTP_QUERY_CONTENT_LOCATION), 03575 FE(HTTP_QUERY_CONTENT_MD5), 03576 FE(HTTP_QUERY_CONTENT_RANGE), 03577 FE(HTTP_QUERY_ETAG), 03578 FE(HTTP_QUERY_HOST), 03579 FE(HTTP_QUERY_IF_MATCH), 03580 FE(HTTP_QUERY_IF_NONE_MATCH), 03581 FE(HTTP_QUERY_IF_RANGE), 03582 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE), 03583 FE(HTTP_QUERY_MAX_FORWARDS), 03584 FE(HTTP_QUERY_PROXY_AUTHORIZATION), 03585 FE(HTTP_QUERY_RANGE), 03586 FE(HTTP_QUERY_TRANSFER_ENCODING), 03587 FE(HTTP_QUERY_UPGRADE), 03588 FE(HTTP_QUERY_VARY), 03589 FE(HTTP_QUERY_VIA), 03590 FE(HTTP_QUERY_WARNING), 03591 FE(HTTP_QUERY_CUSTOM) 03592 }; 03593 static const wininet_flag_info modifier_flags[] = { 03594 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS), 03595 FE(HTTP_QUERY_FLAG_SYSTEMTIME), 03596 FE(HTTP_QUERY_FLAG_NUMBER), 03597 FE(HTTP_QUERY_FLAG_COALESCE) 03598 }; 03599 #undef FE 03600 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK; 03601 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK; 03602 DWORD i; 03603 03604 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info); 03605 TRACE(" Attribute:"); 03606 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) { 03607 if (query_flags[i].val == info) { 03608 TRACE(" %s", query_flags[i].name); 03609 break; 03610 } 03611 } 03612 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) { 03613 TRACE(" Unknown (%08x)", info); 03614 } 03615 03616 TRACE(" Modifier:"); 03617 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) { 03618 if (modifier_flags[i].val & info_mod) { 03619 TRACE(" %s", modifier_flags[i].name); 03620 info_mod &= ~ modifier_flags[i].val; 03621 } 03622 } 03623 03624 if (info_mod) { 03625 TRACE(" Unknown (%08x)", info_mod); 03626 } 03627 TRACE("\n"); 03628 } 03629 03630 request = (http_request_t*) get_handle_object( hHttpRequest ); 03631 if (NULL == request || request->hdr.htype != WH_HHTTPREQ) 03632 { 03633 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 03634 goto lend; 03635 } 03636 03637 if (lpBuffer == NULL) 03638 *lpdwBufferLength = 0; 03639 res = HTTP_HttpQueryInfoW( request, dwInfoLevel, 03640 lpBuffer, lpdwBufferLength, lpdwIndex); 03641 03642 lend: 03643 if( request ) 03644 WININET_Release( &request->hdr ); 03645 03646 TRACE("%u <--\n", res); 03647 if(res != ERROR_SUCCESS) 03648 SetLastError(res); 03649 return res == ERROR_SUCCESS; 03650 } 03651 03652 /*********************************************************************** 03653 * HttpQueryInfoA (WININET.@) 03654 * 03655 * Queries for information about an HTTP request 03656 * 03657 * RETURNS 03658 * TRUE on success 03659 * FALSE on failure 03660 * 03661 */ 03662 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, 03663 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) 03664 { 03665 BOOL result; 03666 DWORD len; 03667 WCHAR* bufferW; 03668 03669 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) || 03670 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)) 03671 { 03672 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer, 03673 lpdwBufferLength, lpdwIndex ); 03674 } 03675 03676 if (lpBuffer) 03677 { 03678 DWORD alloclen; 03679 len = (*lpdwBufferLength)*sizeof(WCHAR); 03680 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM) 03681 { 03682 alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR); 03683 if (alloclen < len) 03684 alloclen = len; 03685 } 03686 else 03687 alloclen = len; 03688 bufferW = heap_alloc(alloclen); 03689 /* buffer is in/out because of HTTP_QUERY_CUSTOM */ 03690 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM) 03691 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) ); 03692 } else 03693 { 03694 bufferW = NULL; 03695 len = 0; 03696 } 03697 03698 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW, 03699 &len, lpdwIndex ); 03700 if( result ) 03701 { 03702 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1, 03703 lpBuffer, *lpdwBufferLength, NULL, NULL ); 03704 *lpdwBufferLength = len - 1; 03705 03706 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer)); 03707 } 03708 else 03709 /* since the strings being returned from HttpQueryInfoW should be 03710 * only ASCII characters, it is reasonable to assume that all of 03711 * the Unicode characters can be reduced to a single byte */ 03712 *lpdwBufferLength = len / sizeof(WCHAR); 03713 03714 HeapFree(GetProcessHeap(), 0, bufferW ); 03715 03716 return result; 03717 } 03718 03719 /*********************************************************************** 03720 * HTTP_GetRedirectURL (internal) 03721 */ 03722 static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl) 03723 { 03724 static WCHAR szHttp[] = {'h','t','t','p',0}; 03725 static WCHAR szHttps[] = {'h','t','t','p','s',0}; 03726 http_session_t *session = request->session; 03727 URL_COMPONENTSW urlComponents; 03728 DWORD url_length = 0; 03729 LPWSTR orig_url; 03730 LPWSTR combined_url; 03731 03732 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); 03733 urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; 03734 urlComponents.dwSchemeLength = 0; 03735 urlComponents.lpszHostName = session->hostName; 03736 urlComponents.dwHostNameLength = 0; 03737 urlComponents.nPort = session->hostPort; 03738 urlComponents.lpszUserName = session->userName; 03739 urlComponents.dwUserNameLength = 0; 03740 urlComponents.lpszPassword = NULL; 03741 urlComponents.dwPasswordLength = 0; 03742 urlComponents.lpszUrlPath = request->path; 03743 urlComponents.dwUrlPathLength = 0; 03744 urlComponents.lpszExtraInfo = NULL; 03745 urlComponents.dwExtraInfoLength = 0; 03746 03747 if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && 03748 (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) 03749 return NULL; 03750 03751 orig_url = heap_alloc(url_length); 03752 03753 /* convert from bytes to characters */ 03754 url_length = url_length / sizeof(WCHAR) - 1; 03755 if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) 03756 { 03757 HeapFree(GetProcessHeap(), 0, orig_url); 03758 return NULL; 03759 } 03760 03761 url_length = 0; 03762 if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && 03763 (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) 03764 { 03765 HeapFree(GetProcessHeap(), 0, orig_url); 03766 return NULL; 03767 } 03768 combined_url = heap_alloc(url_length * sizeof(WCHAR)); 03769 03770 if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) 03771 { 03772 HeapFree(GetProcessHeap(), 0, orig_url); 03773 HeapFree(GetProcessHeap(), 0, combined_url); 03774 return NULL; 03775 } 03776 HeapFree(GetProcessHeap(), 0, orig_url); 03777 return combined_url; 03778 } 03779 03780 03781 /*********************************************************************** 03782 * HTTP_HandleRedirect (internal) 03783 */ 03784 static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl) 03785 { 03786 http_session_t *session = request->session; 03787 appinfo_t *hIC = session->appInfo; 03788 BOOL using_proxy = hIC->proxy && hIC->proxy[0]; 03789 WCHAR path[INTERNET_MAX_URL_LENGTH]; 03790 int index; 03791 03792 if(lpszUrl[0]=='/') 03793 { 03794 /* if it's an absolute path, keep the same session info */ 03795 lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH); 03796 } 03797 else 03798 { 03799 URL_COMPONENTSW urlComponents; 03800 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; 03801 static WCHAR szHttp[] = {'h','t','t','p',0}; 03802 static WCHAR szHttps[] = {'h','t','t','p','s',0}; 03803 03804 userName[0] = 0; 03805 hostName[0] = 0; 03806 protocol[0] = 0; 03807 03808 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); 03809 urlComponents.lpszScheme = protocol; 03810 urlComponents.dwSchemeLength = 32; 03811 urlComponents.lpszHostName = hostName; 03812 urlComponents.dwHostNameLength = MAXHOSTNAME; 03813 urlComponents.lpszUserName = userName; 03814 urlComponents.dwUserNameLength = 1024; 03815 urlComponents.lpszPassword = NULL; 03816 urlComponents.dwPasswordLength = 0; 03817 urlComponents.lpszUrlPath = path; 03818 urlComponents.dwUrlPathLength = 2048; 03819 urlComponents.lpszExtraInfo = NULL; 03820 urlComponents.dwExtraInfoLength = 0; 03821 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) 03822 return INTERNET_GetLastError(); 03823 03824 if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && 03825 (request->hdr.dwFlags & INTERNET_FLAG_SECURE)) 03826 { 03827 TRACE("redirect from secure page to non-secure page\n"); 03828 /* FIXME: warn about from secure redirect to non-secure page */ 03829 request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE; 03830 } 03831 if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) && 03832 !(request->hdr.dwFlags & INTERNET_FLAG_SECURE)) 03833 { 03834 TRACE("redirect from non-secure page to secure page\n"); 03835 /* FIXME: notify about redirect to secure page */ 03836 request->hdr.dwFlags |= INTERNET_FLAG_SECURE; 03837 } 03838 03839 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) 03840 { 03841 if (lstrlenW(protocol)>4) /*https*/ 03842 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT; 03843 else /*http*/ 03844 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; 03845 } 03846 03847 #if 0 03848 /* 03849 * This upsets redirects to binary files on sourceforge.net 03850 * and gives an html page instead of the target file 03851 * Examination of the HTTP request sent by native wininet.dll 03852 * reveals that it doesn't send a referrer in that case. 03853 * Maybe there's a flag that enables this, or maybe a referrer 03854 * shouldn't be added in case of a redirect. 03855 */ 03856 03857 /* consider the current host as the referrer */ 03858 if (session->lpszServerName && *session->lpszServerName) 03859 HTTP_ProcessHeader(request, HTTP_REFERER, session->lpszServerName, 03860 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE| 03861 HTTP_ADDHDR_FLAG_ADD_IF_NEW); 03862 #endif 03863 03864 HeapFree(GetProcessHeap(), 0, session->hostName); 03865 if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT && 03866 urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT) 03867 { 03868 int len; 03869 static const WCHAR fmt[] = {'%','s',':','%','u',0}; 03870 len = lstrlenW(hostName); 03871 len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */ 03872 session->hostName = heap_alloc(len*sizeof(WCHAR)); 03873 sprintfW(session->hostName, fmt, hostName, urlComponents.nPort); 03874 } 03875 else 03876 session->hostName = heap_strdupW(hostName); 03877 03878 HTTP_ProcessHeader(request, hostW, session->hostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); 03879 03880 HeapFree(GetProcessHeap(), 0, session->userName); 03881 session->userName = NULL; 03882 if (userName[0]) 03883 session->userName = heap_strdupW(userName); 03884 03885 reset_data_stream(request); 03886 03887 if(!using_proxy) { 03888 if(strcmpiW(session->serverName, hostName)) { 03889 HeapFree(GetProcessHeap(), 0, session->serverName); 03890 session->serverName = heap_strdupW(hostName); 03891 } 03892 session->serverPort = urlComponents.nPort; 03893 } 03894 } 03895 03896 HeapFree(GetProcessHeap(), 0, request->path); 03897 request->path=NULL; 03898 if (*path) 03899 { 03900 DWORD needed = 0; 03901 HRESULT rc; 03902 03903 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY); 03904 if (rc != E_POINTER) 03905 needed = strlenW(path)+1; 03906 request->path = heap_alloc(needed*sizeof(WCHAR)); 03907 rc = UrlEscapeW(path, request->path, &needed, 03908 URL_ESCAPE_SPACES_ONLY); 03909 if (rc != S_OK) 03910 { 03911 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc); 03912 strcpyW(request->path,path); 03913 } 03914 } 03915 03916 /* Remove custom content-type/length headers on redirects. */ 03917 index = HTTP_GetCustomHeaderIndex(request, szContent_Type, 0, TRUE); 03918 if (0 <= index) 03919 HTTP_DeleteCustomHeader(request, index); 03920 index = HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE); 03921 if (0 <= index) 03922 HTTP_DeleteCustomHeader(request, index); 03923 03924 return ERROR_SUCCESS; 03925 } 03926 03927 /*********************************************************************** 03928 * HTTP_build_req (internal) 03929 * 03930 * concatenate all the strings in the request together 03931 */ 03932 static LPWSTR HTTP_build_req( LPCWSTR *list, int len ) 03933 { 03934 LPCWSTR *t; 03935 LPWSTR str; 03936 03937 for( t = list; *t ; t++ ) 03938 len += strlenW( *t ); 03939 len++; 03940 03941 str = heap_alloc(len*sizeof(WCHAR)); 03942 *str = 0; 03943 03944 for( t = list; *t ; t++ ) 03945 strcatW( str, *t ); 03946 03947 return str; 03948 } 03949 03950 static DWORD HTTP_SecureProxyConnect(http_request_t *request) 03951 { 03952 LPWSTR lpszPath; 03953 LPWSTR requestString; 03954 INT len; 03955 INT cnt; 03956 INT responseLen; 03957 char *ascii_req; 03958 DWORD res; 03959 static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0}; 03960 static const WCHAR szFormat[] = {'%','s',':','%','u',0}; 03961 http_session_t *session = request->session; 03962 03963 TRACE("\n"); 03964 03965 lpszPath = heap_alloc((lstrlenW( session->hostName ) + 13)*sizeof(WCHAR)); 03966 sprintfW( lpszPath, szFormat, session->hostName, session->hostPort ); 03967 requestString = HTTP_BuildHeaderRequestString( request, szConnect, lpszPath, g_szHttp1_1 ); 03968 HeapFree( GetProcessHeap(), 0, lpszPath ); 03969 03970 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, 03971 NULL, 0, NULL, NULL ); 03972 len--; /* the nul terminator isn't needed */ 03973 ascii_req = heap_alloc(len); 03974 WideCharToMultiByte( CP_ACP, 0, requestString, -1, 03975 ascii_req, len, NULL, NULL ); 03976 HeapFree( GetProcessHeap(), 0, requestString ); 03977 03978 TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) ); 03979 03980 res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt ); 03981 HeapFree( GetProcessHeap(), 0, ascii_req ); 03982 if (res != ERROR_SUCCESS) 03983 return res; 03984 03985 responseLen = HTTP_GetResponseHeaders( request, TRUE ); 03986 if (!responseLen) 03987 return ERROR_HTTP_INVALID_HEADER; 03988 03989 return ERROR_SUCCESS; 03990 } 03991 03992 static void HTTP_InsertCookies(http_request_t *request) 03993 { 03994 DWORD cookie_size, size, cnt = 0; 03995 HTTPHEADERW *host; 03996 WCHAR *cookies; 03997 03998 static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' ',0}; 03999 04000 host = HTTP_GetHeader(request, hostW); 04001 if(!host) 04002 return; 04003 04004 if(!get_cookie(host->lpszValue, request->path, NULL, &cookie_size)) 04005 return; 04006 04007 size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf); 04008 if(!(cookies = heap_alloc(size))) 04009 return; 04010 04011 cnt += sprintfW(cookies, cookieW); 04012 get_cookie(host->lpszValue, request->path, cookies+cnt, &cookie_size); 04013 strcatW(cookies, szCrLf); 04014 04015 HTTP_HttpAddRequestHeadersW(request, cookies, strlenW(cookies), HTTP_ADDREQ_FLAG_REPLACE); 04016 04017 heap_free(cookies); 04018 } 04019 04020 static WORD HTTP_ParseDay(LPCWSTR day) 04021 { 04022 static const WCHAR days[7][4] = {{ 's','u','n',0 }, 04023 { 'm','o','n',0 }, 04024 { 't','u','e',0 }, 04025 { 'w','e','d',0 }, 04026 { 't','h','u',0 }, 04027 { 'f','r','i',0 }, 04028 { 's','a','t',0 }}; 04029 int i; 04030 for (i = 0; i < sizeof(days)/sizeof(*days); i++) 04031 if (!strcmpiW(day, days[i])) 04032 return i; 04033 04034 /* Invalid */ 04035 return 7; 04036 } 04037 04038 static WORD HTTP_ParseMonth(LPCWSTR month) 04039 { 04040 static const WCHAR jan[] = { 'j','a','n',0 }; 04041 static const WCHAR feb[] = { 'f','e','b',0 }; 04042 static const WCHAR mar[] = { 'm','a','r',0 }; 04043 static const WCHAR apr[] = { 'a','p','r',0 }; 04044 static const WCHAR may[] = { 'm','a','y',0 }; 04045 static const WCHAR jun[] = { 'j','u','n',0 }; 04046 static const WCHAR jul[] = { 'j','u','l',0 }; 04047 static const WCHAR aug[] = { 'a','u','g',0 }; 04048 static const WCHAR sep[] = { 's','e','p',0 }; 04049 static const WCHAR oct[] = { 'o','c','t',0 }; 04050 static const WCHAR nov[] = { 'n','o','v',0 }; 04051 static const WCHAR dec[] = { 'd','e','c',0 }; 04052 04053 if (!strcmpiW(month, jan)) return 1; 04054 if (!strcmpiW(month, feb)) return 2; 04055 if (!strcmpiW(month, mar)) return 3; 04056 if (!strcmpiW(month, apr)) return 4; 04057 if (!strcmpiW(month, may)) return 5; 04058 if (!strcmpiW(month, jun)) return 6; 04059 if (!strcmpiW(month, jul)) return 7; 04060 if (!strcmpiW(month, aug)) return 8; 04061 if (!strcmpiW(month, sep)) return 9; 04062 if (!strcmpiW(month, oct)) return 10; 04063 if (!strcmpiW(month, nov)) return 11; 04064 if (!strcmpiW(month, dec)) return 12; 04065 /* Invalid */ 04066 return 0; 04067 } 04068 04069 /* Parses the string pointed to by *str, assumed to be a 24-hour time HH:MM:SS, 04070 * optionally preceded by whitespace. 04071 * Upon success, returns TRUE, sets the wHour, wMinute, and wSecond fields of 04072 * st, and sets *str to the first character after the time format. 04073 */ 04074 static BOOL HTTP_ParseTime(SYSTEMTIME *st, LPCWSTR *str) 04075 { 04076 LPCWSTR ptr = *str; 04077 WCHAR *nextPtr; 04078 unsigned long num; 04079 04080 while (isspaceW(*ptr)) 04081 ptr++; 04082 04083 num = strtoulW(ptr, &nextPtr, 10); 04084 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':') 04085 { 04086 ERR("unexpected time format %s\n", debugstr_w(ptr)); 04087 return FALSE; 04088 } 04089 if (num > 23) 04090 { 04091 ERR("unexpected hour in time format %s\n", debugstr_w(ptr)); 04092 return FALSE; 04093 } 04094 ptr = nextPtr + 1; 04095 st->wHour = (WORD)num; 04096 num = strtoulW(ptr, &nextPtr, 10); 04097 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':') 04098 { 04099 ERR("unexpected time format %s\n", debugstr_w(ptr)); 04100 return FALSE; 04101 } 04102 if (num > 59) 04103 { 04104 ERR("unexpected minute in time format %s\n", debugstr_w(ptr)); 04105 return FALSE; 04106 } 04107 ptr = nextPtr + 1; 04108 st->wMinute = (WORD)num; 04109 num = strtoulW(ptr, &nextPtr, 10); 04110 if (!nextPtr || nextPtr <= ptr) 04111 { 04112 ERR("unexpected time format %s\n", debugstr_w(ptr)); 04113 return FALSE; 04114 } 04115 if (num > 59) 04116 { 04117 ERR("unexpected second in time format %s\n", debugstr_w(ptr)); 04118 return FALSE; 04119 } 04120 ptr = nextPtr + 1; 04121 *str = ptr; 04122 st->wSecond = (WORD)num; 04123 return TRUE; 04124 } 04125 04126 static BOOL HTTP_ParseDateAsAsctime(LPCWSTR value, FILETIME *ft) 04127 { 04128 static const WCHAR gmt[]= { 'G','M','T',0 }; 04129 WCHAR day[4], *dayPtr, month[4], *monthPtr, *nextPtr; 04130 LPCWSTR ptr; 04131 SYSTEMTIME st = { 0 }; 04132 unsigned long num; 04133 04134 for (ptr = value, dayPtr = day; *ptr && !isspaceW(*ptr) && 04135 dayPtr - day < sizeof(day) / sizeof(day[0]) - 1; ptr++, dayPtr++) 04136 *dayPtr = *ptr; 04137 *dayPtr = 0; 04138 st.wDayOfWeek = HTTP_ParseDay(day); 04139 if (st.wDayOfWeek >= 7) 04140 { 04141 ERR("unexpected weekday %s\n", debugstr_w(day)); 04142 return FALSE; 04143 } 04144 04145 while (isspaceW(*ptr)) 04146 ptr++; 04147 04148 for (monthPtr = month; !isspace(*ptr) && 04149 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1; 04150 monthPtr++, ptr++) 04151 *monthPtr = *ptr; 04152 *monthPtr = 0; 04153 st.wMonth = HTTP_ParseMonth(month); 04154 if (!st.wMonth || st.wMonth > 12) 04155 { 04156 ERR("unexpected month %s\n", debugstr_w(month)); 04157 return FALSE; 04158 } 04159 04160 while (isspaceW(*ptr)) 04161 ptr++; 04162 04163 num = strtoulW(ptr, &nextPtr, 10); 04164 if (!nextPtr || nextPtr <= ptr || !num || num > 31) 04165 { 04166 ERR("unexpected day %s\n", debugstr_w(ptr)); 04167 return FALSE; 04168 } 04169 ptr = nextPtr; 04170 st.wDay = (WORD)num; 04171 04172 while (isspaceW(*ptr)) 04173 ptr++; 04174 04175 if (!HTTP_ParseTime(&st, &ptr)) 04176 return FALSE; 04177 04178 while (isspaceW(*ptr)) 04179 ptr++; 04180 04181 num = strtoulW(ptr, &nextPtr, 10); 04182 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827) 04183 { 04184 ERR("unexpected year %s\n", debugstr_w(ptr)); 04185 return FALSE; 04186 } 04187 ptr = nextPtr; 04188 st.wYear = (WORD)num; 04189 04190 while (isspaceW(*ptr)) 04191 ptr++; 04192 04193 /* asctime() doesn't report a timezone, but some web servers do, so accept 04194 * with or without GMT. 04195 */ 04196 if (*ptr && strcmpW(ptr, gmt)) 04197 { 04198 ERR("unexpected timezone %s\n", debugstr_w(ptr)); 04199 return FALSE; 04200 } 04201 return SystemTimeToFileTime(&st, ft); 04202 } 04203 04204 static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft) 04205 { 04206 static const WCHAR gmt[]= { 'G','M','T',0 }; 04207 WCHAR *nextPtr, day[4], month[4], *monthPtr; 04208 LPCWSTR ptr; 04209 unsigned long num; 04210 SYSTEMTIME st = { 0 }; 04211 04212 ptr = strchrW(value, ','); 04213 if (!ptr) 04214 return FALSE; 04215 if (ptr - value != 3) 04216 { 04217 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); 04218 return FALSE; 04219 } 04220 memcpy(day, value, (ptr - value) * sizeof(WCHAR)); 04221 day[3] = 0; 04222 st.wDayOfWeek = HTTP_ParseDay(day); 04223 if (st.wDayOfWeek > 6) 04224 { 04225 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); 04226 return FALSE; 04227 } 04228 ptr++; 04229 04230 while (isspaceW(*ptr)) 04231 ptr++; 04232 04233 num = strtoulW(ptr, &nextPtr, 10); 04234 if (!nextPtr || nextPtr <= ptr || !num || num > 31) 04235 { 04236 ERR("unexpected day %s\n", debugstr_w(value)); 04237 return FALSE; 04238 } 04239 ptr = nextPtr; 04240 st.wDay = (WORD)num; 04241 04242 while (isspaceW(*ptr)) 04243 ptr++; 04244 04245 for (monthPtr = month; !isspace(*ptr) && 04246 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1; 04247 monthPtr++, ptr++) 04248 *monthPtr = *ptr; 04249 *monthPtr = 0; 04250 st.wMonth = HTTP_ParseMonth(month); 04251 if (!st.wMonth || st.wMonth > 12) 04252 { 04253 ERR("unexpected month %s\n", debugstr_w(month)); 04254 return FALSE; 04255 } 04256 04257 while (isspaceW(*ptr)) 04258 ptr++; 04259 04260 num = strtoulW(ptr, &nextPtr, 10); 04261 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827) 04262 { 04263 ERR("unexpected year %s\n", debugstr_w(value)); 04264 return FALSE; 04265 } 04266 ptr = nextPtr; 04267 st.wYear = (WORD)num; 04268 04269 if (!HTTP_ParseTime(&st, &ptr)) 04270 return FALSE; 04271 04272 while (isspaceW(*ptr)) 04273 ptr++; 04274 04275 if (strcmpW(ptr, gmt)) 04276 { 04277 ERR("unexpected time zone %s\n", debugstr_w(ptr)); 04278 return FALSE; 04279 } 04280 return SystemTimeToFileTime(&st, ft); 04281 } 04282 04283 /* FIXME: only accepts dates in RFC 1123 format and asctime() format, 04284 * which may not be the only formats actually seen in the wild. 04285 * http://www.hackcraft.net/web/datetime/ suggests at least RFC 850 dates 04286 * should be accepted as well. 04287 */ 04288 static BOOL HTTP_ParseDate(LPCWSTR value, FILETIME *ft) 04289 { 04290 static const WCHAR zero[] = { '0',0 }; 04291 BOOL ret; 04292 04293 if (!strcmpW(value, zero)) 04294 { 04295 ft->dwLowDateTime = ft->dwHighDateTime = 0; 04296 ret = TRUE; 04297 } 04298 else if (strchrW(value, ',')) 04299 ret = HTTP_ParseRfc1123Date(value, ft); 04300 else 04301 { 04302 ret = HTTP_ParseDateAsAsctime(value, ft); 04303 if (!ret) 04304 ERR("unexpected date format %s\n", debugstr_w(value)); 04305 } 04306 return ret; 04307 } 04308 04309 static void HTTP_ProcessExpires(http_request_t *request) 04310 { 04311 BOOL expirationFound = FALSE; 04312 int headerIndex; 04313 04314 /* Look for a Cache-Control header with a max-age directive, as it takes 04315 * precedence over the Expires header. 04316 */ 04317 headerIndex = HTTP_GetCustomHeaderIndex(request, szCache_Control, 0, FALSE); 04318 if (headerIndex != -1) 04319 { 04320 LPHTTPHEADERW ccHeader = &request->custHeaders[headerIndex]; 04321 LPWSTR ptr; 04322 04323 for (ptr = ccHeader->lpszValue; ptr && *ptr; ) 04324 { 04325 LPWSTR comma = strchrW(ptr, ','), end, equal; 04326 04327 if (comma) 04328 end = comma; 04329 else 04330 end = ptr + strlenW(ptr); 04331 for (equal = end - 1; equal > ptr && *equal != '='; equal--) 04332 ; 04333 if (*equal == '=') 04334 { 04335 static const WCHAR max_age[] = { 04336 'm','a','x','-','a','g','e',0 }; 04337 04338 if (!strncmpiW(ptr, max_age, equal - ptr - 1)) 04339 { 04340 LPWSTR nextPtr; 04341 unsigned long age; 04342 04343 age = strtoulW(equal + 1, &nextPtr, 10); 04344 if (nextPtr > equal + 1) 04345 { 04346 LARGE_INTEGER ft; 04347 04348 NtQuerySystemTime( &ft ); 04349 /* Age is in seconds, FILETIME resolution is in 04350 * 100 nanosecond intervals. 04351 */ 04352 ft.QuadPart += age * (ULONGLONG)1000000; 04353 request->expires.dwLowDateTime = ft.u.LowPart; 04354 request->expires.dwHighDateTime = ft.u.HighPart; 04355 expirationFound = TRUE; 04356 } 04357 } 04358 } 04359 if (comma) 04360 { 04361 ptr = comma + 1; 04362 while (isspaceW(*ptr)) 04363 ptr++; 04364 } 04365 else 04366 ptr = NULL; 04367 } 04368 } 04369 if (!expirationFound) 04370 { 04371 headerIndex = HTTP_GetCustomHeaderIndex(request, szExpires, 0, FALSE); 04372 if (headerIndex != -1) 04373 { 04374 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex]; 04375 FILETIME ft; 04376 04377 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft)) 04378 { 04379 expirationFound = TRUE; 04380 request->expires = ft; 04381 } 04382 } 04383 } 04384 if (!expirationFound) 04385 { 04386 LARGE_INTEGER t; 04387 04388 /* With no known age, default to 10 minutes until expiration. */ 04389 NtQuerySystemTime( &t ); 04390 t.QuadPart += 10 * 60 * (ULONGLONG)10000000; 04391 request->expires.dwLowDateTime = t.u.LowPart; 04392 request->expires.dwHighDateTime = t.u.HighPart; 04393 } 04394 } 04395 04396 static void HTTP_ProcessLastModified(http_request_t *request) 04397 { 04398 int headerIndex; 04399 04400 headerIndex = HTTP_GetCustomHeaderIndex(request, szLast_Modified, 0, FALSE); 04401 if (headerIndex != -1) 04402 { 04403 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex]; 04404 FILETIME ft; 04405 04406 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft)) 04407 request->last_modified = ft; 04408 } 04409 } 04410 04411 static void http_process_keep_alive(http_request_t *req) 04412 { 04413 int index; 04414 04415 index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE); 04416 if(index != -1) 04417 req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); 04418 else 04419 req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1); 04420 } 04421 04422 static void HTTP_CacheRequest(http_request_t *request) 04423 { 04424 WCHAR url[INTERNET_MAX_URL_LENGTH]; 04425 WCHAR cacheFileName[MAX_PATH+1]; 04426 BOOL b; 04427 04428 b = HTTP_GetRequestURL(request, url); 04429 if(!b) { 04430 WARN("Could not get URL\n"); 04431 return; 04432 } 04433 04434 b = CreateUrlCacheEntryW(url, request->contentLength, NULL, cacheFileName, 0); 04435 if(b) { 04436 HeapFree(GetProcessHeap(), 0, request->cacheFile); 04437 CloseHandle(request->hCacheFile); 04438 04439 request->cacheFile = heap_strdupW(cacheFileName); 04440 request->hCacheFile = CreateFileW(request->cacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 04441 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 04442 if(request->hCacheFile == INVALID_HANDLE_VALUE) { 04443 WARN("Could not create file: %u\n", GetLastError()); 04444 request->hCacheFile = NULL; 04445 } 04446 }else { 04447 WARN("Could not create cache entry: %08x\n", GetLastError()); 04448 } 04449 } 04450 04451 static DWORD open_http_connection(http_request_t *request, BOOL *reusing) 04452 { 04453 const BOOL is_https = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) != 0; 04454 http_session_t *session = request->session; 04455 netconn_t *netconn = NULL; 04456 server_t *server; 04457 DWORD res; 04458 04459 assert(!request->netconn); 04460 reset_data_stream(request); 04461 04462 server = get_server(session->serverName, session->serverPort); 04463 if(!server) 04464 return ERROR_OUTOFMEMORY; 04465 04466 res = HTTP_ResolveName(request, server); 04467 if(res != ERROR_SUCCESS) { 04468 server_release(server); 04469 return res; 04470 } 04471 04472 EnterCriticalSection(&connection_pool_cs); 04473 04474 while(!list_empty(&server->conn_pool)) { 04475 netconn = LIST_ENTRY(list_head(&server->conn_pool), netconn_t, pool_entry); 04476 list_remove(&netconn->pool_entry); 04477 04478 if(NETCON_is_alive(netconn)) 04479 break; 04480 04481 TRACE("connection %p closed during idle\n", netconn); 04482 free_netconn(netconn); 04483 netconn = NULL; 04484 } 04485 04486 LeaveCriticalSection(&connection_pool_cs); 04487 04488 if(netconn) { 04489 TRACE("<-- reusing %p netconn\n", netconn); 04490 request->netconn = netconn; 04491 *reusing = TRUE; 04492 return ERROR_SUCCESS; 04493 } 04494 04495 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04496 INTERNET_STATUS_CONNECTING_TO_SERVER, 04497 server->addr_str, 04498 strlen(server->addr_str)+1); 04499 04500 res = create_netconn(is_https, server, request->security_flags, &netconn); 04501 server_release(server); 04502 if(res != ERROR_SUCCESS) { 04503 ERR("create_netconn failed: %u\n", res); 04504 return res; 04505 } 04506 04507 request->netconn = netconn; 04508 04509 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04510 INTERNET_STATUS_CONNECTED_TO_SERVER, 04511 server->addr_str, strlen(server->addr_str)+1); 04512 04513 if(is_https) { 04514 /* Note: we differ from Microsoft's WinINet here. they seem to have 04515 * a bug that causes no status callbacks to be sent when starting 04516 * a tunnel to a proxy server using the CONNECT verb. i believe our 04517 * behaviour to be more correct and to not cause any incompatibilities 04518 * because using a secure connection through a proxy server is a rare 04519 * case that would be hard for anyone to depend on */ 04520 if(session->appInfo->proxy) 04521 res = HTTP_SecureProxyConnect(request); 04522 if(res == ERROR_SUCCESS) 04523 res = NETCON_secure_connect(request->netconn, session->hostName); 04524 if(res != ERROR_SUCCESS) 04525 { 04526 WARN("Couldn't connect securely to host\n"); 04527 04528 if((request->hdr.ErrorMask&INTERNET_ERROR_MASK_COMBINED_SEC_CERT) && ( 04529 res == ERROR_INTERNET_SEC_CERT_DATE_INVALID 04530 || res == ERROR_INTERNET_INVALID_CA 04531 || res == ERROR_INTERNET_SEC_CERT_NO_REV 04532 || res == ERROR_INTERNET_SEC_CERT_REV_FAILED 04533 || res == ERROR_INTERNET_SEC_CERT_REVOKED 04534 || res == ERROR_INTERNET_SEC_INVALID_CERT 04535 || res == ERROR_INTERNET_SEC_CERT_CN_INVALID)) 04536 res = ERROR_INTERNET_SEC_CERT_ERRORS; 04537 } 04538 } 04539 04540 if(res != ERROR_SUCCESS) { 04541 http_release_netconn(request, FALSE); 04542 return res; 04543 } 04544 04545 *reusing = FALSE; 04546 TRACE("Created connection to %s: %p\n", debugstr_w(server->name), netconn); 04547 return ERROR_SUCCESS; 04548 } 04549 04550 /*********************************************************************** 04551 * HTTP_HttpSendRequestW (internal) 04552 * 04553 * Sends the specified request to the HTTP server 04554 * 04555 * RETURNS 04556 * ERROR_SUCCESS on success 04557 * win32 error code on failure 04558 * 04559 */ 04560 static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, 04561 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, 04562 DWORD dwContentLength, BOOL bEndRequest) 04563 { 04564 INT cnt; 04565 BOOL redirected = FALSE; 04566 LPWSTR requestString = NULL; 04567 INT responseLen; 04568 BOOL loop_next; 04569 INTERNET_ASYNC_RESULT iar; 04570 static const WCHAR szPost[] = { 'P','O','S','T',0 }; 04571 static const WCHAR szContentLength[] = 04572 { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; 04573 WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; 04574 DWORD res; 04575 04576 TRACE("--> %p\n", request); 04577 04578 assert(request->hdr.htype == WH_HHTTPREQ); 04579 04580 /* if the verb is NULL default to GET */ 04581 if (!request->verb) 04582 request->verb = heap_strdupW(szGET); 04583 04584 if (dwContentLength || strcmpW(request->verb, szGET)) 04585 { 04586 sprintfW(contentLengthStr, szContentLength, dwContentLength); 04587 HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE); 04588 request->bytesToWrite = dwContentLength; 04589 } 04590 if (request->session->appInfo->agent) 04591 { 04592 WCHAR *agent_header; 04593 static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0}; 04594 int len; 04595 04596 len = strlenW(request->session->appInfo->agent) + strlenW(user_agent); 04597 agent_header = heap_alloc(len * sizeof(WCHAR)); 04598 sprintfW(agent_header, user_agent, request->session->appInfo->agent); 04599 04600 HTTP_HttpAddRequestHeadersW(request, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW); 04601 HeapFree(GetProcessHeap(), 0, agent_header); 04602 } 04603 if (request->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE) 04604 { 04605 static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0}; 04606 HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW); 04607 } 04608 if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost)) 04609 { 04610 static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':', 04611 ' ','n','o','-','c','a','c','h','e','\r','\n',0}; 04612 HTTP_HttpAddRequestHeadersW(request, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW); 04613 } 04614 04615 do 04616 { 04617 DWORD len; 04618 BOOL reusing_connection; 04619 char *ascii_req; 04620 04621 loop_next = FALSE; 04622 04623 /* like native, just in case the caller forgot to call InternetReadFile 04624 * for all the data */ 04625 drain_content(request); 04626 if(redirected) { 04627 request->contentLength = ~0u; 04628 request->bytesToWrite = 0; 04629 } 04630 04631 if (TRACE_ON(wininet)) 04632 { 04633 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW); 04634 TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(request->path)); 04635 } 04636 04637 HTTP_FixURL(request); 04638 if (request->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION) 04639 { 04640 HTTP_ProcessHeader(request, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE); 04641 } 04642 HTTP_InsertAuthorization(request, request->authInfo, szAuthorization); 04643 HTTP_InsertAuthorization(request, request->proxyAuthInfo, szProxy_Authorization); 04644 04645 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES)) 04646 HTTP_InsertCookies(request); 04647 04648 /* add the headers the caller supplied */ 04649 if( lpszHeaders && dwHeaderLength ) 04650 { 04651 HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength, 04652 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE); 04653 } 04654 04655 if (request->session->appInfo->proxy && request->session->appInfo->proxy[0]) 04656 { 04657 WCHAR *url = HTTP_BuildProxyRequestUrl(request); 04658 requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version); 04659 HeapFree(GetProcessHeap(), 0, url); 04660 } 04661 else 04662 requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); 04663 04664 04665 TRACE("Request header -> %s\n", debugstr_w(requestString) ); 04666 04667 if ((res = open_http_connection(request, &reusing_connection)) != ERROR_SUCCESS) 04668 break; 04669 04670 /* send the request as ASCII, tack on the optional data */ 04671 if (!lpOptional || redirected) 04672 dwOptionalLength = 0; 04673 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, 04674 NULL, 0, NULL, NULL ); 04675 ascii_req = heap_alloc(len + dwOptionalLength); 04676 WideCharToMultiByte( CP_ACP, 0, requestString, -1, 04677 ascii_req, len, NULL, NULL ); 04678 if( lpOptional ) 04679 memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength ); 04680 len = (len + dwOptionalLength - 1); 04681 ascii_req[len] = 0; 04682 TRACE("full request -> %s\n", debugstr_a(ascii_req) ); 04683 04684 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04685 INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 04686 04687 res = NETCON_send(request->netconn, ascii_req, len, 0, &cnt); 04688 HeapFree( GetProcessHeap(), 0, ascii_req ); 04689 if(res != ERROR_SUCCESS) { 04690 TRACE("send failed: %u\n", res); 04691 if(!reusing_connection) 04692 break; 04693 http_release_netconn(request, FALSE); 04694 loop_next = TRUE; 04695 continue; 04696 } 04697 04698 request->bytesWritten = dwOptionalLength; 04699 04700 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04701 INTERNET_STATUS_REQUEST_SENT, 04702 &len, sizeof(DWORD)); 04703 04704 if (bEndRequest) 04705 { 04706 DWORD dwBufferSize; 04707 DWORD dwStatusCode; 04708 04709 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04710 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 04711 04712 responseLen = HTTP_GetResponseHeaders(request, TRUE); 04713 /* FIXME: We should know that connection is closed before sending 04714 * headers. Otherwise wrong callbacks are executed */ 04715 if(!responseLen && reusing_connection) { 04716 TRACE("Connection closed by server, reconnecting\n"); 04717 http_release_netconn(request, FALSE); 04718 loop_next = TRUE; 04719 continue; 04720 } 04721 04722 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04723 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, 04724 sizeof(DWORD)); 04725 04726 http_process_keep_alive(request); 04727 HTTP_ProcessCookies(request); 04728 HTTP_ProcessExpires(request); 04729 HTTP_ProcessLastModified(request); 04730 04731 dwBufferSize = sizeof(dwStatusCode); 04732 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, 04733 &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS) 04734 dwStatusCode = 0; 04735 04736 res = set_content_length(request, dwStatusCode); 04737 if(res != ERROR_SUCCESS) 04738 goto lend; 04739 if(!request->contentLength) 04740 http_release_netconn(request, TRUE); 04741 04742 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen) 04743 { 04744 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; 04745 dwBufferSize=sizeof(szNewLocation); 04746 if ((dwStatusCode == HTTP_STATUS_REDIRECT || 04747 dwStatusCode == HTTP_STATUS_MOVED || 04748 dwStatusCode == HTTP_STATUS_REDIRECT_KEEP_VERB || 04749 dwStatusCode == HTTP_STATUS_REDIRECT_METHOD) && 04750 HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS) 04751 { 04752 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD)) 04753 { 04754 HeapFree(GetProcessHeap(), 0, request->verb); 04755 request->verb = heap_strdupW(szGET); 04756 } 04757 drain_content(request); 04758 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation ))) 04759 { 04760 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT, 04761 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); 04762 res = HTTP_HandleRedirect(request, new_url); 04763 if (res == ERROR_SUCCESS) 04764 { 04765 HeapFree(GetProcessHeap(), 0, requestString); 04766 loop_next = TRUE; 04767 } 04768 HeapFree( GetProcessHeap(), 0, new_url ); 04769 } 04770 redirected = TRUE; 04771 } 04772 } 04773 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS) 04774 { 04775 WCHAR szAuthValue[2048]; 04776 dwBufferSize=2048; 04777 if (dwStatusCode == HTTP_STATUS_DENIED) 04778 { 04779 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW); 04780 DWORD dwIndex = 0; 04781 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) 04782 { 04783 if (HTTP_DoAuthorization(request, szAuthValue, 04784 &request->authInfo, 04785 request->session->userName, 04786 request->session->password, 04787 Host->lpszValue)) 04788 { 04789 HeapFree(GetProcessHeap(), 0, requestString); 04790 loop_next = TRUE; 04791 break; 04792 } 04793 } 04794 04795 if(!loop_next) { 04796 TRACE("Cleaning wrong authorization data\n"); 04797 destroy_authinfo(request->authInfo); 04798 request->authInfo = NULL; 04799 } 04800 } 04801 if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) 04802 { 04803 DWORD dwIndex = 0; 04804 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) 04805 { 04806 if (HTTP_DoAuthorization(request, szAuthValue, 04807 &request->proxyAuthInfo, 04808 request->session->appInfo->proxyUsername, 04809 request->session->appInfo->proxyPassword, 04810 NULL)) 04811 { 04812 loop_next = TRUE; 04813 break; 04814 } 04815 } 04816 04817 if(!loop_next) { 04818 TRACE("Cleaning wrong proxy authorization data\n"); 04819 destroy_authinfo(request->proxyAuthInfo); 04820 request->proxyAuthInfo = NULL; 04821 } 04822 } 04823 } 04824 } 04825 else 04826 res = ERROR_SUCCESS; 04827 } 04828 while (loop_next); 04829 04830 if(res == ERROR_SUCCESS) 04831 HTTP_CacheRequest(request); 04832 04833 lend: 04834 04835 HeapFree(GetProcessHeap(), 0, requestString); 04836 04837 /* TODO: send notification for P3P header */ 04838 04839 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 04840 { 04841 if (res == ERROR_SUCCESS && request->contentLength && request->bytesWritten == request->bytesToWrite) 04842 HTTP_ReceiveRequestData(request, TRUE); 04843 else 04844 { 04845 iar.dwResult = (res==ERROR_SUCCESS ? (DWORD_PTR)request->hdr.hInternet : 0); 04846 iar.dwError = res; 04847 04848 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04849 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 04850 sizeof(INTERNET_ASYNC_RESULT)); 04851 } 04852 } 04853 04854 TRACE("<--\n"); 04855 return res; 04856 } 04857 04858 /*********************************************************************** 04859 * 04860 * Helper functions for the HttpSendRequest(Ex) functions 04861 * 04862 */ 04863 static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) 04864 { 04865 struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; 04866 http_request_t *request = (http_request_t*) workRequest->hdr; 04867 04868 TRACE("%p\n", request); 04869 04870 HTTP_HttpSendRequestW(request, req->lpszHeader, 04871 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, 04872 req->dwContentLength, req->bEndRequest); 04873 04874 HeapFree(GetProcessHeap(), 0, req->lpszHeader); 04875 } 04876 04877 04878 static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext) 04879 { 04880 INT responseLen; 04881 DWORD dwCode, dwCodeLength; 04882 DWORD dwBufferSize; 04883 DWORD res = ERROR_SUCCESS; 04884 04885 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04886 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 04887 04888 responseLen = HTTP_GetResponseHeaders(request, TRUE); 04889 if (!responseLen) 04890 res = ERROR_HTTP_HEADER_NOT_FOUND; 04891 04892 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04893 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); 04894 04895 /* process cookies here. Is this right? */ 04896 http_process_keep_alive(request); 04897 HTTP_ProcessCookies(request); 04898 HTTP_ProcessExpires(request); 04899 HTTP_ProcessLastModified(request); 04900 04901 dwCodeLength = sizeof(dwCode); 04902 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, 04903 &dwCode,&dwCodeLength,NULL) != ERROR_SUCCESS) 04904 dwCode = 0; 04905 04906 if ((res = set_content_length( request, dwCode )) == ERROR_SUCCESS) { 04907 if(!request->contentLength) 04908 http_release_netconn(request, TRUE); 04909 } 04910 04911 if (res == ERROR_SUCCESS && !(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) 04912 { 04913 if (dwCode == HTTP_STATUS_REDIRECT || 04914 dwCode == HTTP_STATUS_MOVED || 04915 dwCode == HTTP_STATUS_REDIRECT_METHOD || 04916 dwCode == HTTP_STATUS_REDIRECT_KEEP_VERB) 04917 { 04918 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; 04919 dwBufferSize=sizeof(szNewLocation); 04920 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS) 04921 { 04922 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD)) 04923 { 04924 HeapFree(GetProcessHeap(), 0, request->verb); 04925 request->verb = heap_strdupW(szGET); 04926 } 04927 drain_content(request); 04928 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation ))) 04929 { 04930 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT, 04931 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); 04932 res = HTTP_HandleRedirect(request, new_url); 04933 if (res == ERROR_SUCCESS) 04934 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE); 04935 HeapFree( GetProcessHeap(), 0, new_url ); 04936 } 04937 } 04938 } 04939 } 04940 04941 if (res == ERROR_SUCCESS && request->contentLength) { 04942 HTTP_ReceiveRequestData(request, TRUE); 04943 }else { 04944 INTERNET_ASYNC_RESULT iar = {0, res}; 04945 04946 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, 04947 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 04948 sizeof(INTERNET_ASYNC_RESULT)); 04949 } 04950 04951 return res; 04952 } 04953 04954 /*********************************************************************** 04955 * HttpEndRequestA (WININET.@) 04956 * 04957 * Ends an HTTP request that was started by HttpSendRequestEx 04958 * 04959 * RETURNS 04960 * TRUE if successful 04961 * FALSE on failure 04962 * 04963 */ 04964 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 04965 LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) 04966 { 04967 TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext); 04968 04969 if (lpBuffersOut) 04970 { 04971 SetLastError(ERROR_INVALID_PARAMETER); 04972 return FALSE; 04973 } 04974 04975 return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext); 04976 } 04977 04978 static void AsyncHttpEndRequestProc(WORKREQUEST *work) 04979 { 04980 struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW; 04981 http_request_t *request = (http_request_t*)work->hdr; 04982 04983 TRACE("%p\n", request); 04984 04985 HTTP_HttpEndRequestW(request, req->dwFlags, req->dwContext); 04986 } 04987 04988 /*********************************************************************** 04989 * HttpEndRequestW (WININET.@) 04990 * 04991 * Ends an HTTP request that was started by HttpSendRequestEx 04992 * 04993 * RETURNS 04994 * TRUE if successful 04995 * FALSE on failure 04996 * 04997 */ 04998 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, 04999 LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) 05000 { 05001 http_request_t *request; 05002 DWORD res; 05003 05004 TRACE("-->\n"); 05005 05006 if (lpBuffersOut) 05007 { 05008 SetLastError(ERROR_INVALID_PARAMETER); 05009 return FALSE; 05010 } 05011 05012 request = (http_request_t*) get_handle_object( hRequest ); 05013 05014 if (NULL == request || request->hdr.htype != WH_HHTTPREQ) 05015 { 05016 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 05017 if (request) 05018 WININET_Release( &request->hdr ); 05019 return FALSE; 05020 } 05021 request->hdr.dwFlags |= dwFlags; 05022 05023 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 05024 { 05025 WORKREQUEST work; 05026 struct WORKREQ_HTTPENDREQUESTW *work_endrequest; 05027 05028 work.asyncproc = AsyncHttpEndRequestProc; 05029 work.hdr = WININET_AddRef( &request->hdr ); 05030 05031 work_endrequest = &work.u.HttpEndRequestW; 05032 work_endrequest->dwFlags = dwFlags; 05033 work_endrequest->dwContext = dwContext; 05034 05035 INTERNET_AsyncCall(&work); 05036 res = ERROR_IO_PENDING; 05037 } 05038 else 05039 res = HTTP_HttpEndRequestW(request, dwFlags, dwContext); 05040 05041 WININET_Release( &request->hdr ); 05042 TRACE("%u <--\n", res); 05043 if(res != ERROR_SUCCESS) 05044 SetLastError(res); 05045 return res == ERROR_SUCCESS; 05046 } 05047 05048 /*********************************************************************** 05049 * HttpSendRequestExA (WININET.@) 05050 * 05051 * Sends the specified request to the HTTP server and allows chunked 05052 * transfers. 05053 * 05054 * RETURNS 05055 * Success: TRUE 05056 * Failure: FALSE, call GetLastError() for more information. 05057 */ 05058 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, 05059 LPINTERNET_BUFFERSA lpBuffersIn, 05060 LPINTERNET_BUFFERSA lpBuffersOut, 05061 DWORD dwFlags, DWORD_PTR dwContext) 05062 { 05063 INTERNET_BUFFERSW BuffersInW; 05064 BOOL rc = FALSE; 05065 DWORD headerlen; 05066 LPWSTR header = NULL; 05067 05068 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, 05069 lpBuffersOut, dwFlags, dwContext); 05070 05071 if (lpBuffersIn) 05072 { 05073 BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); 05074 if (lpBuffersIn->lpcszHeader) 05075 { 05076 headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, 05077 lpBuffersIn->dwHeadersLength,0,0); 05078 header = heap_alloc(headerlen*sizeof(WCHAR)); 05079 if (!(BuffersInW.lpcszHeader = header)) 05080 { 05081 SetLastError(ERROR_OUTOFMEMORY); 05082 return FALSE; 05083 } 05084 BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, 05085 lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, 05086 header, headerlen); 05087 } 05088 else 05089 BuffersInW.lpcszHeader = NULL; 05090 BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; 05091 BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; 05092 BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; 05093 BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; 05094 BuffersInW.Next = NULL; 05095 } 05096 05097 rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); 05098 05099 HeapFree(GetProcessHeap(),0,header); 05100 05101 return rc; 05102 } 05103 05104 /*********************************************************************** 05105 * HttpSendRequestExW (WININET.@) 05106 * 05107 * Sends the specified request to the HTTP server and allows chunked 05108 * transfers 05109 * 05110 * RETURNS 05111 * Success: TRUE 05112 * Failure: FALSE, call GetLastError() for more information. 05113 */ 05114 BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, 05115 LPINTERNET_BUFFERSW lpBuffersIn, 05116 LPINTERNET_BUFFERSW lpBuffersOut, 05117 DWORD dwFlags, DWORD_PTR dwContext) 05118 { 05119 http_request_t *request; 05120 http_session_t *session; 05121 appinfo_t *hIC; 05122 DWORD res; 05123 05124 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, 05125 lpBuffersOut, dwFlags, dwContext); 05126 05127 request = (http_request_t*) get_handle_object( hRequest ); 05128 05129 if (NULL == request || request->hdr.htype != WH_HHTTPREQ) 05130 { 05131 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 05132 goto lend; 05133 } 05134 05135 session = request->session; 05136 assert(session->hdr.htype == WH_HHTTPSESSION); 05137 hIC = session->appInfo; 05138 assert(hIC->hdr.htype == WH_HINIT); 05139 05140 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 05141 { 05142 WORKREQUEST workRequest; 05143 struct WORKREQ_HTTPSENDREQUESTW *req; 05144 05145 workRequest.asyncproc = AsyncHttpSendRequestProc; 05146 workRequest.hdr = WININET_AddRef( &request->hdr ); 05147 req = &workRequest.u.HttpSendRequestW; 05148 if (lpBuffersIn) 05149 { 05150 DWORD size = 0; 05151 05152 if (lpBuffersIn->lpcszHeader) 05153 { 05154 if (lpBuffersIn->dwHeadersLength == ~0u) 05155 size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); 05156 else 05157 size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); 05158 05159 req->lpszHeader = heap_alloc(size); 05160 memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); 05161 } 05162 else req->lpszHeader = NULL; 05163 05164 req->dwHeaderLength = size / sizeof(WCHAR); 05165 req->lpOptional = lpBuffersIn->lpvBuffer; 05166 req->dwOptionalLength = lpBuffersIn->dwBufferLength; 05167 req->dwContentLength = lpBuffersIn->dwBufferTotal; 05168 } 05169 else 05170 { 05171 req->lpszHeader = NULL; 05172 req->dwHeaderLength = 0; 05173 req->lpOptional = NULL; 05174 req->dwOptionalLength = 0; 05175 req->dwContentLength = 0; 05176 } 05177 05178 req->bEndRequest = FALSE; 05179 05180 INTERNET_AsyncCall(&workRequest); 05181 /* 05182 * This is from windows. 05183 */ 05184 res = ERROR_IO_PENDING; 05185 } 05186 else 05187 { 05188 if (lpBuffersIn) 05189 res = HTTP_HttpSendRequestW(request, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, 05190 lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, 05191 lpBuffersIn->dwBufferTotal, FALSE); 05192 else 05193 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, FALSE); 05194 } 05195 05196 lend: 05197 if ( request ) 05198 WININET_Release( &request->hdr ); 05199 05200 TRACE("<---\n"); 05201 SetLastError(res); 05202 return res == ERROR_SUCCESS; 05203 } 05204 05205 /*********************************************************************** 05206 * HttpSendRequestW (WININET.@) 05207 * 05208 * Sends the specified request to the HTTP server 05209 * 05210 * RETURNS 05211 * TRUE on success 05212 * FALSE on failure 05213 * 05214 */ 05215 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, 05216 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) 05217 { 05218 http_request_t *request; 05219 http_session_t *session = NULL; 05220 appinfo_t *hIC = NULL; 05221 DWORD res = ERROR_SUCCESS; 05222 05223 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, 05224 debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); 05225 05226 request = (http_request_t*) get_handle_object( hHttpRequest ); 05227 if (NULL == request || request->hdr.htype != WH_HHTTPREQ) 05228 { 05229 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 05230 goto lend; 05231 } 05232 05233 session = request->session; 05234 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION) 05235 { 05236 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 05237 goto lend; 05238 } 05239 05240 hIC = session->appInfo; 05241 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) 05242 { 05243 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; 05244 goto lend; 05245 } 05246 05247 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 05248 { 05249 WORKREQUEST workRequest; 05250 struct WORKREQ_HTTPSENDREQUESTW *req; 05251 05252 workRequest.asyncproc = AsyncHttpSendRequestProc; 05253 workRequest.hdr = WININET_AddRef( &request->hdr ); 05254 req = &workRequest.u.HttpSendRequestW; 05255 if (lpszHeaders) 05256 { 05257 DWORD size; 05258 05259 if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR); 05260 else size = dwHeaderLength * sizeof(WCHAR); 05261 05262 req->lpszHeader = heap_alloc(size); 05263 memcpy(req->lpszHeader, lpszHeaders, size); 05264 } 05265 else 05266 req->lpszHeader = 0; 05267 req->dwHeaderLength = dwHeaderLength; 05268 req->lpOptional = lpOptional; 05269 req->dwOptionalLength = dwOptionalLength; 05270 req->dwContentLength = dwOptionalLength; 05271 req->bEndRequest = TRUE; 05272 05273 INTERNET_AsyncCall(&workRequest); 05274 /* 05275 * This is from windows. 05276 */ 05277 res = ERROR_IO_PENDING; 05278 } 05279 else 05280 { 05281 res = HTTP_HttpSendRequestW(request, lpszHeaders, 05282 dwHeaderLength, lpOptional, dwOptionalLength, 05283 dwOptionalLength, TRUE); 05284 } 05285 lend: 05286 if( request ) 05287 WININET_Release( &request->hdr ); 05288 05289 SetLastError(res); 05290 return res == ERROR_SUCCESS; 05291 } 05292 05293 /*********************************************************************** 05294 * HttpSendRequestA (WININET.@) 05295 * 05296 * Sends the specified request to the HTTP server 05297 * 05298 * RETURNS 05299 * TRUE on success 05300 * FALSE on failure 05301 * 05302 */ 05303 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, 05304 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) 05305 { 05306 BOOL result; 05307 LPWSTR szHeaders=NULL; 05308 DWORD nLen=dwHeaderLength; 05309 if(lpszHeaders!=NULL) 05310 { 05311 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); 05312 szHeaders = heap_alloc(nLen*sizeof(WCHAR)); 05313 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); 05314 } 05315 result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); 05316 HeapFree(GetProcessHeap(),0,szHeaders); 05317 return result; 05318 } 05319 05320 /*********************************************************************** 05321 * HTTPSESSION_Destroy (internal) 05322 * 05323 * Deallocate session handle 05324 * 05325 */ 05326 static void HTTPSESSION_Destroy(object_header_t *hdr) 05327 { 05328 http_session_t *session = (http_session_t*) hdr; 05329 05330 TRACE("%p\n", session); 05331 05332 WININET_Release(&session->appInfo->hdr); 05333 05334 HeapFree(GetProcessHeap(), 0, session->hostName); 05335 HeapFree(GetProcessHeap(), 0, session->serverName); 05336 HeapFree(GetProcessHeap(), 0, session->password); 05337 HeapFree(GetProcessHeap(), 0, session->userName); 05338 } 05339 05340 static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 05341 { 05342 switch(option) { 05343 case INTERNET_OPTION_HANDLE_TYPE: 05344 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 05345 05346 if (*size < sizeof(ULONG)) 05347 return ERROR_INSUFFICIENT_BUFFER; 05348 05349 *size = sizeof(DWORD); 05350 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP; 05351 return ERROR_SUCCESS; 05352 } 05353 05354 return INET_QueryOption(hdr, option, buffer, size, unicode); 05355 } 05356 05357 static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) 05358 { 05359 http_session_t *ses = (http_session_t*)hdr; 05360 05361 switch(option) { 05362 case INTERNET_OPTION_USERNAME: 05363 { 05364 HeapFree(GetProcessHeap(), 0, ses->userName); 05365 if (!(ses->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; 05366 return ERROR_SUCCESS; 05367 } 05368 case INTERNET_OPTION_PASSWORD: 05369 { 05370 HeapFree(GetProcessHeap(), 0, ses->password); 05371 if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; 05372 return ERROR_SUCCESS; 05373 } 05374 default: break; 05375 } 05376 05377 return ERROR_INTERNET_INVALID_OPTION; 05378 } 05379 05380 static const object_vtbl_t HTTPSESSIONVtbl = { 05381 HTTPSESSION_Destroy, 05382 NULL, 05383 HTTPSESSION_QueryOption, 05384 HTTPSESSION_SetOption, 05385 NULL, 05386 NULL, 05387 NULL, 05388 NULL, 05389 NULL 05390 }; 05391 05392 05393 /*********************************************************************** 05394 * HTTP_Connect (internal) 05395 * 05396 * Create http session handle 05397 * 05398 * RETURNS 05399 * HINTERNET a session handle on success 05400 * NULL on failure 05401 * 05402 */ 05403 DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, 05404 INTERNET_PORT serverPort, LPCWSTR lpszUserName, 05405 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, 05406 DWORD dwInternalFlags, HINTERNET *ret) 05407 { 05408 http_session_t *session = NULL; 05409 05410 TRACE("-->\n"); 05411 05412 if (!lpszServerName || !lpszServerName[0]) 05413 return ERROR_INVALID_PARAMETER; 05414 05415 assert( hIC->hdr.htype == WH_HINIT ); 05416 05417 session = alloc_object(&hIC->hdr, &HTTPSESSIONVtbl, sizeof(http_session_t)); 05418 if (!session) 05419 return ERROR_OUTOFMEMORY; 05420 05421 /* 05422 * According to my tests. The name is not resolved until a request is sent 05423 */ 05424 05425 session->hdr.htype = WH_HHTTPSESSION; 05426 session->hdr.dwFlags = dwFlags; 05427 session->hdr.dwContext = dwContext; 05428 session->hdr.dwInternalFlags |= dwInternalFlags; 05429 05430 WININET_AddRef( &hIC->hdr ); 05431 session->appInfo = hIC; 05432 list_add_head( &hIC->hdr.children, &session->hdr.entry ); 05433 05434 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) { 05435 if(hIC->proxyBypass) 05436 FIXME("Proxy bypass is ignored.\n"); 05437 } 05438 session->serverName = heap_strdupW(lpszServerName); 05439 session->hostName = heap_strdupW(lpszServerName); 05440 if (lpszUserName && lpszUserName[0]) 05441 session->userName = heap_strdupW(lpszUserName); 05442 if (lpszPassword && lpszPassword[0]) 05443 session->password = heap_strdupW(lpszPassword); 05444 session->serverPort = serverPort; 05445 session->hostPort = serverPort; 05446 05447 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ 05448 if (!(session->hdr.dwInternalFlags & INET_OPENURL)) 05449 { 05450 INTERNET_SendCallback(&hIC->hdr, dwContext, 05451 INTERNET_STATUS_HANDLE_CREATED, &session->hdr.hInternet, 05452 sizeof(HINTERNET)); 05453 } 05454 05455 /* 05456 * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on 05457 * windows 05458 */ 05459 05460 TRACE("%p --> %p\n", hIC, session); 05461 05462 *ret = session->hdr.hInternet; 05463 return ERROR_SUCCESS; 05464 } 05465 05466 /*********************************************************************** 05467 * HTTP_clear_response_headers (internal) 05468 * 05469 * clear out any old response headers 05470 */ 05471 static void HTTP_clear_response_headers( http_request_t *request ) 05472 { 05473 DWORD i; 05474 05475 for( i=0; i<request->nCustHeaders; i++) 05476 { 05477 if( !request->custHeaders[i].lpszField ) 05478 continue; 05479 if( !request->custHeaders[i].lpszValue ) 05480 continue; 05481 if ( request->custHeaders[i].wFlags & HDR_ISREQUEST ) 05482 continue; 05483 HTTP_DeleteCustomHeader( request, i ); 05484 i--; 05485 } 05486 } 05487 05488 /*********************************************************************** 05489 * HTTP_GetResponseHeaders (internal) 05490 * 05491 * Read server response 05492 * 05493 * RETURNS 05494 * 05495 * TRUE on success 05496 * FALSE on error 05497 */ 05498 static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) 05499 { 05500 INT cbreaks = 0; 05501 WCHAR buffer[MAX_REPLY_LEN]; 05502 DWORD buflen = MAX_REPLY_LEN; 05503 BOOL bSuccess = FALSE; 05504 INT rc = 0; 05505 char bufferA[MAX_REPLY_LEN]; 05506 LPWSTR status_code = NULL, status_text = NULL; 05507 DWORD cchMaxRawHeaders = 1024; 05508 LPWSTR lpszRawHeaders = NULL; 05509 LPWSTR temp; 05510 DWORD cchRawHeaders = 0; 05511 BOOL codeHundred = FALSE; 05512 05513 TRACE("-->\n"); 05514 05515 if(!request->netconn) 05516 goto lend; 05517 05518 do { 05519 static const WCHAR szHundred[] = {'1','0','0',0}; 05520 /* 05521 * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. 05522 */ 05523 buflen = MAX_REPLY_LEN; 05524 if (!read_line(request, bufferA, &buflen)) 05525 goto lend; 05526 05527 /* clear old response headers (eg. from a redirect response) */ 05528 if (clear) { 05529 HTTP_clear_response_headers( request ); 05530 clear = FALSE; 05531 } 05532 05533 rc += buflen; 05534 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); 05535 /* check is this a status code line? */ 05536 if (!strncmpW(buffer, g_szHttp1_0, 4)) 05537 { 05538 /* split the version from the status code */ 05539 status_code = strchrW( buffer, ' ' ); 05540 if( !status_code ) 05541 goto lend; 05542 *status_code++=0; 05543 05544 /* split the status code from the status text */ 05545 status_text = strchrW( status_code, ' ' ); 05546 if( !status_text ) 05547 goto lend; 05548 *status_text++=0; 05549 05550 TRACE("version [%s] status code [%s] status text [%s]\n", 05551 debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); 05552 05553 codeHundred = (!strcmpW(status_code, szHundred)); 05554 } 05555 else if (!codeHundred) 05556 { 05557 WARN("No status line at head of response (%s)\n", debugstr_w(buffer)); 05558 05559 HeapFree(GetProcessHeap(), 0, request->version); 05560 HeapFree(GetProcessHeap(), 0, request->statusText); 05561 05562 request->version = heap_strdupW(g_szHttp1_0); 05563 request->statusText = heap_strdupW(szOK); 05564 05565 HeapFree(GetProcessHeap(), 0, request->rawHeaders); 05566 request->rawHeaders = heap_strdupW(szDefaultHeader); 05567 05568 bSuccess = TRUE; 05569 goto lend; 05570 } 05571 } while (codeHundred); 05572 05573 /* Add status code */ 05574 HTTP_ProcessHeader(request, szStatus, status_code, 05575 HTTP_ADDHDR_FLAG_REPLACE); 05576 05577 HeapFree(GetProcessHeap(),0,request->version); 05578 HeapFree(GetProcessHeap(),0,request->statusText); 05579 05580 request->version = heap_strdupW(buffer); 05581 request->statusText = heap_strdupW(status_text); 05582 05583 /* Restore the spaces */ 05584 *(status_code-1) = ' '; 05585 *(status_text-1) = ' '; 05586 05587 /* regenerate raw headers */ 05588 lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR)); 05589 if (!lpszRawHeaders) goto lend; 05590 05591 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) 05592 cchMaxRawHeaders *= 2; 05593 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); 05594 if (temp == NULL) goto lend; 05595 lpszRawHeaders = temp; 05596 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); 05597 cchRawHeaders += (buflen-1); 05598 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); 05599 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; 05600 lpszRawHeaders[cchRawHeaders] = '\0'; 05601 05602 /* Parse each response line */ 05603 do 05604 { 05605 buflen = MAX_REPLY_LEN; 05606 if (read_line(request, bufferA, &buflen)) 05607 { 05608 LPWSTR * pFieldAndValue; 05609 05610 TRACE("got line %s, now interpreting\n", debugstr_a(bufferA)); 05611 05612 if (!bufferA[0]) break; 05613 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); 05614 05615 pFieldAndValue = HTTP_InterpretHttpHeader(buffer); 05616 if (pFieldAndValue) 05617 { 05618 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) 05619 cchMaxRawHeaders *= 2; 05620 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); 05621 if (temp == NULL) goto lend; 05622 lpszRawHeaders = temp; 05623 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); 05624 cchRawHeaders += (buflen-1); 05625 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); 05626 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; 05627 lpszRawHeaders[cchRawHeaders] = '\0'; 05628 05629 HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1], 05630 HTTP_ADDREQ_FLAG_ADD ); 05631 05632 HTTP_FreeTokens(pFieldAndValue); 05633 } 05634 } 05635 else 05636 { 05637 cbreaks++; 05638 if (cbreaks >= 2) 05639 break; 05640 } 05641 }while(1); 05642 05643 /* make sure the response header is terminated with an empty line. Some apps really 05644 truly care about that empty line being there for some reason. Just add it to the 05645 header. */ 05646 if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders) 05647 { 05648 cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf); 05649 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); 05650 if (temp == NULL) goto lend; 05651 lpszRawHeaders = temp; 05652 } 05653 05654 memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); 05655 05656 HeapFree(GetProcessHeap(), 0, request->rawHeaders); 05657 request->rawHeaders = lpszRawHeaders; 05658 TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); 05659 bSuccess = TRUE; 05660 05661 lend: 05662 05663 TRACE("<--\n"); 05664 if (bSuccess) 05665 return rc; 05666 else 05667 { 05668 HeapFree(GetProcessHeap(), 0, lpszRawHeaders); 05669 return 0; 05670 } 05671 } 05672 05673 /*********************************************************************** 05674 * HTTP_InterpretHttpHeader (internal) 05675 * 05676 * Parse server response 05677 * 05678 * RETURNS 05679 * 05680 * Pointer to array of field, value, NULL on success. 05681 * NULL on error. 05682 */ 05683 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) 05684 { 05685 LPWSTR * pTokenPair; 05686 LPWSTR pszColon; 05687 INT len; 05688 05689 pTokenPair = heap_alloc_zero(sizeof(*pTokenPair)*3); 05690 05691 pszColon = strchrW(buffer, ':'); 05692 /* must have two tokens */ 05693 if (!pszColon) 05694 { 05695 HTTP_FreeTokens(pTokenPair); 05696 if (buffer[0]) 05697 TRACE("No ':' in line: %s\n", debugstr_w(buffer)); 05698 return NULL; 05699 } 05700 05701 pTokenPair[0] = heap_alloc((pszColon - buffer + 1) * sizeof(WCHAR)); 05702 if (!pTokenPair[0]) 05703 { 05704 HTTP_FreeTokens(pTokenPair); 05705 return NULL; 05706 } 05707 memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR)); 05708 pTokenPair[0][pszColon - buffer] = '\0'; 05709 05710 /* skip colon */ 05711 pszColon++; 05712 len = strlenW(pszColon); 05713 pTokenPair[1] = heap_alloc((len + 1) * sizeof(WCHAR)); 05714 if (!pTokenPair[1]) 05715 { 05716 HTTP_FreeTokens(pTokenPair); 05717 return NULL; 05718 } 05719 memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR)); 05720 05721 strip_spaces(pTokenPair[0]); 05722 strip_spaces(pTokenPair[1]); 05723 05724 TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1])); 05725 return pTokenPair; 05726 } 05727 05728 /*********************************************************************** 05729 * HTTP_ProcessHeader (internal) 05730 * 05731 * Stuff header into header tables according to <dwModifier> 05732 * 05733 */ 05734 05735 #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) 05736 05737 static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier) 05738 { 05739 LPHTTPHEADERW lphttpHdr = NULL; 05740 INT index = -1; 05741 BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ; 05742 DWORD res = ERROR_HTTP_INVALID_HEADER; 05743 05744 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); 05745 05746 /* REPLACE wins out over ADD */ 05747 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) 05748 dwModifier &= ~HTTP_ADDHDR_FLAG_ADD; 05749 05750 if (dwModifier & HTTP_ADDHDR_FLAG_ADD) 05751 index = -1; 05752 else 05753 index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only); 05754 05755 if (index >= 0) 05756 { 05757 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) 05758 return ERROR_HTTP_INVALID_HEADER; 05759 lphttpHdr = &request->custHeaders[index]; 05760 } 05761 else if (value) 05762 { 05763 HTTPHEADERW hdr; 05764 05765 hdr.lpszField = (LPWSTR)field; 05766 hdr.lpszValue = (LPWSTR)value; 05767 hdr.wFlags = hdr.wCount = 0; 05768 05769 if (dwModifier & HTTP_ADDHDR_FLAG_REQ) 05770 hdr.wFlags |= HDR_ISREQUEST; 05771 05772 return HTTP_InsertCustomHeader(request, &hdr); 05773 } 05774 /* no value to delete */ 05775 else return ERROR_SUCCESS; 05776 05777 if (dwModifier & HTTP_ADDHDR_FLAG_REQ) 05778 lphttpHdr->wFlags |= HDR_ISREQUEST; 05779 else 05780 lphttpHdr->wFlags &= ~HDR_ISREQUEST; 05781 05782 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) 05783 { 05784 HTTP_DeleteCustomHeader( request, index ); 05785 05786 if (value) 05787 { 05788 HTTPHEADERW hdr; 05789 05790 hdr.lpszField = (LPWSTR)field; 05791 hdr.lpszValue = (LPWSTR)value; 05792 hdr.wFlags = hdr.wCount = 0; 05793 05794 if (dwModifier & HTTP_ADDHDR_FLAG_REQ) 05795 hdr.wFlags |= HDR_ISREQUEST; 05796 05797 return HTTP_InsertCustomHeader(request, &hdr); 05798 } 05799 05800 return ERROR_SUCCESS; 05801 } 05802 else if (dwModifier & COALESCEFLAGS) 05803 { 05804 LPWSTR lpsztmp; 05805 WCHAR ch = 0; 05806 INT len = 0; 05807 INT origlen = strlenW(lphttpHdr->lpszValue); 05808 INT valuelen = strlenW(value); 05809 05810 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA) 05811 { 05812 ch = ','; 05813 lphttpHdr->wFlags |= HDR_COMMADELIMITED; 05814 } 05815 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) 05816 { 05817 ch = ';'; 05818 lphttpHdr->wFlags |= HDR_COMMADELIMITED; 05819 } 05820 05821 len = origlen + valuelen + ((ch > 0) ? 2 : 0); 05822 05823 lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR)); 05824 if (lpsztmp) 05825 { 05826 lphttpHdr->lpszValue = lpsztmp; 05827 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */ 05828 if (ch > 0) 05829 { 05830 lphttpHdr->lpszValue[origlen] = ch; 05831 origlen++; 05832 lphttpHdr->lpszValue[origlen] = ' '; 05833 origlen++; 05834 } 05835 05836 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); 05837 lphttpHdr->lpszValue[len] = '\0'; 05838 res = ERROR_SUCCESS; 05839 } 05840 else 05841 { 05842 WARN("heap_realloc (%d bytes) failed\n",len+1); 05843 res = ERROR_OUTOFMEMORY; 05844 } 05845 } 05846 TRACE("<-- %d\n", res); 05847 return res; 05848 } 05849 05850 /*********************************************************************** 05851 * HTTP_GetCustomHeaderIndex (internal) 05852 * 05853 * Return index of custom header from header array 05854 * 05855 */ 05856 static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField, 05857 int requested_index, BOOL request_only) 05858 { 05859 DWORD index; 05860 05861 TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only); 05862 05863 for (index = 0; index < request->nCustHeaders; index++) 05864 { 05865 if (strcmpiW(request->custHeaders[index].lpszField, lpszField)) 05866 continue; 05867 05868 if (request_only && !(request->custHeaders[index].wFlags & HDR_ISREQUEST)) 05869 continue; 05870 05871 if (!request_only && (request->custHeaders[index].wFlags & HDR_ISREQUEST)) 05872 continue; 05873 05874 if (requested_index == 0) 05875 break; 05876 requested_index --; 05877 } 05878 05879 if (index >= request->nCustHeaders) 05880 index = -1; 05881 05882 TRACE("Return: %d\n", index); 05883 return index; 05884 } 05885 05886 05887 /*********************************************************************** 05888 * HTTP_InsertCustomHeader (internal) 05889 * 05890 * Insert header into array 05891 * 05892 */ 05893 static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHdr) 05894 { 05895 INT count; 05896 LPHTTPHEADERW lph = NULL; 05897 05898 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue)); 05899 count = request->nCustHeaders + 1; 05900 if (count > 1) 05901 lph = heap_realloc_zero(request->custHeaders, sizeof(HTTPHEADERW) * count); 05902 else 05903 lph = heap_alloc_zero(sizeof(HTTPHEADERW) * count); 05904 05905 if (!lph) 05906 return ERROR_OUTOFMEMORY; 05907 05908 request->custHeaders = lph; 05909 request->custHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField); 05910 request->custHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue); 05911 request->custHeaders[count-1].wFlags = lpHdr->wFlags; 05912 request->custHeaders[count-1].wCount= lpHdr->wCount; 05913 request->nCustHeaders++; 05914 05915 return ERROR_SUCCESS; 05916 } 05917 05918 05919 /*********************************************************************** 05920 * HTTP_DeleteCustomHeader (internal) 05921 * 05922 * Delete header from array 05923 * If this function is called, the indexs may change. 05924 */ 05925 static BOOL HTTP_DeleteCustomHeader(http_request_t *request, DWORD index) 05926 { 05927 if( request->nCustHeaders <= 0 ) 05928 return FALSE; 05929 if( index >= request->nCustHeaders ) 05930 return FALSE; 05931 request->nCustHeaders--; 05932 05933 HeapFree(GetProcessHeap(), 0, request->custHeaders[index].lpszField); 05934 HeapFree(GetProcessHeap(), 0, request->custHeaders[index].lpszValue); 05935 05936 memmove( &request->custHeaders[index], &request->custHeaders[index+1], 05937 (request->nCustHeaders - index)* sizeof(HTTPHEADERW) ); 05938 memset( &request->custHeaders[request->nCustHeaders], 0, sizeof(HTTPHEADERW) ); 05939 05940 return TRUE; 05941 } 05942 05943 05944 /*********************************************************************** 05945 * HTTP_VerifyValidHeader (internal) 05946 * 05947 * Verify the given header is not invalid for the given http request 05948 * 05949 */ 05950 static BOOL HTTP_VerifyValidHeader(http_request_t *request, LPCWSTR field) 05951 { 05952 /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */ 05953 if (!strcmpW(request->version, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding)) 05954 return ERROR_HTTP_INVALID_HEADER; 05955 05956 return ERROR_SUCCESS; 05957 } 05958 05959 /*********************************************************************** 05960 * IsHostInProxyBypassList (@) 05961 * 05962 * Undocumented 05963 * 05964 */ 05965 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length) 05966 { 05967 FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length); 05968 return FALSE; 05969 } 05970 05971 /*********************************************************************** 05972 * InternetShowSecurityInfoByURLA (@) 05973 */ 05974 BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window) 05975 { 05976 FIXME("stub: %s %p\n", url, window); 05977 return FALSE; 05978 } 05979 05980 /*********************************************************************** 05981 * InternetShowSecurityInfoByURLW (@) 05982 */ 05983 BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window) 05984 { 05985 FIXME("stub: %s %p\n", debugstr_w(url), window); 05986 return FALSE; 05987 } Generated on Mon May 28 2012 04:26:17 for ReactOS by
1.7.6.1
|