blob: dab96b903035835a866ad97956413316d532e967 [file] [log] [blame]
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00001/*
Ulrich Czekallac2757242000-06-11 20:04:44 +00002 * Wininet - Http Implementation
3 *
4 * Copyright 1999 Corel Corporation
Aric Stewartff9b9d42002-06-21 23:59:49 +00005 * Copyright 2002 CodeWeavers Inc.
David Hammerton852c7ae2003-06-20 23:26:56 +00006 * Copyright 2002 TransGaming Technologies Inc.
Francois Gougetad5ff7c2004-02-09 22:07:42 +00007 * Copyright 2004 Mike McCormack for CodeWeavers
Aric Stewartbe918f42005-11-21 15:17:55 +00008 * Copyright 2005 Aric Stewart for CodeWeavers
Rob Shearman272954b2007-01-04 18:23:17 +00009 * Copyright 2006 Robert Shearman for CodeWeavers
Jacek Cabanccd11eb2011-04-02 15:20:33 +020010 * Copyright 2011 Jacek Caban for CodeWeavers
Ulrich Czekallac2757242000-06-11 20:04:44 +000011 *
12 * Ulrich Czekalla
David Hammerton852c7ae2003-06-20 23:26:56 +000013 * David Hammerton
Ulrich Czekallac2757242000-06-11 20:04:44 +000014 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000015 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020027 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Ulrich Czekallac2757242000-06-11 20:04:44 +000028 */
29
Patrik Stridvall4710be22000-06-23 15:47:14 +000030#include "config.h"
Alexandre Julliard754e7aa2004-09-03 18:30:28 +000031#include "wine/port.h"
Patrik Stridvall4710be22000-06-23 15:47:14 +000032
Alexandre Julliard82280612008-12-09 11:33:25 +010033#if defined(__MINGW32__) || defined (_MSC_VER)
34#include <ws2tcpip.h>
35#endif
36
Ulrich Czekallac2757242000-06-11 20:04:44 +000037#include <sys/types.h>
Patrik Stridvall4710be22000-06-23 15:47:14 +000038#ifdef HAVE_SYS_SOCKET_H
39# include <sys/socket.h>
40#endif
Jacek Cabanad023172006-01-05 14:37:06 +010041#ifdef HAVE_ARPA_INET_H
42# include <arpa/inet.h>
43#endif
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000044#include <stdarg.h>
Ulrich Czekallac2757242000-06-11 20:04:44 +000045#include <stdio.h>
46#include <stdlib.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000047#ifdef HAVE_UNISTD_H
48# include <unistd.h>
49#endif
Chris Morganb9807b42001-02-15 21:24:07 +000050#include <time.h>
Mike McCormack3a1391b2004-07-19 21:49:39 +000051#include <assert.h>
Jacek Caban11ca05f2009-05-29 23:35:13 +020052#ifdef HAVE_ZLIB
53# include <zlib.h>
54#endif
Ulrich Czekallac2757242000-06-11 20:04:44 +000055
Guy Albertelliaafec982001-11-06 22:31:19 +000056#include "windef.h"
57#include "winbase.h"
58#include "wininet.h"
Guy Albertelliaafec982001-11-06 22:31:19 +000059#include "winerror.h"
Juan Lang2d323432011-03-03 10:54:07 -080060#include "winternl.h"
Jon Griffiths603f20f2001-12-11 00:30:17 +000061#define NO_SHLWAPI_STREAM
Robert Shearmandc5f1cb2005-11-30 12:01:50 +010062#define NO_SHLWAPI_REG
63#define NO_SHLWAPI_STRFCNS
64#define NO_SHLWAPI_GDI
Guy Albertelliaafec982001-11-06 22:31:19 +000065#include "shlwapi.h"
Rob Shearman4b507682007-05-21 14:26:26 +010066#include "sspi.h"
Jacek Caban7e63f952008-03-12 02:24:23 +010067#include "wincrypt.h"
Guy Albertelliaafec982001-11-06 22:31:19 +000068
Ulrich Czekallac2757242000-06-11 20:04:44 +000069#include "internet.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000070#include "wine/debug.h"
Hans Leidekkerbd805292008-10-24 11:08:12 +020071#include "wine/exception.h"
Alberto Massarid476a5a2002-11-12 02:13:04 +000072#include "wine/unicode.h"
Ulrich Czekallac2757242000-06-11 20:04:44 +000073
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000074WINE_DEFAULT_DEBUG_CHANNEL(wininet);
Ulrich Czekallac2757242000-06-11 20:04:44 +000075
Hans Leidekker3a577112008-03-24 21:31:53 +010076static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0};
Hans Leidekkerd0033db2008-02-17 20:41:42 +010077static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
Hans Leidekker2ed570e2010-02-22 12:28:03 +010078static const WCHAR szOK[] = {'O','K',0};
79static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0};
Jacek Caban83170892009-05-29 23:34:14 +020080static const WCHAR hostW[] = { 'H','o','s','t',0 };
Rob Shearman4b507682007-05-21 14:26:26 +010081static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
Aric Stewart1e946d32005-12-13 17:07:41 +010082static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
83static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
Rob Shearman272954b2007-01-04 18:23:17 +000084static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
Jacek Cabanf9791342008-02-13 13:34:05 +010085static const WCHAR szGET[] = { 'G','E','T', 0 };
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +020086static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
Lei Zhangf7e56d12008-08-27 17:03:13 -070087static const WCHAR szCrLf[] = {'\r','\n', 0};
Mike McCormacka4e902c2004-03-30 04:36:09 +000088
Jacek Caban83170892009-05-29 23:34:14 +020089static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
90static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
91static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
92static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
93static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
94static const WCHAR szAge[] = { 'A','g','e',0 };
95static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
96static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
97static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
98static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
99static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
100static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
101static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
102static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
103static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
104static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
105static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
106static 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 };
107static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
108static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
109static const WCHAR szDate[] = { 'D','a','t','e',0 };
110static const WCHAR szFrom[] = { 'F','r','o','m',0 };
111static const WCHAR szETag[] = { 'E','T','a','g',0 };
112static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
113static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
114static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
115static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
116static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
117static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
118static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
119static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
120static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
121static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
122static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
123static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
124static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
125static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
126static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
127static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
128static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
129static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
130static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
131static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
132static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
133static 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 };
134static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
135static const WCHAR szURI[] = { 'U','R','I',0 };
136static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
137static const WCHAR szVary[] = { 'V','a','r','y',0 };
138static const WCHAR szVia[] = { 'V','i','a',0 };
139static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
140static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
141
Ulrich Czekallac2757242000-06-11 20:04:44 +0000142#define MAXHOSTNAME 100
143#define MAX_FIELD_VALUE_LEN 256
144#define MAX_FIELD_LEN 256
145
Jacek Caban83170892009-05-29 23:34:14 +0200146#define HTTP_REFERER szReferer
147#define HTTP_ACCEPT szAccept
148#define HTTP_USERAGENT szUser_Agent
Ulrich Czekallac2757242000-06-11 20:04:44 +0000149
150#define HTTP_ADDHDR_FLAG_ADD 0x20000000
151#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
152#define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
153#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
154#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
155#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
156#define HTTP_ADDHDR_FLAG_REQ 0x02000000
157
Jacek Caban8a1df202011-05-10 09:26:43 +0000158#define COLLECT_TIME 60000
159
Rob Shearman4b507682007-05-21 14:26:26 +0100160#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
161
162struct HttpAuthInfo
163{
164 LPWSTR scheme;
165 CredHandle cred;
166 CtxtHandle ctx;
167 TimeStamp exp;
168 ULONG attr;
Rob Shearman0be05ab2008-03-10 16:41:44 +0000169 ULONG max_token;
Rob Shearman4b507682007-05-21 14:26:26 +0100170 void *auth_data;
171 unsigned int auth_data_len;
172 BOOL finished; /* finished authenticating */
173};
Ulrich Czekallac2757242000-06-11 20:04:44 +0000174
Jacek Caban11ca05f2009-05-29 23:35:13 +0200175
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200176typedef struct _basicAuthorizationData
Aric Stewartfc508932009-10-12 14:24:18 -0500177{
178 struct list entry;
179
Juan Lang2c6ad542011-03-01 10:30:46 -0800180 LPWSTR host;
181 LPWSTR realm;
182 LPSTR authorization;
183 UINT authorizationLen;
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200184} basicAuthorizationData;
185
186typedef struct _authorizationData
187{
188 struct list entry;
189
190 LPWSTR host;
191 LPWSTR scheme;
192 LPWSTR domain;
193 UINT domain_len;
194 LPWSTR user;
195 UINT user_len;
196 LPWSTR password;
197 UINT password_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500198} authorizationData;
199
200static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200201static struct list authorizationCache = LIST_INIT(authorizationCache);
Aric Stewartfc508932009-10-12 14:24:18 -0500202
203static CRITICAL_SECTION authcache_cs;
204static CRITICAL_SECTION_DEBUG critsect_debug =
205{
206 0, 0, &authcache_cs,
207 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
208 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
209};
210static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
211
Jacek Caban34abacd2009-07-13 01:41:50 +0200212static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
Jacek Cabane9749652009-11-30 20:01:00 +0100213static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
Jacek Caban02708c62005-10-26 10:07:58 +0000214static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
Jacek Cabane9749652009-11-30 20:01:00 +0100215static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
Jacek Caban34abacd2009-07-13 01:41:50 +0200216static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
217static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
Aric Stewartbe918f42005-11-21 15:17:55 +0000218static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
Jacek Caban9823c232009-12-14 02:27:29 +0100219static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
Jacek Caban34abacd2009-07-13 01:41:50 +0200220static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
Rob Shearman4b507682007-05-21 14:26:26 +0100221static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
Jacek Caban34abacd2009-07-13 01:41:50 +0200222static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
Jacek Caban8a1df202011-05-10 09:26:43 +0000223
224static CRITICAL_SECTION connection_pool_cs;
225static CRITICAL_SECTION_DEBUG connection_pool_debug =
226{
227 0, 0, &connection_pool_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
230};
231static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
232
233static struct list connection_pool = LIST_INIT(connection_pool);
234static BOOL collector_running;
235
236void server_addref(server_t *server)
237{
238 InterlockedIncrement(&server->ref);
239}
240
241void server_release(server_t *server)
242{
243 if(InterlockedDecrement(&server->ref))
244 return;
245
246 if(!server->ref)
247 server->keep_until = GetTickCount64() + COLLECT_TIME;
248}
249
250static server_t *get_server(const WCHAR *name, INTERNET_PORT port)
251{
252 server_t *iter, *server = NULL;
253
254 EnterCriticalSection(&connection_pool_cs);
255
256 LIST_FOR_EACH_ENTRY(iter, &connection_pool, server_t, entry) {
257 if(iter->port == port && !strcmpW(iter->name, name)) {
258 server = iter;
259 server_addref(server);
260 break;
261 }
262 }
263
264 if(!server) {
265 server = heap_alloc(sizeof(*server));
266 if(server) {
267 server->addr_len = 0;
268 server->ref = 1;
269 server->port = port;
270 list_init(&server->conn_pool);
271 server->name = heap_strdupW(name);
272 if(server->name) {
273 list_add_head(&connection_pool, &server->entry);
274 }else {
275 heap_free(server);
276 server = NULL;
277 }
278 }
279 }
280
281 LeaveCriticalSection(&connection_pool_cs);
282
283 return server;
284}
285
286BOOL collect_connections(BOOL collect_all)
287{
288 netconn_t *netconn, *netconn_safe;
289 server_t *server, *server_safe;
290 BOOL remaining = FALSE;
291 DWORD64 now;
292
293 now = GetTickCount64();
294
295 LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) {
296 LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
297 if(collect_all || netconn->keep_until < now) {
298 TRACE("freeing %p\n", netconn);
299 list_remove(&netconn->pool_entry);
300 free_netconn(netconn);
301 }else {
302 remaining = TRUE;
303 }
304 }
305
306 if(!server->ref) {
307 if(collect_all || server->keep_until < now) {
308 list_remove(&server->entry);
309
310 heap_free(server->name);
311 heap_free(server);
312 }else {
313 remaining = TRUE;
314 }
315 }
316 }
317
318 return remaining;
319}
320
321static DWORD WINAPI collect_connections_proc(void *arg)
322{
323 BOOL remaining_conns;
324
325 do {
326 /* FIXME: Use more sophisticated method */
327 Sleep(5000);
328
329 EnterCriticalSection(&connection_pool_cs);
330
331 remaining_conns = collect_connections(FALSE);
332 if(!remaining_conns)
333 collector_running = FALSE;
334
335 LeaveCriticalSection(&connection_pool_cs);
336 }while(remaining_conns);
337
338 FreeLibraryAndExitThread(WININET_hModule, 0);
339}
Aric Stewart1e946d32005-12-13 17:07:41 +0100340
Jacek Caban34abacd2009-07-13 01:41:50 +0200341static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
Aric Stewart1e946d32005-12-13 17:07:41 +0100342{
343 int HeaderIndex = 0;
344 HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
345 if (HeaderIndex == -1)
346 return NULL;
347 else
Juan Lang20980062011-03-01 11:18:22 -0800348 return &req->custHeaders[HeaderIndex];
Aric Stewart1e946d32005-12-13 17:07:41 +0100349}
Ulrich Czekallac2757242000-06-11 20:04:44 +0000350
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200351typedef enum {
352 READMODE_SYNC,
353 READMODE_ASYNC,
354 READMODE_NOBLOCK
355} read_mode_t;
356
357struct data_stream_vtbl_t {
358 DWORD (*get_avail_data)(data_stream_t*,http_request_t*);
359 BOOL (*end_of_data)(data_stream_t*,http_request_t*);
360 DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,read_mode_t);
Jacek Caban8a1df202011-05-10 09:26:43 +0000361 BOOL (*drain_content)(data_stream_t*,http_request_t*);
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200362 void (*destroy)(data_stream_t*);
363};
364
365typedef struct {
366 data_stream_t data_stream;
367
368 BYTE buf[READ_BUFFER_SIZE];
369 DWORD buf_size;
370 DWORD buf_pos;
371 DWORD chunk_size;
372} chunked_stream_t;
373
Michael Stefaniuc9bf247d2011-04-05 16:18:38 +0200374static inline void destroy_data_stream(data_stream_t *stream)
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200375{
376 stream->vtbl->destroy(stream);
377}
378
379static void reset_data_stream(http_request_t *req)
380{
381 destroy_data_stream(req->data_stream);
382 req->data_stream = &req->netconn_stream.data_stream;
383 req->read_pos = req->read_size = req->netconn_stream.content_read = 0;
384 req->read_chunked = req->read_gzip = FALSE;
385}
386
Jacek Caban11ca05f2009-05-29 23:35:13 +0200387#ifdef HAVE_ZLIB
388
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200389typedef struct {
390 data_stream_t stream;
391 data_stream_t *parent_stream;
392 z_stream zstream;
393 BYTE buf[READ_BUFFER_SIZE];
394 DWORD buf_size;
395 DWORD buf_pos;
396 BOOL end_of_data;
397} gzip_stream_t;
398
399static DWORD gzip_get_avail_data(data_stream_t *stream, http_request_t *req)
400{
401 /* Allow reading only from read buffer */
402 return 0;
403}
404
405static BOOL gzip_end_of_data(data_stream_t *stream, http_request_t *req)
406{
407 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
408 return gzip_stream->end_of_data;
409}
410
411static DWORD gzip_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
412 DWORD *read, read_mode_t read_mode)
413{
414 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
415 z_stream *zstream = &gzip_stream->zstream;
416 DWORD current_read, ret_read = 0;
417 BOOL end;
418 int zres;
419 DWORD res = ERROR_SUCCESS;
420
421 while(size && !gzip_stream->end_of_data) {
422 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req);
423
424 if(gzip_stream->buf_size <= 64 && !end) {
425 if(gzip_stream->buf_pos) {
426 if(gzip_stream->buf_size)
427 memmove(gzip_stream->buf, gzip_stream->buf+gzip_stream->buf_pos, gzip_stream->buf_size);
428 gzip_stream->buf_pos = 0;
429 }
430 res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size,
431 sizeof(gzip_stream->buf)-gzip_stream->buf_size, &current_read, read_mode);
432 gzip_stream->buf_size += current_read;
433 if(res != ERROR_SUCCESS)
434 break;
435 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req);
436 if(!current_read && !end) {
437 if(read_mode != READMODE_NOBLOCK) {
438 WARN("unexpected end of data\n");
439 gzip_stream->end_of_data = TRUE;
440 }
441 break;
442 }
443 if(gzip_stream->buf_size <= 64 && !end)
444 continue;
445 }
446
447 zstream->next_in = gzip_stream->buf+gzip_stream->buf_pos;
448 zstream->avail_in = gzip_stream->buf_size-(end ? 0 : 64);
449 zstream->next_out = buf+ret_read;
450 zstream->avail_out = size;
451 zres = inflate(&gzip_stream->zstream, 0);
452 current_read = size - zstream->avail_out;
453 size -= current_read;
454 ret_read += current_read;
455 gzip_stream->buf_size -= zstream->next_in - (gzip_stream->buf+gzip_stream->buf_pos);
456 gzip_stream->buf_pos = zstream->next_in-gzip_stream->buf;
457 if(zres == Z_STREAM_END) {
458 TRACE("end of data\n");
459 gzip_stream->end_of_data = TRUE;
460 inflateEnd(zstream);
461 }else if(zres != Z_OK) {
462 WARN("inflate failed %d: %s\n", zres, debugstr_a(zstream->msg));
463 if(!ret_read)
464 res = ERROR_INTERNET_DECODING_FAILED;
465 break;
466 }
467
468 if(ret_read && read_mode == READMODE_ASYNC)
469 read_mode = READMODE_NOBLOCK;
470 }
471
472 TRACE("read %u bytes\n", ret_read);
473 *read = ret_read;
474 return res;
475}
476
Jacek Caban8a1df202011-05-10 09:26:43 +0000477static BOOL gzip_drain_content(data_stream_t *stream, http_request_t *req)
478{
479 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
480 return gzip_stream->parent_stream->vtbl->drain_content(gzip_stream->parent_stream, req);
481}
482
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200483static void gzip_destroy(data_stream_t *stream)
484{
485 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
486
487 destroy_data_stream(gzip_stream->parent_stream);
488
489 if(!gzip_stream->end_of_data)
490 inflateEnd(&gzip_stream->zstream);
491 heap_free(gzip_stream);
492}
493
494static const data_stream_vtbl_t gzip_stream_vtbl = {
495 gzip_get_avail_data,
496 gzip_end_of_data,
497 gzip_read,
Jacek Caban8a1df202011-05-10 09:26:43 +0000498 gzip_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200499 gzip_destroy
500};
501
Jacek Caban11ca05f2009-05-29 23:35:13 +0200502static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
503{
Jacek Caban354a74e2011-04-21 13:39:03 +0200504 return heap_alloc(items*size);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200505}
506
507static void wininet_zfree(voidpf opaque, voidpf address)
508{
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200509 heap_free(address);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200510}
511
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200512static DWORD init_gzip_stream(http_request_t *req)
Jacek Caban11ca05f2009-05-29 23:35:13 +0200513{
514 gzip_stream_t *gzip_stream;
Jacek Caban3858e352009-07-31 21:07:42 +0200515 int index, zres;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200516
Jacek Cabanec966042011-03-15 00:08:34 +0100517 gzip_stream = heap_alloc_zero(sizeof(gzip_stream_t));
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200518 if(!gzip_stream)
519 return ERROR_OUTOFMEMORY;
520
521 gzip_stream->stream.vtbl = &gzip_stream_vtbl;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200522 gzip_stream->zstream.zalloc = wininet_zalloc;
523 gzip_stream->zstream.zfree = wininet_zfree;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200524
525 zres = inflateInit2(&gzip_stream->zstream, 0x1f);
526 if(zres != Z_OK) {
527 ERR("inflateInit failed: %d\n", zres);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200528 heap_free(gzip_stream);
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200529 return ERROR_OUTOFMEMORY;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200530 }
531
Jacek Caban3858e352009-07-31 21:07:42 +0200532 index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
533 if(index != -1)
534 HTTP_DeleteCustomHeader(req, index);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200535
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200536 if(req->read_size) {
537 memcpy(gzip_stream->buf, req->read_buf+req->read_pos, req->read_size);
538 gzip_stream->buf_size = req->read_size;
539 req->read_pos = req->read_size = 0;
540 }
541
542 req->read_gzip = TRUE;
543 gzip_stream->parent_stream = req->data_stream;
544 req->data_stream = &gzip_stream->stream;
545 return ERROR_SUCCESS;
Jacek Cabanec966042011-03-15 00:08:34 +0100546}
547
Jacek Caban11ca05f2009-05-29 23:35:13 +0200548#else
549
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200550static DWORD init_gzip_stream(http_request_t *req)
Jacek Caban11ca05f2009-05-29 23:35:13 +0200551{
552 ERR("gzip stream not supported, missing zlib.\n");
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200553 return ERROR_SUCCESS;
Jacek Cabanec966042011-03-15 00:08:34 +0100554}
555
Jacek Caban11ca05f2009-05-29 23:35:13 +0200556#endif
557
Ulrich Czekallac2757242000-06-11 20:04:44 +0000558/***********************************************************************
Robert Shearmandee87512004-07-19 20:09:20 +0000559 * HTTP_Tokenize (internal)
560 *
561 * Tokenize a string, allocating memory for the tokens.
562 */
563static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
564{
565 LPWSTR * token_array;
566 int tokens = 0;
567 int i;
568 LPCWSTR next_token;
569
Rob Shearman0715d9c2008-10-07 15:39:50 +0100570 if (string)
571 {
572 /* empty string has no tokens */
573 if (*string)
Robert Shearmandee87512004-07-19 20:09:20 +0000574 tokens++;
Rob Shearman0715d9c2008-10-07 15:39:50 +0100575 /* count tokens */
576 for (i = 0; string[i]; i++)
577 {
578 if (!strncmpW(string+i, token_string, strlenW(token_string)))
579 {
580 DWORD j;
581 tokens++;
582 /* we want to skip over separators, but not the null terminator */
583 for (j = 0; j < strlenW(token_string) - 1; j++)
584 if (!string[i+j])
585 break;
586 i += j;
587 }
Robert Shearmandee87512004-07-19 20:09:20 +0000588 }
Rob Shearman0715d9c2008-10-07 15:39:50 +0100589 }
Robert Shearmandee87512004-07-19 20:09:20 +0000590
591 /* add 1 for terminating NULL */
Jacek Caban354a74e2011-04-21 13:39:03 +0200592 token_array = heap_alloc((tokens+1) * sizeof(*token_array));
Robert Shearmandee87512004-07-19 20:09:20 +0000593 token_array[tokens] = NULL;
594 if (!tokens)
595 return token_array;
596 for (i = 0; i < tokens; i++)
597 {
598 int len;
599 next_token = strstrW(string, token_string);
600 if (!next_token) next_token = string+strlenW(string);
601 len = next_token - string;
Jacek Caban354a74e2011-04-21 13:39:03 +0200602 token_array[i] = heap_alloc((len+1)*sizeof(WCHAR));
Robert Shearmandee87512004-07-19 20:09:20 +0000603 memcpy(token_array[i], string, len*sizeof(WCHAR));
604 token_array[i][len] = '\0';
605 string = next_token+strlenW(token_string);
606 }
607 return token_array;
608}
609
610/***********************************************************************
611 * HTTP_FreeTokens (internal)
612 *
613 * Frees memory returned from HTTP_Tokenize.
614 */
615static void HTTP_FreeTokens(LPWSTR * token_array)
616{
617 int i;
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200618 for (i = 0; token_array[i]; i++) heap_free(token_array[i]);
619 heap_free(token_array);
Robert Shearmandee87512004-07-19 20:09:20 +0000620}
621
Juan Langb49b2432011-03-01 10:59:39 -0800622static void HTTP_FixURL(http_request_t *request)
Aric Stewartbe918f42005-11-21 15:17:55 +0000623{
624 static const WCHAR szSlash[] = { '/',0 };
625 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
626
627 /* If we don't have a path we set it to root */
Juan Lang20980062011-03-01 11:18:22 -0800628 if (NULL == request->path)
629 request->path = heap_strdupW(szSlash);
Aric Stewartbe918f42005-11-21 15:17:55 +0000630 else /* remove \r and \n*/
631 {
Juan Lang20980062011-03-01 11:18:22 -0800632 int nLen = strlenW(request->path);
633 while ((nLen >0 ) && ((request->path[nLen-1] == '\r')||(request->path[nLen-1] == '\n')))
Aric Stewartbe918f42005-11-21 15:17:55 +0000634 {
635 nLen--;
Juan Lang20980062011-03-01 11:18:22 -0800636 request->path[nLen]='\0';
Aric Stewartbe918f42005-11-21 15:17:55 +0000637 }
638 /* Replace '\' with '/' */
639 while (nLen>0) {
640 nLen--;
Juan Lang20980062011-03-01 11:18:22 -0800641 if (request->path[nLen] == '\\') request->path[nLen]='/';
Aric Stewartbe918f42005-11-21 15:17:55 +0000642 }
643 }
644
645 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
Juan Lang20980062011-03-01 11:18:22 -0800646 request->path, strlenW(request->path), szHttp, strlenW(szHttp) )
647 && request->path[0] != '/') /* not an absolute path ?? --> fix it !! */
Aric Stewartbe918f42005-11-21 15:17:55 +0000648 {
Jacek Caban354a74e2011-04-21 13:39:03 +0200649 WCHAR *fixurl = heap_alloc((strlenW(request->path) + 2)*sizeof(WCHAR));
Aric Stewartbe918f42005-11-21 15:17:55 +0000650 *fixurl = '/';
Juan Lang20980062011-03-01 11:18:22 -0800651 strcpyW(fixurl + 1, request->path);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200652 heap_free( request->path );
Juan Lang20980062011-03-01 11:18:22 -0800653 request->path = fixurl;
Aric Stewartbe918f42005-11-21 15:17:55 +0000654 }
655}
656
Juan Langb49b2432011-03-01 10:59:39 -0800657static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
Aric Stewartbe918f42005-11-21 15:17:55 +0000658{
659 LPWSTR requestString;
660 DWORD len, n;
661 LPCWSTR *req;
Gerald Pfeifer3f1a20b2008-01-12 20:14:04 +0100662 UINT i;
Aric Stewartbe918f42005-11-21 15:17:55 +0000663 LPWSTR p;
664
665 static const WCHAR szSpace[] = { ' ',0 };
Aric Stewartbe918f42005-11-21 15:17:55 +0000666 static const WCHAR szColon[] = { ':',' ',0 };
667 static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
668
669 /* allocate space for an array of all the string pointers to be added */
Juan Langb49b2432011-03-01 10:59:39 -0800670 len = (request->nCustHeaders)*4 + 10;
Jacek Caban354a74e2011-04-21 13:39:03 +0200671 req = heap_alloc(len*sizeof(LPCWSTR));
Aric Stewartbe918f42005-11-21 15:17:55 +0000672
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100673 /* add the verb, path and HTTP version string */
Aric Stewartbe918f42005-11-21 15:17:55 +0000674 n = 0;
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100675 req[n++] = verb;
Aric Stewartbe918f42005-11-21 15:17:55 +0000676 req[n++] = szSpace;
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100677 req[n++] = path;
Hans Leidekkerd0033db2008-02-17 20:41:42 +0100678 req[n++] = szSpace;
679 req[n++] = version;
Aric Stewartbe918f42005-11-21 15:17:55 +0000680
Austin English0e4adae2008-01-04 13:37:14 -0600681 /* Append custom request headers */
Juan Langb49b2432011-03-01 10:59:39 -0800682 for (i = 0; i < request->nCustHeaders; i++)
Aric Stewartbe918f42005-11-21 15:17:55 +0000683 {
Juan Lang20980062011-03-01 11:18:22 -0800684 if (request->custHeaders[i].wFlags & HDR_ISREQUEST)
Aric Stewartbe918f42005-11-21 15:17:55 +0000685 {
Lei Zhangf7e56d12008-08-27 17:03:13 -0700686 req[n++] = szCrLf;
Juan Lang20980062011-03-01 11:18:22 -0800687 req[n++] = request->custHeaders[i].lpszField;
Aric Stewartbe918f42005-11-21 15:17:55 +0000688 req[n++] = szColon;
Juan Lang20980062011-03-01 11:18:22 -0800689 req[n++] = request->custHeaders[i].lpszValue;
Aric Stewartbe918f42005-11-21 15:17:55 +0000690
691 TRACE("Adding custom header %s (%s)\n",
Juan Lang20980062011-03-01 11:18:22 -0800692 debugstr_w(request->custHeaders[i].lpszField),
693 debugstr_w(request->custHeaders[i].lpszValue));
Aric Stewartbe918f42005-11-21 15:17:55 +0000694 }
695 }
696
697 if( n >= len )
698 ERR("oops. buffer overrun\n");
699
700 req[n] = NULL;
701 requestString = HTTP_build_req( req, 4 );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200702 heap_free( req );
Aric Stewartbe918f42005-11-21 15:17:55 +0000703
704 /*
705 * Set (header) termination string for request
706 * Make sure there's exactly two new lines at the end of the request
707 */
708 p = &requestString[strlenW(requestString)-1];
709 while ( (*p == '\n') || (*p == '\r') )
710 p--;
711 strcpyW( p+1, sztwocrlf );
712
713 return requestString;
714}
715
Juan Langb49b2432011-03-01 10:59:39 -0800716static void HTTP_ProcessCookies( http_request_t *request )
Aric Stewartbe918f42005-11-21 15:17:55 +0000717{
Aric Stewart1e946d32005-12-13 17:07:41 +0100718 int HeaderIndex;
Jan-Peter Nilssonb2618362008-09-24 22:42:36 +0200719 int numCookies = 0;
Aric Stewart1e946d32005-12-13 17:07:41 +0100720 LPHTTPHEADERW setCookieHeader;
721
Jacek Caban2e2ed522011-05-19 16:11:45 +0200722 if(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES)
723 return;
724
725 while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, szSet_Cookie, numCookies++, FALSE)) != -1)
Aric Stewartbe918f42005-11-21 15:17:55 +0000726 {
Jacek Caban2e2ed522011-05-19 16:11:45 +0200727 HTTPHEADERW *host;
728 const WCHAR *data;
729 WCHAR *name;
730
Juan Lang20980062011-03-01 11:18:22 -0800731 setCookieHeader = &request->custHeaders[HeaderIndex];
Aric Stewartbe918f42005-11-21 15:17:55 +0000732
Jacek Caban2e2ed522011-05-19 16:11:45 +0200733 if (!setCookieHeader->lpszValue)
734 continue;
Aric Stewart1e946d32005-12-13 17:07:41 +0100735
Jacek Caban2e2ed522011-05-19 16:11:45 +0200736 host = HTTP_GetHeader(request, hostW);
737 if(!host)
738 continue;
Jan-Peter Nilssonb2618362008-09-24 22:42:36 +0200739
Jacek Caban2e2ed522011-05-19 16:11:45 +0200740 data = strchrW(setCookieHeader->lpszValue, '=');
741 if(!data)
742 continue;
743
744 name = heap_strndupW(setCookieHeader->lpszValue, data-setCookieHeader->lpszValue);
745 if(!name)
746 continue;
747
748 data++;
749 set_cookie(host->lpszValue, request->path, name, data);
750 heap_free(name);
Aric Stewartbe918f42005-11-21 15:17:55 +0000751 }
752}
753
Aric Stewartfc508932009-10-12 14:24:18 -0500754static void strip_spaces(LPWSTR start)
755{
756 LPWSTR str = start;
757 LPWSTR end;
758
759 while (*str == ' ' && *str != '\0')
760 str++;
761
762 if (str != start)
763 memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
764
765 end = start + strlenW(start) - 1;
766 while (end >= start && *end == ' ')
767 {
768 *end = '\0';
769 end--;
770 }
771}
772
773static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
Rob Shearman4b507682007-05-21 14:26:26 +0100774{
775 static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
Aric Stewartfc508932009-10-12 14:24:18 -0500776 static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
777 BOOL is_basic;
778 is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
Rob Shearman6021fa02008-05-15 21:05:21 +0100779 ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
Aric Stewartfc508932009-10-12 14:24:18 -0500780 if (is_basic && pszRealm)
781 {
782 LPCWSTR token;
783 LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)];
784 LPCWSTR realm;
785 ptr++;
786 *pszRealm=NULL;
787 token = strchrW(ptr,'=');
788 if (!token)
789 return TRUE;
790 realm = ptr;
791 while (*realm == ' ' && *realm != '\0')
792 realm++;
793 if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) &&
794 (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '='))
795 {
796 token++;
797 while (*token == ' ' && *token != '\0')
798 token++;
799 if (*token == '\0')
800 return TRUE;
801 *pszRealm = heap_strdupW(token);
802 strip_spaces(*pszRealm);
803 }
804 }
805
806 return is_basic;
Rob Shearman4b507682007-05-21 14:26:26 +0100807}
808
Hans Leidekker50fef742009-09-02 11:44:43 +0200809static void destroy_authinfo( struct HttpAuthInfo *authinfo )
810{
811 if (!authinfo) return;
812
813 if (SecIsValidHandle(&authinfo->ctx))
814 DeleteSecurityContext(&authinfo->ctx);
815 if (SecIsValidHandle(&authinfo->cred))
816 FreeCredentialsHandle(&authinfo->cred);
817
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200818 heap_free(authinfo->auth_data);
819 heap_free(authinfo->scheme);
820 heap_free(authinfo);
Hans Leidekker50fef742009-09-02 11:44:43 +0200821}
822
Aric Stewartfc508932009-10-12 14:24:18 -0500823static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
824{
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200825 basicAuthorizationData *ad;
Aric Stewartfc508932009-10-12 14:24:18 -0500826 UINT rc = 0;
827
828 TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
829
830 EnterCriticalSection(&authcache_cs);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200831 LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, basicAuthorizationData, entry)
Aric Stewartfc508932009-10-12 14:24:18 -0500832 {
Juan Lang2c6ad542011-03-01 10:30:46 -0800833 if (!strcmpiW(host,ad->host) && !strcmpW(realm,ad->realm))
Aric Stewartfc508932009-10-12 14:24:18 -0500834 {
835 TRACE("Authorization found in cache\n");
Jacek Caban354a74e2011-04-21 13:39:03 +0200836 *auth_data = heap_alloc(ad->authorizationLen);
Juan Lang2c6ad542011-03-01 10:30:46 -0800837 memcpy(*auth_data,ad->authorization,ad->authorizationLen);
838 rc = ad->authorizationLen;
Aric Stewartfc508932009-10-12 14:24:18 -0500839 break;
840 }
841 }
842 LeaveCriticalSection(&authcache_cs);
843 return rc;
844}
845
846static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
847{
848 struct list *cursor;
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200849 basicAuthorizationData* ad = NULL;
Aric Stewartfc508932009-10-12 14:24:18 -0500850
851 TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
852
853 EnterCriticalSection(&authcache_cs);
854 LIST_FOR_EACH(cursor, &basicAuthorizationCache)
855 {
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200856 basicAuthorizationData *check = LIST_ENTRY(cursor,basicAuthorizationData,entry);
Juan Lang2c6ad542011-03-01 10:30:46 -0800857 if (!strcmpiW(host,check->host) && !strcmpW(realm,check->realm))
Aric Stewartfc508932009-10-12 14:24:18 -0500858 {
859 ad = check;
860 break;
861 }
862 }
863
864 if (ad)
865 {
866 TRACE("Found match in cache, replacing\n");
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200867 heap_free(ad->authorization);
Jacek Caban354a74e2011-04-21 13:39:03 +0200868 ad->authorization = heap_alloc(auth_data_len);
Juan Lang2c6ad542011-03-01 10:30:46 -0800869 memcpy(ad->authorization, auth_data, auth_data_len);
870 ad->authorizationLen = auth_data_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500871 }
872 else
873 {
Jacek Caban354a74e2011-04-21 13:39:03 +0200874 ad = heap_alloc(sizeof(basicAuthorizationData));
Juan Lang2c6ad542011-03-01 10:30:46 -0800875 ad->host = heap_strdupW(host);
Jacek Caban0281b7d2011-07-28 16:53:57 +0200876 ad->realm = heap_strdupW(realm);
Jacek Caban354a74e2011-04-21 13:39:03 +0200877 ad->authorization = heap_alloc(auth_data_len);
Juan Lang2c6ad542011-03-01 10:30:46 -0800878 memcpy(ad->authorization, auth_data, auth_data_len);
879 ad->authorizationLen = auth_data_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500880 list_add_head(&basicAuthorizationCache,&ad->entry);
881 TRACE("authorization cached\n");
882 }
883 LeaveCriticalSection(&authcache_cs);
884}
885
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200886static BOOL retrieve_cached_authorization(LPWSTR host, LPWSTR scheme,
887 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
888{
889 authorizationData *ad;
890
891 TRACE("Looking for authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
892
893 EnterCriticalSection(&authcache_cs);
894 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry) {
895 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
896 TRACE("Authorization found in cache\n");
897
898 nt_auth_identity->User = heap_strdupW(ad->user);
899 nt_auth_identity->Password = heap_strdupW(ad->password);
Jacek Caban354a74e2011-04-21 13:39:03 +0200900 nt_auth_identity->Domain = heap_alloc(sizeof(WCHAR)*ad->domain_len);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200901 if(!nt_auth_identity->User || !nt_auth_identity->Password ||
902 (!nt_auth_identity->Domain && ad->domain_len)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200903 heap_free(nt_auth_identity->User);
904 heap_free(nt_auth_identity->Password);
905 heap_free(nt_auth_identity->Domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200906 break;
907 }
908
909 nt_auth_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
910 nt_auth_identity->UserLength = ad->user_len;
911 nt_auth_identity->PasswordLength = ad->password_len;
912 memcpy(nt_auth_identity->Domain, ad->domain, sizeof(WCHAR)*ad->domain_len);
913 nt_auth_identity->DomainLength = ad->domain_len;
914 LeaveCriticalSection(&authcache_cs);
915 return TRUE;
916 }
917 }
918 LeaveCriticalSection(&authcache_cs);
919
920 return FALSE;
921}
922
923static void cache_authorization(LPWSTR host, LPWSTR scheme,
924 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
925{
926 authorizationData *ad;
927 BOOL found = FALSE;
928
929 TRACE("Caching authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
930
931 EnterCriticalSection(&authcache_cs);
932 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry)
933 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
934 found = TRUE;
935 break;
936 }
937
938 if(found) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200939 heap_free(ad->user);
940 heap_free(ad->password);
941 heap_free(ad->domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200942 } else {
Jacek Caban354a74e2011-04-21 13:39:03 +0200943 ad = heap_alloc(sizeof(authorizationData));
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200944 if(!ad) {
945 LeaveCriticalSection(&authcache_cs);
946 return;
947 }
948
949 ad->host = heap_strdupW(host);
950 ad->scheme = heap_strdupW(scheme);
951 list_add_head(&authorizationCache, &ad->entry);
952 }
953
954 ad->user = heap_strndupW(nt_auth_identity->User, nt_auth_identity->UserLength);
955 ad->password = heap_strndupW(nt_auth_identity->Password, nt_auth_identity->PasswordLength);
956 ad->domain = heap_strndupW(nt_auth_identity->Domain, nt_auth_identity->DomainLength);
957 ad->user_len = nt_auth_identity->UserLength;
958 ad->password_len = nt_auth_identity->PasswordLength;
959 ad->domain_len = nt_auth_identity->DomainLength;
960
961 if(!ad->host || !ad->scheme || !ad->user || !ad->password
962 || (nt_auth_identity->Domain && !ad->domain)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200963 heap_free(ad->host);
964 heap_free(ad->scheme);
965 heap_free(ad->user);
966 heap_free(ad->password);
967 heap_free(ad->domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200968 list_remove(&ad->entry);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200969 heap_free(ad);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200970 }
971
972 LeaveCriticalSection(&authcache_cs);
973}
974
Juan Langb49b2432011-03-01 10:59:39 -0800975static BOOL HTTP_DoAuthorization( http_request_t *request, LPCWSTR pszAuthValue,
Rob Shearmancb289692007-06-05 19:49:58 +0100976 struct HttpAuthInfo **ppAuthInfo,
Aric Stewartfc508932009-10-12 14:24:18 -0500977 LPWSTR domain_and_username, LPWSTR password,
978 LPWSTR host )
Rob Shearman4b507682007-05-21 14:26:26 +0100979{
980 SECURITY_STATUS sec_status;
Rob Shearmancb289692007-06-05 19:49:58 +0100981 struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
Rob Shearman7b948712007-05-26 08:49:12 +0100982 BOOL first = FALSE;
Aric Stewartfc508932009-10-12 14:24:18 -0500983 LPWSTR szRealm = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +0100984
985 TRACE("%s\n", debugstr_w(pszAuthValue));
986
987 if (!pAuthInfo)
988 {
989 TimeStamp exp;
990
Rob Shearman7b948712007-05-26 08:49:12 +0100991 first = TRUE;
Jacek Caban354a74e2011-04-21 13:39:03 +0200992 pAuthInfo = heap_alloc(sizeof(*pAuthInfo));
Rob Shearman4b507682007-05-21 14:26:26 +0100993 if (!pAuthInfo)
994 return FALSE;
995
Rob Shearman4b507682007-05-21 14:26:26 +0100996 SecInvalidateHandle(&pAuthInfo->cred);
997 SecInvalidateHandle(&pAuthInfo->ctx);
998 memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
999 pAuthInfo->attr = 0;
1000 pAuthInfo->auth_data = NULL;
1001 pAuthInfo->auth_data_len = 0;
1002 pAuthInfo->finished = FALSE;
1003
Aric Stewartfc508932009-10-12 14:24:18 -05001004 if (is_basic_auth_value(pszAuthValue,NULL))
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001005 {
1006 static const WCHAR szBasic[] = {'B','a','s','i','c',0};
Jacek Cabanf5987092009-07-17 01:10:41 +02001007 pAuthInfo->scheme = heap_strdupW(szBasic);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001008 if (!pAuthInfo->scheme)
1009 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001010 heap_free(pAuthInfo);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001011 return FALSE;
1012 }
1013 }
1014 else
Rob Shearman4b507682007-05-21 14:26:26 +01001015 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001016 PVOID pAuthData;
Rob Shearman4b507682007-05-21 14:26:26 +01001017 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
Rob Shearman4b507682007-05-21 14:26:26 +01001018
Jacek Cabanf5987092009-07-17 01:10:41 +02001019 pAuthInfo->scheme = heap_strdupW(pszAuthValue);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001020 if (!pAuthInfo->scheme)
1021 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001022 heap_free(pAuthInfo);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001023 return FALSE;
1024 }
1025
Rob Shearman7631bdf2008-03-10 16:40:23 +00001026 if (domain_and_username)
Rob Shearman4b507682007-05-21 14:26:26 +01001027 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001028 WCHAR *user = strchrW(domain_and_username, '\\');
1029 WCHAR *domain = domain_and_username;
Rob Shearman4b507682007-05-21 14:26:26 +01001030
Rob Shearman7631bdf2008-03-10 16:40:23 +00001031 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
1032
1033 pAuthData = &nt_auth_identity;
1034
1035 if (user) user++;
1036 else
1037 {
1038 user = domain_and_username;
1039 domain = NULL;
1040 }
1041
1042 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1043 nt_auth_identity.User = user;
1044 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
1045 nt_auth_identity.Domain = domain;
1046 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
1047 nt_auth_identity.Password = password;
1048 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001049
1050 cache_authorization(host, pAuthInfo->scheme, &nt_auth_identity);
Rob Shearman7631bdf2008-03-10 16:40:23 +00001051 }
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001052 else if(retrieve_cached_authorization(host, pAuthInfo->scheme, &nt_auth_identity))
1053 pAuthData = &nt_auth_identity;
Rob Shearman7631bdf2008-03-10 16:40:23 +00001054 else
1055 /* use default credentials */
1056 pAuthData = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001057
1058 sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
1059 SECPKG_CRED_OUTBOUND, NULL,
Rob Shearman7631bdf2008-03-10 16:40:23 +00001060 pAuthData, NULL,
Rob Shearman4b507682007-05-21 14:26:26 +01001061 NULL, &pAuthInfo->cred,
1062 &exp);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001063
1064 if(pAuthData && !domain_and_username) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001065 heap_free(nt_auth_identity.User);
1066 heap_free(nt_auth_identity.Domain);
1067 heap_free(nt_auth_identity.Password);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001068 }
1069
Rob Shearman0be05ab2008-03-10 16:41:44 +00001070 if (sec_status == SEC_E_OK)
1071 {
1072 PSecPkgInfoW sec_pkg_info;
1073 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
1074 if (sec_status == SEC_E_OK)
1075 {
1076 pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
1077 FreeContextBuffer(sec_pkg_info);
1078 }
1079 }
Rob Shearman4b507682007-05-21 14:26:26 +01001080 if (sec_status != SEC_E_OK)
1081 {
1082 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
1083 debugstr_w(pAuthInfo->scheme), sec_status);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001084 heap_free(pAuthInfo->scheme);
1085 heap_free(pAuthInfo);
Rob Shearman4b507682007-05-21 14:26:26 +01001086 return FALSE;
1087 }
1088 }
Rob Shearmancb289692007-06-05 19:49:58 +01001089 *ppAuthInfo = pAuthInfo;
Rob Shearman4b507682007-05-21 14:26:26 +01001090 }
1091 else if (pAuthInfo->finished)
1092 return FALSE;
1093
1094 if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
1095 strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
1096 {
1097 ERR("authentication scheme changed from %s to %s\n",
1098 debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
1099 return FALSE;
1100 }
1101
Aric Stewartfc508932009-10-12 14:24:18 -05001102 if (is_basic_auth_value(pszAuthValue,&szRealm))
Rob Shearman4b507682007-05-21 14:26:26 +01001103 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001104 int userlen;
1105 int passlen;
Aric Stewartfc508932009-10-12 14:24:18 -05001106 char *auth_data = NULL;
1107 UINT auth_data_len = 0;
Rob Shearman847cc512007-05-21 14:28:02 +01001108
Aric Stewartfc508932009-10-12 14:24:18 -05001109 TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
Rob Shearman847cc512007-05-21 14:28:02 +01001110
Aric Stewartfc508932009-10-12 14:24:18 -05001111 if (!domain_and_username)
1112 {
1113 if (host && szRealm)
1114 auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data);
1115 if (auth_data_len == 0)
1116 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001117 heap_free(szRealm);
Aric Stewartfc508932009-10-12 14:24:18 -05001118 return FALSE;
1119 }
1120 }
1121 else
1122 {
1123 userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
1124 passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
Rob Shearman7631bdf2008-03-10 16:40:23 +00001125
Aric Stewartfc508932009-10-12 14:24:18 -05001126 /* length includes a nul terminator, which will be re-used for the ':' */
Jacek Caban354a74e2011-04-21 13:39:03 +02001127 auth_data = heap_alloc(userlen + 1 + passlen);
Aric Stewartfc508932009-10-12 14:24:18 -05001128 if (!auth_data)
1129 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001130 heap_free(szRealm);
Aric Stewartfc508932009-10-12 14:24:18 -05001131 return FALSE;
1132 }
Rob Shearman7631bdf2008-03-10 16:40:23 +00001133
Aric Stewartfc508932009-10-12 14:24:18 -05001134 WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
1135 auth_data[userlen] = ':';
1136 WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
1137 auth_data_len = userlen + 1 + passlen;
1138 if (host && szRealm)
1139 cache_basic_authorization(host, szRealm, auth_data, auth_data_len);
1140 }
Rob Shearman847cc512007-05-21 14:28:02 +01001141
1142 pAuthInfo->auth_data = auth_data;
Aric Stewartfc508932009-10-12 14:24:18 -05001143 pAuthInfo->auth_data_len = auth_data_len;
Rob Shearman847cc512007-05-21 14:28:02 +01001144 pAuthInfo->finished = TRUE;
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001145 heap_free(szRealm);
Rob Shearman847cc512007-05-21 14:28:02 +01001146 return TRUE;
Rob Shearman4b507682007-05-21 14:26:26 +01001147 }
1148 else
1149 {
1150 LPCWSTR pszAuthData;
1151 SecBufferDesc out_desc, in_desc;
1152 SecBuffer out, in;
1153 unsigned char *buffer;
1154 ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
1155 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
1156
1157 in.BufferType = SECBUFFER_TOKEN;
1158 in.cbBuffer = 0;
1159 in.pvBuffer = NULL;
1160
1161 in_desc.ulVersion = 0;
1162 in_desc.cBuffers = 1;
1163 in_desc.pBuffers = &in;
1164
1165 pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
1166 if (*pszAuthData == ' ')
1167 {
1168 pszAuthData++;
1169 in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
Jacek Caban354a74e2011-04-21 13:39:03 +02001170 in.pvBuffer = heap_alloc(in.cbBuffer);
Rob Shearman4b507682007-05-21 14:26:26 +01001171 HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
1172 }
1173
Jacek Caban354a74e2011-04-21 13:39:03 +02001174 buffer = heap_alloc(pAuthInfo->max_token);
Rob Shearman4b507682007-05-21 14:26:26 +01001175
1176 out.BufferType = SECBUFFER_TOKEN;
Rob Shearman0be05ab2008-03-10 16:41:44 +00001177 out.cbBuffer = pAuthInfo->max_token;
Rob Shearman4b507682007-05-21 14:26:26 +01001178 out.pvBuffer = buffer;
1179
1180 out_desc.ulVersion = 0;
1181 out_desc.cBuffers = 1;
1182 out_desc.pBuffers = &out;
1183
Rob Shearman7b948712007-05-26 08:49:12 +01001184 sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
Rob Shearman5edcf3a2008-01-24 19:30:11 +00001185 first ? NULL : &pAuthInfo->ctx,
Juan Lang20980062011-03-01 11:18:22 -08001186 first ? request->session->serverName : NULL,
Rob Shearman4b507682007-05-21 14:26:26 +01001187 context_req, 0, SECURITY_NETWORK_DREP,
1188 in.pvBuffer ? &in_desc : NULL,
1189 0, &pAuthInfo->ctx, &out_desc,
1190 &pAuthInfo->attr, &pAuthInfo->exp);
1191 if (sec_status == SEC_E_OK)
1192 {
1193 pAuthInfo->finished = TRUE;
1194 pAuthInfo->auth_data = out.pvBuffer;
1195 pAuthInfo->auth_data_len = out.cbBuffer;
1196 TRACE("sending last auth packet\n");
1197 }
1198 else if (sec_status == SEC_I_CONTINUE_NEEDED)
1199 {
1200 pAuthInfo->auth_data = out.pvBuffer;
1201 pAuthInfo->auth_data_len = out.cbBuffer;
1202 TRACE("sending next auth packet\n");
1203 }
1204 else
1205 {
1206 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001207 heap_free(out.pvBuffer);
Hans Leidekker50fef742009-09-02 11:44:43 +02001208 destroy_authinfo(pAuthInfo);
1209 *ppAuthInfo = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001210 return FALSE;
1211 }
1212 }
1213
1214 return TRUE;
1215}
1216
Robert Shearmandee87512004-07-19 20:09:20 +00001217/***********************************************************************
Mike McCormackb288f712004-06-14 17:57:26 +00001218 * HTTP_HttpAddRequestHeadersW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001219 */
Juan Langb49b2432011-03-01 10:59:39 -08001220static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *request,
Mike McCormacka4e902c2004-03-30 04:36:09 +00001221 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001222{
Mike McCormacka4e902c2004-03-30 04:36:09 +00001223 LPWSTR lpszStart;
1224 LPWSTR lpszEnd;
1225 LPWSTR buffer;
Jacek Cabane9749652009-11-30 20:01:00 +01001226 DWORD len, res = ERROR_HTTP_INVALID_HEADER;
David Hammerton852c7ae2003-06-20 23:26:56 +00001227
Francois Gougetabfa73b2008-02-19 00:18:02 +01001228 TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
Mike McCormack08c6c692004-08-10 23:41:35 +00001229
Alexandre Julliard7c1925a02005-09-13 15:00:32 +00001230 if( dwHeaderLength == ~0U )
Mike McCormack08c6c692004-08-10 23:41:35 +00001231 len = strlenW(lpszHeader);
1232 else
1233 len = dwHeaderLength;
Jacek Caban354a74e2011-04-21 13:39:03 +02001234 buffer = heap_alloc(sizeof(WCHAR)*(len+1));
Peter Berg Larsene732fc02005-03-28 14:17:51 +00001235 lstrcpynW( buffer, lpszHeader, len + 1);
Mike McCormack08c6c692004-08-10 23:41:35 +00001236
Ulrich Czekallac2757242000-06-11 20:04:44 +00001237 lpszStart = buffer;
1238
1239 do
1240 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00001241 LPWSTR * pFieldAndValue;
1242
Ulrich Czekallac2757242000-06-11 20:04:44 +00001243 lpszEnd = lpszStart;
1244
1245 while (*lpszEnd != '\0')
1246 {
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001247 if (*lpszEnd == '\r' || *lpszEnd == '\n')
Ulrich Czekallac2757242000-06-11 20:04:44 +00001248 break;
1249 lpszEnd++;
1250 }
1251
Robert Shearman4cd38b42004-07-13 23:34:28 +00001252 if (*lpszStart == '\0')
Ulrich Czekallac2757242000-06-11 20:04:44 +00001253 break;
1254
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001255 if (*lpszEnd == '\r' || *lpszEnd == '\n')
Robert Shearman4cd38b42004-07-13 23:34:28 +00001256 {
1257 *lpszEnd = '\0';
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001258 lpszEnd++; /* Jump over newline */
Robert Shearman4cd38b42004-07-13 23:34:28 +00001259 }
Mike McCormacka4e902c2004-03-30 04:36:09 +00001260 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
Paul TBBle Hampson4d57ee32009-04-25 02:31:06 +10001261 if (*lpszStart == '\0')
1262 {
1263 /* Skip 0-length headers */
1264 lpszStart = lpszEnd;
Jacek Cabane9749652009-11-30 20:01:00 +01001265 res = ERROR_SUCCESS;
Paul TBBle Hampson4d57ee32009-04-25 02:31:06 +10001266 continue;
1267 }
Robert Shearmanb72a6822004-09-23 22:53:50 +00001268 pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
1269 if (pFieldAndValue)
1270 {
Juan Langb49b2432011-03-01 10:59:39 -08001271 res = HTTP_VerifyValidHeader(request, pFieldAndValue[0]);
Jacek Cabane9749652009-11-30 20:01:00 +01001272 if (res == ERROR_SUCCESS)
Juan Langb49b2432011-03-01 10:59:39 -08001273 res = HTTP_ProcessHeader(request, pFieldAndValue[0],
Aric Stewartc8dfc022007-07-26 08:59:00 -05001274 pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
Robert Shearmanb72a6822004-09-23 22:53:50 +00001275 HTTP_FreeTokens(pFieldAndValue);
1276 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00001277
Robert Shearman4cd38b42004-07-13 23:34:28 +00001278 lpszStart = lpszEnd;
Jacek Cabane9749652009-11-30 20:01:00 +01001279 } while (res == ERROR_SUCCESS);
Ulrich Czekallac2757242000-06-11 20:04:44 +00001280
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001281 heap_free(buffer);
Jacek Cabane9749652009-11-30 20:01:00 +01001282 return res;
Mike McCormackb288f712004-06-14 17:57:26 +00001283}
1284
1285/***********************************************************************
1286 * HttpAddRequestHeadersW (WININET.@)
1287 *
1288 * Adds one or more HTTP header to the request handler
1289 *
Francois Gougetabfa73b2008-02-19 00:18:02 +01001290 * NOTE
1291 * On Windows if dwHeaderLength includes the trailing '\0', then
1292 * HttpAddRequestHeadersW() adds it too. However this results in an
1293 * invalid Http header which is rejected by some servers so we probably
1294 * don't need to match Windows on that point.
1295 *
Mike McCormackb288f712004-06-14 17:57:26 +00001296 * RETURNS
1297 * TRUE on success
1298 * FALSE on failure
1299 *
1300 */
1301BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
1302 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1303{
Juan Langb49b2432011-03-01 10:59:39 -08001304 http_request_t *request;
Jacek Cabane9749652009-11-30 20:01:00 +01001305 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
Mike McCormackb288f712004-06-14 17:57:26 +00001306
Francois Gougetabfa73b2008-02-19 00:18:02 +01001307 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
Mike McCormackb288f712004-06-14 17:57:26 +00001308
1309 if (!lpszHeader)
1310 return TRUE;
1311
Juan Langb49b2432011-03-01 10:59:39 -08001312 request = (http_request_t*) get_handle_object( hHttpRequest );
1313 if (request && request->hdr.htype == WH_HHTTPREQ)
1314 res = HTTP_HttpAddRequestHeadersW( request, lpszHeader, dwHeaderLength, dwModifier );
1315 if( request )
1316 WININET_Release( &request->hdr );
Mike McCormackb288f712004-06-14 17:57:26 +00001317
Jacek Cabane9749652009-11-30 20:01:00 +01001318 if(res != ERROR_SUCCESS)
1319 SetLastError(res);
1320 return res == ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00001321}
1322
Chris Morgana8b32162002-09-27 22:05:23 +00001323/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00001324 * HttpAddRequestHeadersA (WININET.@)
1325 *
1326 * Adds one or more HTTP header to the request handler
1327 *
1328 * RETURNS
1329 * TRUE on success
1330 * FALSE on failure
1331 *
1332 */
1333BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
1334 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1335{
1336 DWORD len;
1337 LPWSTR hdr;
1338 BOOL r;
1339
Francois Gougetabfa73b2008-02-19 00:18:02 +01001340 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001341
1342 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
Jacek Caban354a74e2011-04-21 13:39:03 +02001343 hdr = heap_alloc(len*sizeof(WCHAR));
Mike McCormacka4e902c2004-03-30 04:36:09 +00001344 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
Alexandre Julliard7c1925a02005-09-13 15:00:32 +00001345 if( dwHeaderLength != ~0U )
Mike McCormacka4e902c2004-03-30 04:36:09 +00001346 dwHeaderLength = len;
1347
1348 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
1349
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001350 heap_free( hdr );
Mike McCormacka4e902c2004-03-30 04:36:09 +00001351 return r;
1352}
1353
1354/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00001355 * HttpOpenRequestA (WININET.@)
Alberto Massarid476a5a2002-11-12 02:13:04 +00001356 *
1357 * Open a HTTP request handle
1358 *
1359 * RETURNS
1360 * HINTERNET a HTTP request handle on success
1361 * NULL on failure
1362 *
1363 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00001364HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
1365 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1366 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
Francois Gougetd4337f22007-08-30 16:21:33 +02001367 DWORD dwFlags, DWORD_PTR dwContext)
Alberto Massarid476a5a2002-11-12 02:13:04 +00001368{
Mike McCormacka4e902c2004-03-30 04:36:09 +00001369 LPWSTR szVerb = NULL, szObjectName = NULL;
1370 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
Jacek Caban97936252009-07-17 01:17:13 +02001371 INT acceptTypesCount;
David Hammerton852c7ae2003-06-20 23:26:56 +00001372 HINTERNET rc = FALSE;
Hans Leidekker493b6912008-05-07 13:19:37 +02001373 LPCSTR *types;
1374
Francois Gougetd4337f22007-08-30 16:21:33 +02001375 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
Mike McCormacka4e902c2004-03-30 04:36:09 +00001376 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1377 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
David Hammerton852c7ae2003-06-20 23:26:56 +00001378 dwFlags, dwContext);
Alberto Massaribc8bd722002-12-06 23:20:31 +00001379
David Hammerton852c7ae2003-06-20 23:26:56 +00001380 if (lpszVerb)
1381 {
Jacek Caban97936252009-07-17 01:17:13 +02001382 szVerb = heap_strdupAtoW(lpszVerb);
Mike McCormack43629c92003-08-15 03:47:30 +00001383 if ( !szVerb )
David Hammerton852c7ae2003-06-20 23:26:56 +00001384 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001385 }
1386
1387 if (lpszObjectName)
1388 {
Jacek Caban97936252009-07-17 01:17:13 +02001389 szObjectName = heap_strdupAtoW(lpszObjectName);
Mike McCormack43629c92003-08-15 03:47:30 +00001390 if ( !szObjectName )
David Hammerton852c7ae2003-06-20 23:26:56 +00001391 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001392 }
1393
1394 if (lpszVersion)
1395 {
Jacek Caban97936252009-07-17 01:17:13 +02001396 szVersion = heap_strdupAtoW(lpszVersion);
Mike McCormack43629c92003-08-15 03:47:30 +00001397 if ( !szVersion )
David Hammerton852c7ae2003-06-20 23:26:56 +00001398 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001399 }
1400
1401 if (lpszReferrer)
1402 {
Jacek Caban97936252009-07-17 01:17:13 +02001403 szReferrer = heap_strdupAtoW(lpszReferrer);
Mike McCormack43629c92003-08-15 03:47:30 +00001404 if ( !szReferrer )
David Hammerton852c7ae2003-06-20 23:26:56 +00001405 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001406 }
1407
David Hammerton852c7ae2003-06-20 23:26:56 +00001408 if (lpszAcceptTypes)
1409 {
David Hammerton852c7ae2003-06-20 23:26:56 +00001410 acceptTypesCount = 0;
Hans Leidekker493b6912008-05-07 13:19:37 +02001411 types = lpszAcceptTypes;
1412 while (*types)
David Hammerton852c7ae2003-06-20 23:26:56 +00001413 {
Hans Leidekkerbd805292008-10-24 11:08:12 +02001414 __TRY
Hans Leidekker493b6912008-05-07 13:19:37 +02001415 {
Hans Leidekkerbd805292008-10-24 11:08:12 +02001416 /* find out how many there are */
1417 if (*types && **types)
1418 {
1419 TRACE("accept type: %s\n", debugstr_a(*types));
1420 acceptTypesCount++;
1421 }
Hans Leidekker493b6912008-05-07 13:19:37 +02001422 }
Hans Leidekkerbd805292008-10-24 11:08:12 +02001423 __EXCEPT_PAGE_FAULT
1424 {
1425 WARN("invalid accept type pointer\n");
1426 }
1427 __ENDTRY;
Hans Leidekker493b6912008-05-07 13:19:37 +02001428 types++;
1429 }
Jacek Caban354a74e2011-04-21 13:39:03 +02001430 szAcceptTypes = heap_alloc(sizeof(WCHAR *) * (acceptTypesCount+1));
Hans Leidekker493b6912008-05-07 13:19:37 +02001431 if (!szAcceptTypes) goto end;
1432
1433 acceptTypesCount = 0;
1434 types = lpszAcceptTypes;
1435 while (*types)
1436 {
Hans Leidekkerbd805292008-10-24 11:08:12 +02001437 __TRY
Hans Leidekker493b6912008-05-07 13:19:37 +02001438 {
Hans Leidekkerbd805292008-10-24 11:08:12 +02001439 if (*types && **types)
Jacek Caban97936252009-07-17 01:17:13 +02001440 szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
Hans Leidekker493b6912008-05-07 13:19:37 +02001441 }
Hans Leidekkerbd805292008-10-24 11:08:12 +02001442 __EXCEPT_PAGE_FAULT
1443 {
1444 /* ignore invalid pointer */
1445 }
1446 __ENDTRY;
Hans Leidekker493b6912008-05-07 13:19:37 +02001447 types++;
David Hammerton852c7ae2003-06-20 23:26:56 +00001448 }
Mike McCormacka4e902c2004-03-30 04:36:09 +00001449 szAcceptTypes[acceptTypesCount] = NULL;
David Hammerton852c7ae2003-06-20 23:26:56 +00001450 }
David Hammerton852c7ae2003-06-20 23:26:56 +00001451
Mike McCormacka4e902c2004-03-30 04:36:09 +00001452 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
1453 szVersion, szReferrer,
1454 (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
David Hammerton852c7ae2003-06-20 23:26:56 +00001455
1456end:
1457 if (szAcceptTypes)
1458 {
1459 acceptTypesCount = 0;
1460 while (szAcceptTypes[acceptTypesCount])
1461 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001462 heap_free(szAcceptTypes[acceptTypesCount]);
David Hammerton852c7ae2003-06-20 23:26:56 +00001463 acceptTypesCount++;
1464 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001465 heap_free(szAcceptTypes);
David Hammerton852c7ae2003-06-20 23:26:56 +00001466 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001467 heap_free(szReferrer);
1468 heap_free(szVersion);
1469 heap_free(szObjectName);
1470 heap_free(szVerb);
David Hammerton852c7ae2003-06-20 23:26:56 +00001471 return rc;
Alberto Massarid476a5a2002-11-12 02:13:04 +00001472}
Ulrich Czekallac2757242000-06-11 20:04:44 +00001473
1474/***********************************************************************
Rob Shearmana9ebc702007-01-12 19:17:20 -06001475 * HTTP_EncodeBase64
Mike McCormacka1c16d22003-07-22 03:17:52 +00001476 */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001477static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001478{
1479 UINT n = 0, x;
Andrew Talbot46fc9c22007-02-24 21:55:12 +00001480 static const CHAR HTTP_Base64Enc[] =
Mike McCormacka1c16d22003-07-22 03:17:52 +00001481 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1482
Rob Shearmana9ebc702007-01-12 19:17:20 -06001483 while( len > 0 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001484 {
1485 /* first 6 bits, all from bin[0] */
1486 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1487 x = (bin[0] & 3) << 4;
1488
1489 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001490 if( len == 1 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001491 {
1492 base64[n++] = HTTP_Base64Enc[x];
1493 base64[n++] = '=';
1494 base64[n++] = '=';
1495 break;
1496 }
1497 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1498 x = ( bin[1] & 0x0f ) << 2;
1499
1500 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001501 if( len == 2 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001502 {
1503 base64[n++] = HTTP_Base64Enc[x];
1504 base64[n++] = '=';
1505 break;
1506 }
1507 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1508
1509 /* last 6 bits, all from bin [2] */
1510 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1511 bin += 3;
Rob Shearmana9ebc702007-01-12 19:17:20 -06001512 len -= 3;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001513 }
1514 base64[n] = 0;
1515 return n;
1516}
1517
Rob Shearman4b507682007-05-21 14:26:26 +01001518#define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1519 ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1520 ((x) >= '0' && (x) <= '9') ? (x) - '0' + 52 : \
1521 ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1522static const signed char HTTP_Base64Dec[256] =
1523{
1524 CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1525 CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1526 CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1527 CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1528 CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1529 CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1530 CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1531 CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1532 CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1533 CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1534 CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1535 CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1536 CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1537 CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1538 CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1539 CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1540 CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1541 CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1542 CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1543 CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1544 CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1545 CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1546 CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1547 CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1548 CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1549 CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1550};
1551#undef CH
1552
1553/***********************************************************************
1554 * HTTP_DecodeBase64
1555 */
1556static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
1557{
1558 unsigned int n = 0;
1559
1560 while(*base64)
1561 {
1562 signed char in[4];
1563
Rob Shearmanf8f9dbb2008-02-15 10:06:32 +00001564 if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
Rob Shearman4b507682007-05-21 14:26:26 +01001565 ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
Rob Shearmanf8f9dbb2008-02-15 10:06:32 +00001566 base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
Rob Shearman4b507682007-05-21 14:26:26 +01001567 ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1568 {
1569 WARN("invalid base64: %s\n", debugstr_w(base64));
1570 return 0;
1571 }
1572 if (bin)
1573 bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1574 n++;
1575
1576 if ((base64[2] == '=') && (base64[3] == '='))
1577 break;
1578 if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) ||
1579 ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1580 {
1581 WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1582 return 0;
1583 }
1584 if (bin)
1585 bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1586 n++;
1587
1588 if (base64[3] == '=')
1589 break;
1590 if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) ||
1591 ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1592 {
1593 WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1594 return 0;
1595 }
1596 if (bin)
1597 bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1598 n++;
1599
1600 base64 += 4;
1601 }
1602
1603 return n;
1604}
1605
Mike McCormacka1c16d22003-07-22 03:17:52 +00001606/***********************************************************************
Hans Leidekker1c5bc9a2008-05-09 15:18:51 +02001607 * HTTP_InsertAuthorization
Rob Shearman4b507682007-05-21 14:26:26 +01001608 *
1609 * Insert or delete the authorization field in the request header.
1610 */
Juan Langb49b2432011-03-01 10:59:39 -08001611static BOOL HTTP_InsertAuthorization( http_request_t *request, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
Rob Shearman4b507682007-05-21 14:26:26 +01001612{
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001613 if (pAuthInfo)
Rob Shearman4b507682007-05-21 14:26:26 +01001614 {
1615 static const WCHAR wszSpace[] = {' ',0};
Rob Shearman01826e02007-11-27 14:19:50 +00001616 static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
Rob Shearman4b507682007-05-21 14:26:26 +01001617 unsigned int len;
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001618 WCHAR *authorization = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001619
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001620 if (pAuthInfo->auth_data_len)
Rob Shearman01826e02007-11-27 14:19:50 +00001621 {
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001622 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1623 len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
Jacek Caban354a74e2011-04-21 13:39:03 +02001624 authorization = heap_alloc((len+1)*sizeof(WCHAR));
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001625 if (!authorization)
1626 return FALSE;
1627
1628 strcpyW(authorization, pAuthInfo->scheme);
1629 strcatW(authorization, wszSpace);
1630 HTTP_EncodeBase64(pAuthInfo->auth_data,
1631 pAuthInfo->auth_data_len,
1632 authorization+strlenW(authorization));
1633
1634 /* clear the data as it isn't valid now that it has been sent to the
1635 * server, unless it's Basic authentication which doesn't do
1636 * connection tracking */
1637 if (strcmpiW(pAuthInfo->scheme, wszBasic))
1638 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001639 heap_free(pAuthInfo->auth_data);
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001640 pAuthInfo->auth_data = NULL;
1641 pAuthInfo->auth_data_len = 0;
1642 }
Rob Shearman01826e02007-11-27 14:19:50 +00001643 }
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001644
1645 TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1646
Juan Langb49b2432011-03-01 10:59:39 -08001647 HTTP_ProcessHeader(request, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001648 heap_free(authorization);
Rob Shearman4b507682007-05-21 14:26:26 +01001649 }
Rob Shearman4b507682007-05-21 14:26:26 +01001650 return TRUE;
1651}
1652
Jacek Caban34abacd2009-07-13 01:41:50 +02001653static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001654{
Hans Leidekker612f3c12008-03-31 20:26:16 +02001655 WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001656 DWORD size;
1657
1658 size = sizeof(new_location);
Jacek Caban9823c232009-12-14 02:27:29 +01001659 if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS)
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001660 {
Jacek Caban354a74e2011-04-21 13:39:03 +02001661 if (!(url = heap_alloc(size + sizeof(WCHAR)))) return NULL;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001662 strcpyW( url, new_location );
1663 }
1664 else
1665 {
1666 static const WCHAR slash[] = { '/',0 };
André Hentschel1a39e292011-03-27 15:27:46 +02001667 static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 };
1668 static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','u',0 };
Juan Lang20980062011-03-01 11:18:22 -08001669 http_session_t *session = req->session;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001670
Lei Zhangbd584632008-05-21 19:04:10 -07001671 size = 16; /* "https://" + sizeof(port#) + ":/\0" */
Juan Lang20980062011-03-01 11:18:22 -08001672 size += strlenW( session->hostName ) + strlenW( req->path );
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001673
Jacek Caban354a74e2011-04-21 13:39:03 +02001674 if (!(url = heap_alloc(size * sizeof(WCHAR)))) return NULL;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001675
Lei Zhangbd584632008-05-21 19:04:10 -07001676 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
Juan Lang8e050392011-03-01 11:02:14 -08001677 sprintfW( url, formatSSL, session->hostName, session->hostPort );
Lei Zhangbd584632008-05-21 19:04:10 -07001678 else
Juan Lang8e050392011-03-01 11:02:14 -08001679 sprintfW( url, format, session->hostName, session->hostPort );
Juan Lang20980062011-03-01 11:18:22 -08001680 if (req->path[0] != '/') strcatW( url, slash );
1681 strcatW( url, req->path );
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001682 }
1683 TRACE("url=%s\n", debugstr_w(url));
1684 return url;
1685}
1686
Rob Shearman4b507682007-05-21 14:26:26 +01001687/***********************************************************************
Mike McCormacka1c16d22003-07-22 03:17:52 +00001688 * HTTP_DealWithProxy
1689 */
Juan Langb49b2432011-03-01 10:59:39 -08001690static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *session, http_request_t *request)
Mike McCormacka1c16d22003-07-22 03:17:52 +00001691{
Mike McCormacka4e902c2004-03-30 04:36:09 +00001692 WCHAR buf[MAXHOSTNAME];
Juan Langde6a0a82010-03-13 09:36:46 -08001693 WCHAR protoProxy[MAXHOSTNAME + 15];
1694 DWORD protoProxyLen = sizeof(protoProxy) / sizeof(protoProxy[0]);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001695 WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
Hans Leidekker781f3f72006-10-13 15:43:54 +02001696 static WCHAR szNul[] = { 0 };
Mike McCormacka4e902c2004-03-30 04:36:09 +00001697 URL_COMPONENTSW UrlComponents;
Juan Langde6a0a82010-03-13 09:36:46 -08001698 static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001699 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1700 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
Mike McCormacka1c16d22003-07-22 03:17:52 +00001701
1702 memset( &UrlComponents, 0, sizeof UrlComponents );
1703 UrlComponents.dwStructSize = sizeof UrlComponents;
1704 UrlComponents.lpszHostName = buf;
1705 UrlComponents.dwHostNameLength = MAXHOSTNAME;
1706
Juan Lang72431562011-03-01 11:00:49 -08001707 if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen))
Juan Langde6a0a82010-03-13 09:36:46 -08001708 return FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00001709 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
Juan Langde6a0a82010-03-13 09:36:46 -08001710 protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1711 sprintfW(proxy, szFormat, protoProxy);
Uwe Bonnes599c4522003-12-15 19:47:31 +00001712 else
Juan Langde6a0a82010-03-13 09:36:46 -08001713 strcpyW(proxy, protoProxy);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001714 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001715 return FALSE;
1716 if( UrlComponents.dwHostNameLength == 0 )
1717 return FALSE;
1718
Juan Lang20980062011-03-01 11:18:22 -08001719 if( !request->path )
1720 request->path = szNul;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001721
1722 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1723 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1724
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001725 heap_free(session->serverName);
Juan Lang8e050392011-03-01 11:02:14 -08001726 session->serverName = heap_strdupW(UrlComponents.lpszHostName);
1727 session->serverPort = UrlComponents.nPort;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001728
Juan Lang8e050392011-03-01 11:02:14 -08001729 TRACE("proxy server=%s port=%d\n", debugstr_w(session->serverName), session->serverPort);
Mike McCormacka1c16d22003-07-22 03:17:52 +00001730 return TRUE;
1731}
1732
Jacek Caban8a1df202011-05-10 09:26:43 +00001733static DWORD HTTP_ResolveName(http_request_t *request, server_t *server)
Rob Shearman72575a02006-12-07 00:52:50 +00001734{
Jacek Caban8a1df202011-05-10 09:26:43 +00001735 socklen_t addr_len;
Juan Lang058e9182009-07-09 11:36:00 -07001736 const void *addr;
Rob Shearman72575a02006-12-07 00:52:50 +00001737
Jacek Caban8a1df202011-05-10 09:26:43 +00001738 if(server->addr_len)
1739 return ERROR_SUCCESS;
1740
Juan Langb49b2432011-03-01 10:59:39 -08001741 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001742 INTERNET_STATUS_RESOLVING_NAME,
Jacek Caban8a1df202011-05-10 09:26:43 +00001743 server->name,
1744 (strlenW(server->name)+1) * sizeof(WCHAR));
Rob Shearman72575a02006-12-07 00:52:50 +00001745
Jacek Caban8a1df202011-05-10 09:26:43 +00001746 addr_len = sizeof(server->addr);
1747 if (!GetAddress(server->name, server->port, (struct sockaddr *)&server->addr, &addr_len))
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001748 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Rob Shearman72575a02006-12-07 00:52:50 +00001749
Jacek Caban8a1df202011-05-10 09:26:43 +00001750 switch(server->addr.ss_family) {
Juan Lang058e9182009-07-09 11:36:00 -07001751 case AF_INET:
Jacek Caban8a1df202011-05-10 09:26:43 +00001752 addr = &((struct sockaddr_in *)&server->addr)->sin_addr;
Juan Lang058e9182009-07-09 11:36:00 -07001753 break;
Juan Lang481c9b82009-07-09 11:42:25 -07001754 case AF_INET6:
Jacek Caban8a1df202011-05-10 09:26:43 +00001755 addr = &((struct sockaddr_in6 *)&server->addr)->sin6_addr;
Juan Lang481c9b82009-07-09 11:42:25 -07001756 break;
Juan Lang058e9182009-07-09 11:36:00 -07001757 default:
Jacek Caban8a1df202011-05-10 09:26:43 +00001758 WARN("unsupported family %d\n", server->addr.ss_family);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001759 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Juan Lang058e9182009-07-09 11:36:00 -07001760 }
Jacek Caban8a1df202011-05-10 09:26:43 +00001761
1762 server->addr_len = addr_len;
1763 inet_ntop(server->addr.ss_family, addr, server->addr_str, sizeof(server->addr_str));
Juan Langb49b2432011-03-01 10:59:39 -08001764 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001765 INTERNET_STATUS_NAME_RESOLVED,
Jacek Caban8a1df202011-05-10 09:26:43 +00001766 server->addr_str, strlen(server->addr_str)+1);
Hans Leidekker2f994502008-05-31 21:46:07 +02001767
Jacek Caban8a1df202011-05-10 09:26:43 +00001768 TRACE("resolved %s to %s\n", debugstr_w(server->name), server->addr_str);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001769 return ERROR_SUCCESS;
Rob Shearman72575a02006-12-07 00:52:50 +00001770}
1771
Piotr Caban75481bd2010-07-24 17:56:41 +02001772static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1773{
Juan Langb9c348a2011-03-02 08:28:39 -08001774 static const WCHAR http[] = { 'h','t','t','p',':','/','/',0 };
1775 static const WCHAR https[] = { 'h','t','t','p','s',':','/','/',0 };
1776 static const WCHAR slash[] = { '/',0 };
Piotr Caban75481bd2010-07-24 17:56:41 +02001777 LPHTTPHEADERW host_header;
Juan Langb9c348a2011-03-02 08:28:39 -08001778 LPCWSTR scheme;
Piotr Caban75481bd2010-07-24 17:56:41 +02001779
1780 host_header = HTTP_GetHeader(req, hostW);
1781 if(!host_header)
1782 return FALSE;
1783
Juan Langb9c348a2011-03-02 08:28:39 -08001784 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1785 scheme = https;
1786 else
1787 scheme = http;
1788 strcpyW(buf, scheme);
1789 strcatW(buf, host_header->lpszValue);
1790 if (req->path[0] != '/')
1791 strcatW(buf, slash);
1792 strcatW(buf, req->path);
Piotr Caban75481bd2010-07-24 17:56:41 +02001793 return TRUE;
1794}
1795
Jacek Caban5a535d62008-02-26 20:20:41 +01001796
1797/***********************************************************************
1798 * HTTPREQ_Destroy (internal)
1799 *
1800 * Deallocate request handle
1801 *
1802 */
Jacek Caban44d633a2009-07-07 21:46:09 +02001803static void HTTPREQ_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01001804{
Juan Langb49b2432011-03-01 10:59:39 -08001805 http_request_t *request = (http_request_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01001806 DWORD i;
1807
1808 TRACE("\n");
1809
Juan Langb49b2432011-03-01 10:59:39 -08001810 if(request->hCacheFile) {
Piotr Caban75481bd2010-07-24 17:56:41 +02001811 WCHAR url[INTERNET_MAX_URL_LENGTH];
Piotr Caban75481bd2010-07-24 17:56:41 +02001812
Juan Langb49b2432011-03-01 10:59:39 -08001813 CloseHandle(request->hCacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001814
Juan Langb49b2432011-03-01 10:59:39 -08001815 if(HTTP_GetRequestURL(request, url)) {
Juan Lang011b26b2011-03-03 15:33:40 -08001816 DWORD headersLen;
1817
1818 headersLen = request->rawHeaders ? strlenW(request->rawHeaders) : 0;
Juan Lang28e92292011-03-04 11:43:54 -08001819 CommitUrlCacheEntryW(url, request->cacheFile, request->expires,
Juan Lang011b26b2011-03-03 15:33:40 -08001820 request->last_modified, NORMAL_CACHE_ENTRY,
1821 request->rawHeaders, headersLen, NULL, 0);
Piotr Caban75481bd2010-07-24 17:56:41 +02001822 }
1823 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001824 heap_free(request->cacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001825
Juan Langb49b2432011-03-01 10:59:39 -08001826 DeleteCriticalSection( &request->read_section );
Juan Lang20980062011-03-01 11:18:22 -08001827 WININET_Release(&request->session->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01001828
Juan Lang20980062011-03-01 11:18:22 -08001829 destroy_authinfo(request->authInfo);
1830 destroy_authinfo(request->proxyAuthInfo);
Hans Leidekkerd5dca632008-10-17 13:46:25 +02001831
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001832 heap_free(request->path);
1833 heap_free(request->verb);
1834 heap_free(request->rawHeaders);
1835 heap_free(request->version);
1836 heap_free(request->statusText);
Jacek Caban5a535d62008-02-26 20:20:41 +01001837
Juan Langb49b2432011-03-01 10:59:39 -08001838 for (i = 0; i < request->nCustHeaders; i++)
Jacek Caban5a535d62008-02-26 20:20:41 +01001839 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001840 heap_free(request->custHeaders[i].lpszField);
1841 heap_free(request->custHeaders[i].lpszValue);
Jacek Caban5a535d62008-02-26 20:20:41 +01001842 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02001843 destroy_data_stream(request->data_stream);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001844 heap_free(request->custHeaders);
Jacek Caban5a535d62008-02-26 20:20:41 +01001845}
1846
Jacek Caban8a1df202011-05-10 09:26:43 +00001847static void http_release_netconn(http_request_t *req, BOOL reuse)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001848{
Jacek Caban8a1df202011-05-10 09:26:43 +00001849 TRACE("%p %p\n",req, req->netconn);
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001850
Jacek Caban8a1df202011-05-10 09:26:43 +00001851 if(!req->netconn)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001852 return;
1853
Jacek Caban8a1df202011-05-10 09:26:43 +00001854 if(reuse && req->netconn->keep_alive) {
1855 BOOL run_collector;
1856
1857 EnterCriticalSection(&connection_pool_cs);
1858
1859 list_add_head(&req->netconn->server->conn_pool, &req->netconn->pool_entry);
1860 req->netconn->keep_until = GetTickCount64() + COLLECT_TIME;
1861 req->netconn = NULL;
1862
1863 run_collector = !collector_running;
1864 collector_running = TRUE;
1865
1866 LeaveCriticalSection(&connection_pool_cs);
1867
1868 if(run_collector) {
1869 HANDLE thread = NULL;
1870 HMODULE module;
1871
1872 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)WININET_hModule, &module);
1873 if(module)
1874 thread = CreateThread(NULL, 0, collect_connections_proc, NULL, 0, NULL);
1875 if(!thread) {
1876 EnterCriticalSection(&connection_pool_cs);
1877 collector_running = FALSE;
1878 LeaveCriticalSection(&connection_pool_cs);
1879
1880 if(module)
1881 FreeLibrary(module);
1882 }
1883 }
1884 return;
1885 }
1886
1887 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001888 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1889
Jacek Caban8a1df202011-05-10 09:26:43 +00001890 free_netconn(req->netconn);
1891 req->netconn = NULL;
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001892
Jacek Caban8a1df202011-05-10 09:26:43 +00001893 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001894 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1895}
1896
Jacek Caban8a1df202011-05-10 09:26:43 +00001897static void drain_content(http_request_t *req)
1898{
1899 BOOL try_reuse;
1900
1901 if (!req->netconn) return;
1902
1903 if (req->contentLength == -1)
1904 try_reuse = FALSE;
1905 else if(!strcmpW(req->verb, szHEAD))
1906 try_reuse = TRUE;
1907 else
1908 try_reuse = req->data_stream->vtbl->drain_content(req->data_stream, req);
1909
1910 http_release_netconn(req, try_reuse);
1911}
1912
Juan Langb49b2432011-03-01 10:59:39 -08001913static BOOL HTTP_KeepAlive(http_request_t *request)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001914{
1915 WCHAR szVersion[10];
1916 WCHAR szConnectionResponse[20];
1917 DWORD dwBufferSize = sizeof(szVersion);
1918 BOOL keepalive = FALSE;
1919
1920 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1921 * the connection is keep-alive by default */
Juan Langb49b2432011-03-01 10:59:39 -08001922 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS
Jacek Caban9823c232009-12-14 02:27:29 +01001923 && !strcmpiW(szVersion, g_szHttp1_1))
Juan Lang6ae6ea92009-08-10 15:20:45 -07001924 {
1925 keepalive = TRUE;
1926 }
1927
1928 dwBufferSize = sizeof(szConnectionResponse);
Juan Langb49b2432011-03-01 10:59:39 -08001929 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
1930 || HTTP_HttpQueryInfoW(request, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001931 {
1932 keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1933 }
1934
1935 return keepalive;
1936}
1937
Jacek Caban8a1df202011-05-10 09:26:43 +00001938static void HTTPREQ_CloseConnection(object_header_t *hdr)
1939{
1940 http_request_t *req = (http_request_t*)hdr;
1941
1942 drain_content(req);
1943}
1944
Jacek Caban44d633a2009-07-07 21:46:09 +02001945static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01001946{
Jacek Caban34abacd2009-07-13 01:41:50 +02001947 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e010d82008-03-12 02:23:48 +01001948
Jacek Cabane2933c22008-03-12 02:23:20 +01001949 switch(option) {
Juan Lang6ae6ea92009-08-10 15:20:45 -07001950 case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1951 {
Juan Lang20980062011-03-01 11:18:22 -08001952 http_session_t *session = req->session;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001953 INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1954
1955 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1956
1957 if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1958 return ERROR_INSUFFICIENT_BUFFER;
1959 *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1960 /* FIXME: can't get a SOCKET from our connection since we don't use
1961 * winsock
1962 */
1963 info->Socket = 0;
1964 /* FIXME: get source port from req->netConnection */
1965 info->SourcePort = 0;
Juan Lang8e050392011-03-01 11:02:14 -08001966 info->DestPort = session->hostPort;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001967 info->Flags = 0;
1968 if (HTTP_KeepAlive(req))
1969 info->Flags |= IDSI_FLAG_KEEP_ALIVE;
Juan Lang8e050392011-03-01 11:02:14 -08001970 if (session->appInfo->proxy && session->appInfo->proxy[0] != 0)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001971 info->Flags |= IDSI_FLAG_PROXY;
Jacek Caban8a1df202011-05-10 09:26:43 +00001972 if (req->netconn->useSSL)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001973 info->Flags |= IDSI_FLAG_SECURE;
1974
1975 return ERROR_SUCCESS;
1976 }
1977
Aric Stewartc6ae9452009-06-23 15:29:00 +09001978 case INTERNET_OPTION_SECURITY_FLAGS:
1979 {
Juan Lang948173b2010-09-30 13:33:47 -07001980 DWORD flags;
Aric Stewartc6ae9452009-06-23 15:29:00 +09001981
1982 if (*size < sizeof(ULONG))
1983 return ERROR_INSUFFICIENT_BUFFER;
1984
1985 *size = sizeof(DWORD);
Juan Lang948173b2010-09-30 13:33:47 -07001986 flags = 0;
Juan Lang80545ef2010-09-30 17:11:56 -07001987 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
Juan Lang948173b2010-09-30 13:33:47 -07001988 flags |= SECURITY_FLAG_SECURE;
Jacek Caban8a1df202011-05-10 09:26:43 +00001989 flags |= req->security_flags;
1990 if(req->netconn) {
1991 int bits = NETCON_GetCipherStrength(req->netconn);
1992 if (bits >= 128)
1993 flags |= SECURITY_FLAG_STRENGTH_STRONG;
1994 else if (bits >= 56)
1995 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
1996 else
1997 flags |= SECURITY_FLAG_STRENGTH_WEAK;
1998 }
Juan Lang948173b2010-09-30 13:33:47 -07001999 *(DWORD *)buffer = flags;
Aric Stewartc6ae9452009-06-23 15:29:00 +09002000 return ERROR_SUCCESS;
2001 }
2002
Jacek Cabane2933c22008-03-12 02:23:20 +01002003 case INTERNET_OPTION_HANDLE_TYPE:
2004 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2005
2006 if (*size < sizeof(ULONG))
2007 return ERROR_INSUFFICIENT_BUFFER;
2008
2009 *size = sizeof(DWORD);
2010 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
2011 return ERROR_SUCCESS;
Jacek Caban0e010d82008-03-12 02:23:48 +01002012
2013 case INTERNET_OPTION_URL: {
2014 WCHAR url[INTERNET_MAX_URL_LENGTH];
2015 HTTPHEADERW *host;
2016 DWORD len;
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002017 WCHAR *pch;
Jacek Caban0e010d82008-03-12 02:23:48 +01002018
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002019 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
Jacek Caban0e010d82008-03-12 02:23:48 +01002020
2021 TRACE("INTERNET_OPTION_URL\n");
2022
2023 host = HTTP_GetHeader(req, hostW);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002024 strcpyW(url, httpW);
2025 strcatW(url, host->lpszValue);
2026 if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
2027 *pch = 0;
Juan Lang20980062011-03-01 11:18:22 -08002028 strcatW(url, req->path);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002029
Jacek Caban0e010d82008-03-12 02:23:48 +01002030 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
2031
2032 if(unicode) {
2033 len = (strlenW(url)+1) * sizeof(WCHAR);
2034 if(*size < len)
2035 return ERROR_INSUFFICIENT_BUFFER;
2036
2037 *size = len;
2038 strcpyW(buffer, url);
2039 return ERROR_SUCCESS;
2040 }else {
2041 len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
2042 if(len > *size)
2043 return ERROR_INSUFFICIENT_BUFFER;
2044
2045 *size = len;
2046 return ERROR_SUCCESS;
2047 }
2048 }
Jacek Cabance6a2282008-03-12 02:24:06 +01002049
Hans Leidekkerc2932852009-06-16 15:13:52 +02002050 case INTERNET_OPTION_CACHE_TIMESTAMPS: {
2051 INTERNET_CACHE_ENTRY_INFOW *info;
2052 INTERNET_CACHE_TIMESTAMPS *ts = buffer;
2053 WCHAR url[INTERNET_MAX_URL_LENGTH];
2054 DWORD nbytes, error;
2055 BOOL ret;
2056
2057 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
2058
2059 if (*size < sizeof(*ts))
2060 {
2061 *size = sizeof(*ts);
2062 return ERROR_INSUFFICIENT_BUFFER;
2063 }
2064 nbytes = 0;
2065 HTTP_GetRequestURL(req, url);
2066 ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
2067 error = GetLastError();
2068 if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
2069 {
Jacek Caban354a74e2011-04-21 13:39:03 +02002070 if (!(info = heap_alloc(nbytes)))
Hans Leidekkerc2932852009-06-16 15:13:52 +02002071 return ERROR_OUTOFMEMORY;
2072
2073 GetUrlCacheEntryInfoW(url, info, &nbytes);
2074
2075 ts->ftExpires = info->ExpireTime;
2076 ts->ftLastModified = info->LastModifiedTime;
2077
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002078 heap_free(info);
Hans Leidekkerc2932852009-06-16 15:13:52 +02002079 *size = sizeof(*ts);
2080 return ERROR_SUCCESS;
2081 }
2082 return error;
2083 }
2084
Jacek Cabance6a2282008-03-12 02:24:06 +01002085 case INTERNET_OPTION_DATAFILE_NAME: {
2086 DWORD req_size;
2087
2088 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
2089
Juan Lang20980062011-03-01 11:18:22 -08002090 if(!req->cacheFile) {
Jacek Cabance6a2282008-03-12 02:24:06 +01002091 *size = 0;
2092 return ERROR_INTERNET_ITEM_NOT_FOUND;
2093 }
2094
2095 if(unicode) {
Juan Lang20980062011-03-01 11:18:22 -08002096 req_size = (lstrlenW(req->cacheFile)+1) * sizeof(WCHAR);
Jacek Cabance6a2282008-03-12 02:24:06 +01002097 if(*size < req_size)
2098 return ERROR_INSUFFICIENT_BUFFER;
2099
2100 *size = req_size;
Juan Lang20980062011-03-01 11:18:22 -08002101 memcpy(buffer, req->cacheFile, *size);
Jacek Cabance6a2282008-03-12 02:24:06 +01002102 return ERROR_SUCCESS;
2103 }else {
Juan Lang20980062011-03-01 11:18:22 -08002104 req_size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile, -1, NULL, 0, NULL, NULL);
Jacek Cabance6a2282008-03-12 02:24:06 +01002105 if (req_size > *size)
2106 return ERROR_INSUFFICIENT_BUFFER;
2107
Juan Lang20980062011-03-01 11:18:22 -08002108 *size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile,
Jacek Cabance6a2282008-03-12 02:24:06 +01002109 -1, buffer, *size, NULL, NULL);
2110 return ERROR_SUCCESS;
2111 }
2112 }
Jacek Caban7e63f952008-03-12 02:24:23 +01002113
2114 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
2115 PCCERT_CONTEXT context;
2116
Juan Lang56ebc042010-09-30 13:09:04 -07002117 if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
2118 *size = sizeof(INTERNET_CERTIFICATE_INFOA);
Jacek Caban7e63f952008-03-12 02:24:23 +01002119 return ERROR_INSUFFICIENT_BUFFER;
2120 }
2121
Jacek Caban8a1df202011-05-10 09:26:43 +00002122 context = (PCCERT_CONTEXT)NETCON_GetCert(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002123 if(context) {
Juan Lang56ebc042010-09-30 13:09:04 -07002124 INTERNET_CERTIFICATE_INFOA *info = (INTERNET_CERTIFICATE_INFOA*)buffer;
Jacek Caban7e63f952008-03-12 02:24:23 +01002125 DWORD len;
2126
2127 memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
2128 info->ftExpiry = context->pCertInfo->NotAfter;
2129 info->ftStart = context->pCertInfo->NotBefore;
Juan Lang56ebc042010-09-30 13:09:04 -07002130 len = CertNameToStrA(context->dwCertEncodingType,
2131 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
2132 info->lpszSubjectInfo = LocalAlloc(0, len);
2133 if(info->lpszSubjectInfo)
2134 CertNameToStrA(context->dwCertEncodingType,
2135 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2136 info->lpszSubjectInfo, len);
2137 len = CertNameToStrA(context->dwCertEncodingType,
2138 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
2139 info->lpszIssuerInfo = LocalAlloc(0, len);
2140 if(info->lpszIssuerInfo)
2141 CertNameToStrA(context->dwCertEncodingType,
2142 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2143 info->lpszIssuerInfo, len);
Jacek Caban8a1df202011-05-10 09:26:43 +00002144 info->dwKeySize = NETCON_GetCipherStrength(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002145 CertFreeCertificateContext(context);
2146 return ERROR_SUCCESS;
2147 }
2148 }
Jacek Cabane2933c22008-03-12 02:23:20 +01002149 }
2150
Hans Leidekker80dd3672010-05-25 12:19:32 +02002151 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01002152}
2153
Jacek Caban44d633a2009-07-07 21:46:09 +02002154static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Jacek Caban0e33eee2008-02-26 20:22:02 +01002155{
Jacek Caban34abacd2009-07-13 01:41:50 +02002156 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002157
2158 switch(option) {
Juan Lang77c4ade2010-09-28 16:46:41 -07002159 case INTERNET_OPTION_SECURITY_FLAGS:
2160 {
2161 DWORD flags;
2162
2163 if (!buffer || size != sizeof(DWORD))
2164 return ERROR_INVALID_PARAMETER;
2165 flags = *(DWORD *)buffer;
2166 TRACE("%08x\n", flags);
Jacek Caban8a1df202011-05-10 09:26:43 +00002167 req->security_flags = flags;
2168 if(req->netconn)
2169 req->netconn->security_flags = flags;
Juan Lang77c4ade2010-09-28 16:46:41 -07002170 return ERROR_SUCCESS;
2171 }
Jacek Caban0e33eee2008-02-26 20:22:02 +01002172 case INTERNET_OPTION_SEND_TIMEOUT:
2173 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2174 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
2175
2176 if (size != sizeof(DWORD))
2177 return ERROR_INVALID_PARAMETER;
2178
Jacek Caban8a1df202011-05-10 09:26:43 +00002179 if(!req->netconn) {
Jacek Caban4c1c5fe2011-05-04 11:47:32 +00002180 FIXME("unsupported without active connection\n");
2181 return ERROR_SUCCESS;
2182 }
2183
Jacek Caban8a1df202011-05-10 09:26:43 +00002184 return NETCON_set_timeout(req->netconn, option == INTERNET_OPTION_SEND_TIMEOUT,
Jacek Caban0e33eee2008-02-26 20:22:02 +01002185 *(DWORD*)buffer);
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002186
2187 case INTERNET_OPTION_USERNAME:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002188 heap_free(req->session->userName);
Juan Lang20980062011-03-01 11:18:22 -08002189 if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002190 return ERROR_SUCCESS;
2191
2192 case INTERNET_OPTION_PASSWORD:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002193 heap_free(req->session->password);
Juan Lang20980062011-03-01 11:18:22 -08002194 if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002195 return ERROR_SUCCESS;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002196 case INTERNET_OPTION_HTTP_DECODING:
2197 if(size != sizeof(BOOL))
2198 return ERROR_INVALID_PARAMETER;
2199 req->decoding = *(BOOL*)buffer;
2200 return ERROR_SUCCESS;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002201 }
2202
2203 return ERROR_INTERNET_INVALID_OPTION;
2204}
2205
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002206/* read some more data into the read buffer (the read section must be held) */
Jacek Caban1d96e202009-11-30 19:59:56 +01002207static DWORD read_more_data( http_request_t *req, int maxlen )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002208{
Jacek Caban358e7b72009-11-30 19:59:40 +01002209 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002210 int len;
2211
Jacek Caban11ca05f2009-05-29 23:35:13 +02002212 if (req->read_pos)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002213 {
2214 /* move existing data to the start of the buffer */
Jacek Caban11ca05f2009-05-29 23:35:13 +02002215 if(req->read_size)
2216 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002217 req->read_pos = 0;
2218 }
2219
2220 if (maxlen == -1) maxlen = sizeof(req->read_buf);
Jacek Caban11ca05f2009-05-29 23:35:13 +02002221
Jacek Caban8a1df202011-05-10 09:26:43 +00002222 res = NETCON_recv( req->netconn, req->read_buf + req->read_size,
Jacek Caban358e7b72009-11-30 19:59:40 +01002223 maxlen - req->read_size, 0, &len );
Jacek Caban1d96e202009-11-30 19:59:56 +01002224 if(res == ERROR_SUCCESS)
2225 req->read_size += len;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002226
Jacek Caban1d96e202009-11-30 19:59:56 +01002227 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002228}
2229
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002230/* remove some amount of data from the read buffer (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002231static void remove_data( http_request_t *req, int count )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002232{
2233 if (!(req->read_size -= count)) req->read_pos = 0;
2234 else req->read_pos += count;
2235}
2236
Jacek Caban34abacd2009-07-13 01:41:50 +02002237static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002238{
2239 int count, bytes_read, pos = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002240 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002241
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002242 EnterCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002243 for (;;)
2244 {
Jacek Caban26bbf072009-05-29 23:34:37 +02002245 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002246
2247 if (eol)
2248 {
2249 count = eol - (req->read_buf + req->read_pos);
2250 bytes_read = count + 1;
2251 }
2252 else count = bytes_read = req->read_size;
2253
2254 count = min( count, *len - pos );
2255 memcpy( buffer + pos, req->read_buf + req->read_pos, count );
2256 pos += count;
2257 remove_data( req, bytes_read );
2258 if (eol) break;
2259
Jacek Caban1d96e202009-11-30 19:59:56 +01002260 if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002261 {
2262 *len = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00002263 TRACE( "returning empty string %u\n", res);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002264 LeaveCriticalSection( &req->read_section );
Jacek Caban1d96e202009-11-30 19:59:56 +01002265 INTERNET_SetLastError(res);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002266 return FALSE;
2267 }
2268 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002269 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002270
2271 if (pos < *len)
2272 {
2273 if (pos && buffer[pos - 1] == '\r') pos--;
2274 *len = pos + 1;
2275 }
2276 buffer[*len - 1] = 0;
2277 TRACE( "returning %s\n", debugstr_a(buffer));
2278 return TRUE;
2279}
2280
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002281/* check if we have reached the end of the data to read (the read section must be held) */
2282static BOOL end_of_read_data( http_request_t *req )
2283{
2284 return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req);
2285}
2286
2287/* fetch some more data into the read buffer (the read section must be held) */
Jacek Caban193da882011-05-23 16:10:09 +02002288static DWORD refill_read_buffer(http_request_t *req, read_mode_t read_mode, DWORD *read_bytes)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002289{
2290 DWORD res, read=0;
2291
2292 if(req->read_size == sizeof(req->read_buf))
2293 return ERROR_SUCCESS;
2294
2295 if(req->read_pos) {
2296 if(req->read_size)
2297 memmove(req->read_buf, req->read_buf+req->read_pos, req->read_size);
2298 req->read_pos = 0;
2299 }
2300
2301 res = req->data_stream->vtbl->read(req->data_stream, req, req->read_buf+req->read_size,
2302 sizeof(req->read_buf)-req->read_size, &read, read_mode);
2303 req->read_size += read;
2304
2305 TRACE("read %u bytes, read_size %u\n", read, req->read_size);
Jacek Caban193da882011-05-23 16:10:09 +02002306 if(read_bytes)
2307 *read_bytes = read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002308 return res;
2309}
2310
2311/* return the size of data available to be read immediately (the read section must be held) */
2312static DWORD get_avail_data( http_request_t *req )
2313{
2314 return req->read_size + req->data_stream->vtbl->get_avail_data(req->data_stream, req);
2315}
2316
2317static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req)
2318{
Jacek Caban8a1df202011-05-10 09:26:43 +00002319 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002320 DWORD avail = 0;
2321
Jacek Caban8a1df202011-05-10 09:26:43 +00002322 if(req->netconn)
2323 NETCON_query_data_available(req->netconn, &avail);
2324 return netconn_stream->content_length == ~0u
2325 ? avail
2326 : min(avail, netconn_stream->content_length-netconn_stream->content_read);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002327}
2328
2329static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req)
2330{
2331 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Caban8a1df202011-05-10 09:26:43 +00002332 return netconn_stream->content_read == netconn_stream->content_length || !req->netconn;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002333}
2334
2335static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2336 DWORD *read, read_mode_t read_mode)
2337{
2338 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002339 int len = 0;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002340
2341 size = min(size, netconn_stream->content_length-netconn_stream->content_read);
2342
2343 if(read_mode == READMODE_NOBLOCK)
2344 size = min(size, netconn_get_avail_data(stream, req));
2345
Jacek Caban8a1df202011-05-10 09:26:43 +00002346 if(size && req->netconn) {
2347 if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS)
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002348 len = 0;
Jacek Cabancfdc5392011-06-10 14:47:27 +02002349 if(!len)
2350 netconn_stream->content_length = netconn_stream->content_read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002351 }
2352
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002353 netconn_stream->content_read += *read = len;
2354 TRACE("read %u bytes\n", len);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002355 return ERROR_SUCCESS;
2356}
2357
Jacek Caban8a1df202011-05-10 09:26:43 +00002358static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req)
2359{
2360 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2361 BYTE buf[1024];
2362 DWORD avail;
2363 int len;
2364
2365 if(netconn_end_of_data(stream, req))
2366 return TRUE;
2367
2368 do {
2369 avail = netconn_get_avail_data(stream, req);
2370 if(!avail)
2371 return FALSE;
2372
2373 if(NETCON_recv(req->netconn, buf, min(avail, sizeof(buf)), 0, &len) != ERROR_SUCCESS)
2374 return FALSE;
2375
2376 netconn_stream->content_read += len;
2377 }while(netconn_stream->content_read < netconn_stream->content_length);
2378
2379 return TRUE;
2380}
2381
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002382static void netconn_destroy(data_stream_t *stream)
2383{
2384}
2385
2386static const data_stream_vtbl_t netconn_stream_vtbl = {
2387 netconn_get_avail_data,
2388 netconn_end_of_data,
2389 netconn_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002390 netconn_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002391 netconn_destroy
2392};
2393
2394/* read some more data into the read buffer (the read section must be held) */
2395static DWORD read_more_chunked_data(chunked_stream_t *stream, http_request_t *req, int maxlen)
2396{
2397 DWORD res;
2398 int len;
2399
2400 if (stream->buf_pos)
2401 {
2402 /* move existing data to the start of the buffer */
2403 if(stream->buf_size)
2404 memmove(stream->buf, stream->buf + stream->buf_pos, stream->buf_size);
2405 stream->buf_pos = 0;
2406 }
2407
2408 if (maxlen == -1) maxlen = sizeof(stream->buf);
2409
Jacek Caban8a1df202011-05-10 09:26:43 +00002410 res = NETCON_recv( req->netconn, stream->buf + stream->buf_size,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002411 maxlen - stream->buf_size, 0, &len );
2412 if(res == ERROR_SUCCESS)
2413 stream->buf_size += len;
2414
2415 return res;
2416}
2417
2418/* remove some amount of data from the read buffer (the read section must be held) */
2419static void remove_chunked_data(chunked_stream_t *stream, int count)
2420{
2421 if (!(stream->buf_size -= count)) stream->buf_pos = 0;
2422 else stream->buf_pos += count;
2423}
2424
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002425/* discard data contents until we reach end of line (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002426static DWORD discard_chunked_eol(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002427{
Jacek Caban1d96e202009-11-30 19:59:56 +01002428 DWORD res;
2429
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002430 do
2431 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002432 BYTE *eol = memchr(stream->buf + stream->buf_pos, '\n', stream->buf_size);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002433 if (eol)
2434 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002435 remove_chunked_data(stream, (eol + 1) - (stream->buf + stream->buf_pos));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002436 break;
2437 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002438 stream->buf_pos = stream->buf_size = 0; /* discard everything */
2439 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2440 } while (stream->buf_size);
Jacek Caban1d96e202009-11-30 19:59:56 +01002441 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002442}
2443
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002444/* read the size of the next chunk (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002445static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002446{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002447 /* TODOO */
Jacek Caban1d96e202009-11-30 19:59:56 +01002448 DWORD chunk_size = 0, res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002449
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002450 if(stream->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
2451 return res;
2452
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002453 for (;;)
2454 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002455 while (stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002456 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002457 char ch = stream->buf[stream->buf_pos];
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002458 if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
2459 else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
2460 else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
2461 else if (ch == ';' || ch == '\r' || ch == '\n')
2462 {
2463 TRACE( "reading %u byte chunk\n", chunk_size );
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002464 stream->chunk_size = chunk_size;
2465 req->contentLength += chunk_size;
2466 return discard_chunked_eol(stream, req);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002467 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002468 remove_chunked_data(stream, 1);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002469 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002470 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2471 if (!stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002472 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002473 stream->chunk_size = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002474 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002475 }
2476 }
2477}
2478
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002479static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002480{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002481 /* Allow reading only from read buffer */
2482 return 0;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002483}
2484
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002485static BOOL chunked_end_of_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002486{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002487 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2488 return !chunked_stream->chunk_size;
2489}
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002490
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002491static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2492 DWORD *read, read_mode_t read_mode)
2493{
2494 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2495 DWORD read_bytes = 0, ret_read = 0, res = ERROR_SUCCESS;
2496
2497 if(chunked_stream->chunk_size == ~0u) {
2498 res = start_next_chunk(chunked_stream, req);
2499 if(res != ERROR_SUCCESS)
2500 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002501 }
2502
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002503 while(size && chunked_stream->chunk_size) {
2504 if(chunked_stream->buf_size) {
2505 read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002506
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002507 /* this could block */
2508 if(read_mode == READMODE_NOBLOCK && read_bytes == chunked_stream->chunk_size)
2509 break;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002510
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002511 memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
2512 remove_chunked_data(chunked_stream, read_bytes);
2513 }else {
2514 read_bytes = min(size, chunked_stream->chunk_size);
Jacek Cabana76db212009-06-07 21:19:06 +02002515
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002516 if(read_mode == READMODE_NOBLOCK) {
2517 DWORD avail;
Jacek Cabana76db212009-06-07 21:19:06 +02002518
Jacek Caban8a1df202011-05-10 09:26:43 +00002519 if(!NETCON_query_data_available(req->netconn, &avail) || !avail)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002520 break;
2521 if(read_bytes > avail)
2522 read_bytes = avail;
2523
2524 /* this could block */
2525 if(read_bytes == chunked_stream->chunk_size)
2526 break;
2527 }
2528
Jacek Caban8a1df202011-05-10 09:26:43 +00002529 res = NETCON_recv(req->netconn, (char *)buf+ret_read, read_bytes, 0, (int*)&read_bytes);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002530 if(res != ERROR_SUCCESS)
Jacek Cabana76db212009-06-07 21:19:06 +02002531 break;
2532 }
2533
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002534 chunked_stream->chunk_size -= read_bytes;
2535 size -= read_bytes;
2536 ret_read += read_bytes;
2537 if(!chunked_stream->chunk_size) {
2538 assert(read_mode != READMODE_NOBLOCK);
2539 res = start_next_chunk(chunked_stream, req);
2540 if(res != ERROR_SUCCESS)
2541 break;
Jacek Cabana76db212009-06-07 21:19:06 +02002542 }
Jacek Cabana76db212009-06-07 21:19:06 +02002543
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002544 if(read_mode == READMODE_ASYNC)
2545 read_mode = READMODE_NOBLOCK;
Jacek Cabana76db212009-06-07 21:19:06 +02002546 }
2547
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002548 TRACE("read %u bytes\n", ret_read);
2549 *read = ret_read;
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002550 return res;
2551}
2552
Jacek Caban8a1df202011-05-10 09:26:43 +00002553static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req)
2554{
2555 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2556
2557 /* FIXME: we can do better */
2558 return !chunked_stream->chunk_size;
2559}
2560
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002561static void chunked_destroy(data_stream_t *stream)
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002562{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002563 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2564 heap_free(chunked_stream);
Jacek Cabana76db212009-06-07 21:19:06 +02002565}
2566
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002567static const data_stream_vtbl_t chunked_stream_vtbl = {
2568 chunked_get_avail_data,
2569 chunked_end_of_data,
2570 chunked_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002571 chunked_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002572 chunked_destroy
2573};
2574
2575/* set the request content length based on the headers */
Jacek Cabana890e3a2011-05-13 13:48:15 +02002576static DWORD set_content_length(http_request_t *request, DWORD status_code)
Jacek Cabana76db212009-06-07 21:19:06 +02002577{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002578 static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
2579 WCHAR encoding[20];
2580 DWORD size;
2581
Jacek Cabana890e3a2011-05-13 13:48:15 +02002582 if(status_code == HTTP_STATUS_NO_CONTENT) {
2583 request->contentLength = request->netconn_stream.content_length = 0;
2584 return ERROR_SUCCESS;
2585 }
2586
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002587 size = sizeof(request->contentLength);
2588 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
2589 &request->contentLength, &size, NULL) != ERROR_SUCCESS)
2590 request->contentLength = ~0u;
2591 request->netconn_stream.content_length = request->contentLength;
2592 request->netconn_stream.content_read = request->read_size;
2593
2594 size = sizeof(encoding);
2595 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS &&
2596 !strcmpiW(encoding, szChunked))
2597 {
2598 chunked_stream_t *chunked_stream;
2599
2600 chunked_stream = heap_alloc(sizeof(*chunked_stream));
2601 if(!chunked_stream)
2602 return ERROR_OUTOFMEMORY;
2603
2604 chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
2605 chunked_stream->buf_size = chunked_stream->buf_pos = 0;
2606 chunked_stream->chunk_size = ~0u;
2607
2608 if(request->read_size) {
2609 memcpy(chunked_stream->buf, request->read_buf+request->read_pos, request->read_size);
2610 chunked_stream->buf_size = request->read_size;
2611 request->read_size = request->read_pos = 0;
2612 }
2613
2614 request->data_stream = &chunked_stream->data_stream;
2615 request->contentLength = ~0u;
2616 request->read_chunked = TRUE;
2617 }
2618
2619 if(request->decoding) {
2620 int encoding_idx;
2621
2622 static const WCHAR gzipW[] = {'g','z','i','p',0};
2623
2624 encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE);
2625 if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW))
2626 return init_gzip_stream(request);
2627 }
2628
2629 return ERROR_SUCCESS;
Jacek Cabana76db212009-06-07 21:19:06 +02002630}
2631
Jacek Cabanc0293df2011-06-10 14:47:04 +02002632static void send_request_complete(http_request_t *req, DWORD_PTR result, DWORD error)
Jacek Caban12931062009-01-13 00:28:25 +01002633{
2634 INTERNET_ASYNC_RESULT iar;
Jacek Cabanc0293df2011-06-10 14:47:04 +02002635
2636 iar.dwResult = result;
2637 iar.dwError = error;
2638
2639 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2640 sizeof(INTERNET_ASYNC_RESULT));
2641}
2642
2643static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2644{
2645 DWORD res, read = 0, avail = 0;
Jacek Caban193da882011-05-23 16:10:09 +02002646 read_mode_t mode;
Jacek Caban12931062009-01-13 00:28:25 +01002647
2648 TRACE("%p\n", req);
2649
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002650 EnterCriticalSection( &req->read_section );
Jacek Caban193da882011-05-23 16:10:09 +02002651
2652 mode = first_notif && req->read_size ? READMODE_NOBLOCK : READMODE_ASYNC;
2653 res = refill_read_buffer(req, mode, &read);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002654 if(res == ERROR_SUCCESS && !first_notif)
2655 avail = get_avail_data(req);
Jacek Caban193da882011-05-23 16:10:09 +02002656
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002657 LeaveCriticalSection( &req->read_section );
Jacek Caban12931062009-01-13 00:28:25 +01002658
Jacek Caban193da882011-05-23 16:10:09 +02002659 if(res != ERROR_SUCCESS || (mode != READMODE_NOBLOCK && !read)) {
2660 WARN("res %u read %u, closing connection\n", res, read);
2661 http_release_netconn(req, FALSE);
2662 }
2663
Jacek Cabanc0293df2011-06-10 14:47:04 +02002664 if(res == ERROR_SUCCESS)
Jacek Caban8e37ed52011-06-10 14:47:16 +02002665 send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002666 else
2667 send_request_complete(req, 0, res);
Jacek Caban12931062009-01-13 00:28:25 +01002668}
2669
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002670/* read data from the http connection (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002671static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
Jacek Caban3b4ca692008-03-02 19:35:11 +01002672{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002673 DWORD current_read = 0, ret_read = 0;
2674 read_mode_t read_mode;
2675 DWORD res = ERROR_SUCCESS;
2676
2677 read_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? READMODE_ASYNC : READMODE_SYNC;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002678
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002679 EnterCriticalSection( &req->read_section );
Jacek Cabana76db212009-06-07 21:19:06 +02002680
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002681 if(req->read_size) {
2682 ret_read = min(size, req->read_size);
2683 memcpy(buffer, req->read_buf+req->read_pos, ret_read);
2684 req->read_size -= ret_read;
2685 req->read_pos += ret_read;
2686 if(read_mode == READMODE_ASYNC)
2687 read_mode = READMODE_NOBLOCK;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002688 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002689
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002690 if(ret_read < size) {
2691 res = req->data_stream->vtbl->read(req->data_stream, req, (BYTE*)buffer+ret_read, size-ret_read, &current_read, read_mode);
2692 ret_read += current_read;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002693 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002694
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002695 LeaveCriticalSection( &req->read_section );
2696
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002697 *read = ret_read;
2698 TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength );
Jacek Caban3b4ca692008-03-02 19:35:11 +01002699
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002700 if(req->hCacheFile && res == ERROR_SUCCESS && ret_read) {
2701 BOOL res;
2702 DWORD written;
2703
2704 res = WriteFile(req->hCacheFile, buffer, ret_read, &written, NULL);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002705 if(!res)
2706 WARN("WriteFile failed: %u\n", GetLastError());
2707 }
2708
Jacek Caban086eb612011-05-13 13:48:00 +02002709 if(size && !ret_read)
2710 http_release_netconn(req, res == ERROR_SUCCESS);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002711
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002712 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002713}
2714
Hans Leidekker058761f2008-03-26 22:22:04 +01002715
Jacek Caban44d633a2009-07-07 21:46:09 +02002716static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
Hans Leidekker058761f2008-03-26 22:22:04 +01002717{
Jacek Caban34abacd2009-07-13 01:41:50 +02002718 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002719 DWORD res;
2720
2721 EnterCriticalSection( &req->read_section );
2722 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2723 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2724
2725 res = HTTPREQ_Read(req, buffer, size, read, TRUE);
2726 if(res == ERROR_SUCCESS)
2727 res = hdr->dwError;
2728 LeaveCriticalSection( &req->read_section );
2729
2730 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002731}
2732
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002733static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
Jacek Caband597fd12008-03-03 18:07:20 +01002734{
2735 struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
Jacek Caban34abacd2009-07-13 01:41:50 +02002736 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caband597fd12008-03-03 18:07:20 +01002737 DWORD res;
2738
2739 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2740
2741 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2742 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2743
Jacek Cabanc0293df2011-06-10 14:47:04 +02002744 send_request_complete(req, res == ERROR_SUCCESS, res);
Jacek Caband597fd12008-03-03 18:07:20 +01002745}
2746
Jacek Caban44d633a2009-07-07 21:46:09 +02002747static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
Jacek Caband597fd12008-03-03 18:07:20 +01002748 DWORD flags, DWORD_PTR context)
2749{
Jacek Caban34abacd2009-07-13 01:41:50 +02002750 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002751 DWORD res, size, read, error = ERROR_SUCCESS;
Jacek Caband597fd12008-03-03 18:07:20 +01002752
2753 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2754 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2755
2756 if (buffers->dwStructSize != sizeof(*buffers))
2757 return ERROR_INVALID_PARAMETER;
2758
2759 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2760
Piotr Caban898531d2010-07-01 13:10:46 +02002761 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002762 {
2763 WORKREQUEST workRequest;
Jacek Caband597fd12008-03-03 18:07:20 +01002764
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002765 if (TryEnterCriticalSection( &req->read_section ))
2766 {
2767 if (get_avail_data(req))
2768 {
2769 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2770 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002771 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002772 LeaveCriticalSection( &req->read_section );
2773 goto done;
2774 }
2775 LeaveCriticalSection( &req->read_section );
2776 }
2777
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002778 workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2779 workRequest.hdr = WININET_AddRef(&req->hdr);
2780 workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
Jacek Caband597fd12008-03-03 18:07:20 +01002781
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002782 INTERNET_AsyncCall(&workRequest);
Jacek Caband597fd12008-03-03 18:07:20 +01002783
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002784 return ERROR_IO_PENDING;
Jacek Caband597fd12008-03-03 18:07:20 +01002785 }
2786
Piotr Caban21ced8d2010-07-20 00:33:24 +02002787 read = 0;
2788 size = buffers->dwBufferLength;
2789
2790 EnterCriticalSection( &req->read_section );
2791 if(hdr->dwError == ERROR_SUCCESS)
2792 hdr->dwError = INTERNET_HANDLE_IN_USE;
2793 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2794 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2795
2796 while(1) {
2797 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2798 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002799 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002800 break;
2801
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002802 read += buffers->dwBufferLength;
2803 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002804 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002805
Piotr Caban21ced8d2010-07-20 00:33:24 +02002806 LeaveCriticalSection( &req->read_section );
2807
2808 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2809 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2810 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2811 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2812
2813 EnterCriticalSection( &req->read_section );
2814 }
2815
2816 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2817 hdr->dwError = ERROR_SUCCESS;
2818 else
2819 error = hdr->dwError;
2820
2821 LeaveCriticalSection( &req->read_section );
2822 size = buffers->dwBufferLength;
2823 buffers->dwBufferLength = read;
Jacek Caband597fd12008-03-03 18:07:20 +01002824
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002825done:
Jacek Caband597fd12008-03-03 18:07:20 +01002826 if (res == ERROR_SUCCESS) {
Jacek Caband597fd12008-03-03 18:07:20 +01002827 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2828 &size, sizeof(size));
2829 }
2830
Piotr Caban21ced8d2010-07-20 00:33:24 +02002831 return res==ERROR_SUCCESS ? error : res;
Jacek Caband597fd12008-03-03 18:07:20 +01002832}
2833
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002834static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2835{
2836 struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
Jacek Caban34abacd2009-07-13 01:41:50 +02002837 http_request_t *req = (http_request_t*)workRequest->hdr;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002838 DWORD res;
2839
2840 TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2841
2842 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2843 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2844
Jacek Cabanc0293df2011-06-10 14:47:04 +02002845 send_request_complete(req, res == ERROR_SUCCESS, res);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002846}
2847
Jacek Caban44d633a2009-07-07 21:46:09 +02002848static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002849 DWORD flags, DWORD_PTR context)
2850{
2851
Jacek Caban34abacd2009-07-13 01:41:50 +02002852 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002853 DWORD res, size, read, error = ERROR_SUCCESS;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002854
2855 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2856 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2857
2858 if (buffers->dwStructSize != sizeof(*buffers))
2859 return ERROR_INVALID_PARAMETER;
2860
2861 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2862
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002863 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002864 {
2865 WORKREQUEST workRequest;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002866
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002867 if (TryEnterCriticalSection( &req->read_section ))
2868 {
2869 if (get_avail_data(req))
2870 {
2871 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2872 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002873 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002874 LeaveCriticalSection( &req->read_section );
2875 goto done;
2876 }
2877 LeaveCriticalSection( &req->read_section );
2878 }
2879
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002880 workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2881 workRequest.hdr = WININET_AddRef(&req->hdr);
2882 workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002883
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002884 INTERNET_AsyncCall(&workRequest);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002885
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002886 return ERROR_IO_PENDING;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002887 }
2888
Piotr Caban21ced8d2010-07-20 00:33:24 +02002889 read = 0;
2890 size = buffers->dwBufferLength;
2891
2892 EnterCriticalSection( &req->read_section );
2893 if(hdr->dwError == ERROR_SUCCESS)
2894 hdr->dwError = INTERNET_HANDLE_IN_USE;
2895 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2896 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2897
2898 while(1) {
2899 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2900 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002901 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002902 break;
2903
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002904 read += buffers->dwBufferLength;
2905 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002906 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002907
Piotr Caban21ced8d2010-07-20 00:33:24 +02002908 LeaveCriticalSection( &req->read_section );
2909
2910 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2911 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2912 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2913 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2914
2915 EnterCriticalSection( &req->read_section );
2916 }
2917
2918 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2919 hdr->dwError = ERROR_SUCCESS;
2920 else
2921 error = hdr->dwError;
2922
2923 LeaveCriticalSection( &req->read_section );
2924 size = buffers->dwBufferLength;
2925 buffers->dwBufferLength = read;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002926
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002927done:
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002928 if (res == ERROR_SUCCESS) {
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002929 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2930 &size, sizeof(size));
2931 }
2932
Piotr Caban21ced8d2010-07-20 00:33:24 +02002933 return res==ERROR_SUCCESS ? error : res;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002934}
2935
Jacek Caban1ee3ad42009-11-30 00:13:39 +01002936static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002937{
Jacek Cabanb77868c2009-11-30 00:13:21 +01002938 DWORD res;
Juan Langb49b2432011-03-01 10:59:39 -08002939 http_request_t *request = (http_request_t*)hdr;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002940
Juan Langb49b2432011-03-01 10:59:39 -08002941 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Hans Leidekker85eb4382009-04-08 15:22:05 +02002942
Hans Leidekker0fabf542009-04-08 15:21:28 +02002943 *written = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00002944 res = NETCON_send(request->netconn, buffer, size, 0, (LPINT)written);
Jacek Cabanb77868c2009-11-30 00:13:21 +01002945 if (res == ERROR_SUCCESS)
Juan Lang20980062011-03-01 11:18:22 -08002946 request->bytesWritten += *written;
Hans Leidekker0fabf542009-04-08 15:21:28 +02002947
Juan Langb49b2432011-03-01 10:59:39 -08002948 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
Jacek Caban1ee3ad42009-11-30 00:13:39 +01002949 return res;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002950}
2951
Jacek Caban33141842008-02-29 12:57:57 +01002952static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
2953{
Jacek Caban34abacd2009-07-13 01:41:50 +02002954 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caban33141842008-02-29 12:57:57 +01002955
Jacek Cabane13781a2009-01-22 13:48:23 +01002956 HTTP_ReceiveRequestData(req, FALSE);
Jacek Caban33141842008-02-29 12:57:57 +01002957}
2958
Jacek Caban44d633a2009-07-07 21:46:09 +02002959static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
Jacek Caban33141842008-02-29 12:57:57 +01002960{
Jacek Caban34abacd2009-07-13 01:41:50 +02002961 http_request_t *req = (http_request_t*)hdr;
Jacek Caban33141842008-02-29 12:57:57 +01002962
2963 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
2964
Juan Lang20980062011-03-01 11:18:22 -08002965 if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban33141842008-02-29 12:57:57 +01002966 {
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002967 WORKREQUEST workRequest;
Jacek Caban33141842008-02-29 12:57:57 +01002968
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002969 /* never wait, if we can't enter the section we queue an async request right away */
2970 if (TryEnterCriticalSection( &req->read_section ))
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002971 {
Jacek Caban193da882011-05-23 16:10:09 +02002972 refill_read_buffer(req, READMODE_NOBLOCK, NULL);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002973 if ((*available = get_avail_data( req ))) goto done;
2974 if (end_of_read_data( req )) goto done;
2975 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002976 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002977
2978 workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
2979 workRequest.hdr = WININET_AddRef( &req->hdr );
2980
2981 INTERNET_AsyncCall(&workRequest);
2982
2983 return ERROR_IO_PENDING;
Jacek Caban33141842008-02-29 12:57:57 +01002984 }
2985
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002986 EnterCriticalSection( &req->read_section );
2987
2988 if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
2989 {
Jacek Caban193da882011-05-23 16:10:09 +02002990 refill_read_buffer( req, READMODE_ASYNC, NULL );
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002991 *available = get_avail_data( req );
2992 }
2993
2994done:
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002995 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002996
2997 TRACE( "returning %u\n", *available );
Jacek Caban33141842008-02-29 12:57:57 +01002998 return ERROR_SUCCESS;
2999}
3000
Jacek Caban44d633a2009-07-07 21:46:09 +02003001static const object_vtbl_t HTTPREQVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01003002 HTTPREQ_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003003 HTTPREQ_CloseConnection,
Jacek Cabane2933c22008-03-12 02:23:20 +01003004 HTTPREQ_QueryOption,
Jacek Caban0e33eee2008-02-26 20:22:02 +01003005 HTTPREQ_SetOption,
Jacek Caban3b4ca692008-03-02 19:35:11 +01003006 HTTPREQ_ReadFile,
Jacek Caband597fd12008-03-03 18:07:20 +01003007 HTTPREQ_ReadFileExA,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01003008 HTTPREQ_ReadFileExW,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003009 HTTPREQ_WriteFile,
Jacek Caban33141842008-02-29 12:57:57 +01003010 HTTPREQ_QueryDataAvailable,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003011 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01003012};
3013
Mike McCormacka1c16d22003-07-22 03:17:52 +00003014/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003015 * HTTP_HttpOpenRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003016 *
3017 * Open a HTTP request handle
3018 *
3019 * RETURNS
3020 * HINTERNET a HTTP request handle on success
3021 * NULL on failure
3022 *
3023 */
Juan Langb49b2432011-03-01 10:59:39 -08003024static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
Jacek Caban85a057e2009-11-30 20:00:44 +01003025 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3026 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3027 DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003028{
Jacek Caban8a1df202011-05-10 09:26:43 +00003029 appinfo_t *hIC = session->appInfo;
Juan Langb49b2432011-03-01 10:59:39 -08003030 http_request_t *request;
Jacek Caban8a1df202011-05-10 09:26:43 +00003031 DWORD len, res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003032
Francois Gouget0edbaf72005-11-10 12:14:56 +00003033 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00003034
Juan Langb49b2432011-03-01 10:59:39 -08003035 request = alloc_object(&session->hdr, &HTTPREQVtbl, sizeof(http_request_t));
3036 if(!request)
Jacek Cabana073c662011-02-02 22:51:13 +01003037 return ERROR_OUTOFMEMORY;
3038
Juan Langb49b2432011-03-01 10:59:39 -08003039 request->hdr.htype = WH_HHTTPREQ;
3040 request->hdr.dwFlags = dwFlags;
3041 request->hdr.dwContext = dwContext;
Juan Lang20980062011-03-01 11:18:22 -08003042 request->contentLength = ~0u;
Jacek Cabana073c662011-02-02 22:51:13 +01003043
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003044 request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl;
3045 request->data_stream = &request->netconn_stream.data_stream;
3046
Juan Langb49b2432011-03-01 10:59:39 -08003047 InitializeCriticalSection( &request->read_section );
Mike McCormack3a1391b2004-07-19 21:49:39 +00003048
Juan Langb49b2432011-03-01 10:59:39 -08003049 WININET_AddRef( &session->hdr );
Juan Lang20980062011-03-01 11:18:22 -08003050 request->session = session;
Juan Langb49b2432011-03-01 10:59:39 -08003051 list_add_head( &session->hdr.children, &request->hdr.entry );
Jacek Cabana9bdc012006-10-29 18:50:25 +01003052
Juan Lang0b8bfd92011-04-07 08:05:36 -07003053 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_CN_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003054 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
Juan Lang0b8bfd92011-04-07 08:05:36 -07003055 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_DATE_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003056 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003057
Jacek Cabanf9791342008-02-13 13:34:05 +01003058 if (lpszObjectName && *lpszObjectName) {
Aric Stewartff9b9d42002-06-21 23:59:49 +00003059 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003060
3061 len = 0;
3062 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003063 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003064 len = strlenW(lpszObjectName)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003065 request->path = heap_alloc(len*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003066 rc = UrlEscapeW(lpszObjectName, request->path, &len,
Huw D M Davies0aebee92001-01-21 21:09:00 +00003067 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003068 if (rc != S_OK)
Aric Stewartff9b9d42002-06-21 23:59:49 +00003069 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003070 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
Juan Lang20980062011-03-01 11:18:22 -08003071 strcpyW(request->path,lpszObjectName);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003072 }
Jacek Caband1d1da32009-05-29 23:34:25 +02003073 }else {
3074 static const WCHAR slashW[] = {'/',0};
3075
Juan Lang20980062011-03-01 11:18:22 -08003076 request->path = heap_strdupW(slashW);
Huw D M Davies0aebee92001-01-21 21:09:00 +00003077 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003078
Jacek Cabanf9791342008-02-13 13:34:05 +01003079 if (lpszReferrer && *lpszReferrer)
Juan Langb49b2432011-03-01 10:59:39 -08003080 HTTP_ProcessHeader(request, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003081
Hans Leidekker2024f682007-02-12 15:19:17 +01003082 if (lpszAcceptTypes)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003083 {
3084 int i;
Hans Leidekker2024f682007-02-12 15:19:17 +01003085 for (i = 0; lpszAcceptTypes[i]; i++)
3086 {
3087 if (!*lpszAcceptTypes[i]) continue;
Juan Langb49b2432011-03-01 10:59:39 -08003088 HTTP_ProcessHeader(request, HTTP_ACCEPT, lpszAcceptTypes[i],
Hans Leidekker2024f682007-02-12 15:19:17 +01003089 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
3090 HTTP_ADDHDR_FLAG_REQ |
3091 (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
3092 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003093 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003094
Juan Lang20980062011-03-01 11:18:22 -08003095 request->verb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
3096 request->version = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
Hans Leidekkerd0033db2008-02-17 20:41:42 +01003097
Juan Lang8e050392011-03-01 11:02:14 -08003098 if (session->hostPort != INTERNET_INVALID_PORT_NUMBER &&
3099 session->hostPort != INTERNET_DEFAULT_HTTP_PORT &&
3100 session->hostPort != INTERNET_DEFAULT_HTTPS_PORT)
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003101 {
Jacek Caban59f2e832011-05-02 11:26:10 +02003102 WCHAR *host_name;
3103
3104 static const WCHAR host_formatW[] = {'%','s',':','%','u',0};
3105
3106 host_name = heap_alloc((strlenW(session->hostName) + 7 /* length of ":65535" + 1 */) * sizeof(WCHAR));
3107 if (!host_name) {
3108 res = ERROR_OUTOFMEMORY;
3109 goto lend;
3110 }
3111
3112 sprintfW(host_name, host_formatW, session->hostName, session->hostPort);
3113 HTTP_ProcessHeader(request, hostW, host_name, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
3114 heap_free(host_name);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003115 }
3116 else
Juan Lang8e050392011-03-01 11:02:14 -08003117 HTTP_ProcessHeader(request, hostW, session->hostName,
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003118 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Robert Shearman37f2cc82004-09-13 19:33:17 +00003119
Juan Lang8e050392011-03-01 11:02:14 -08003120 if (session->serverPort == INTERNET_INVALID_PORT_NUMBER)
3121 session->serverPort = (dwFlags & INTERNET_FLAG_SECURE ?
Mike McCormack403e58f2005-10-19 19:07:08 +00003122 INTERNET_DEFAULT_HTTPS_PORT :
3123 INTERNET_DEFAULT_HTTP_PORT);
Hans Leidekkere4c59c22008-03-30 19:17:31 +01003124
Juan Lang8e050392011-03-01 11:02:14 -08003125 if (session->hostPort == INTERNET_INVALID_PORT_NUMBER)
3126 session->hostPort = (dwFlags & INTERNET_FLAG_SECURE ?
Hans Leidekkere4c59c22008-03-30 19:17:31 +01003127 INTERNET_DEFAULT_HTTPS_PORT :
3128 INTERNET_DEFAULT_HTTP_PORT);
Mike McCormack403e58f2005-10-19 19:07:08 +00003129
Jacek Caban8a1df202011-05-10 09:26:43 +00003130 if (hIC->proxy && hIC->proxy[0])
Juan Langb49b2432011-03-01 10:59:39 -08003131 HTTP_DealWithProxy( hIC, session, request );
Ulrich Czekallac2757242000-06-11 20:04:44 +00003132
Juan Langb49b2432011-03-01 10:59:39 -08003133 INTERNET_SendCallback(&session->hdr, dwContext,
3134 INTERNET_STATUS_HANDLE_CREATED, &request->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01003135 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00003136
Mike McCormack3a1391b2004-07-19 21:49:39 +00003137lend:
Juan Langb49b2432011-03-01 10:59:39 -08003138 TRACE("<-- %u (%p)\n", res, request);
Mike McCormack3a1391b2004-07-19 21:49:39 +00003139
Jacek Cabana073c662011-02-02 22:51:13 +01003140 if(res != ERROR_SUCCESS) {
Juan Langb49b2432011-03-01 10:59:39 -08003141 WININET_Release( &request->hdr );
Jacek Cabana073c662011-02-02 22:51:13 +01003142 *ret = NULL;
3143 return res;
3144 }
3145
Juan Langb49b2432011-03-01 10:59:39 -08003146 *ret = request->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01003147 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003148}
3149
Jacek Caban47c71fc2009-11-30 20:00:28 +01003150/***********************************************************************
3151 * HttpOpenRequestW (WININET.@)
3152 *
3153 * Open a HTTP request handle
3154 *
3155 * RETURNS
3156 * HINTERNET a HTTP request handle on success
3157 * NULL on failure
3158 *
3159 */
3160HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
3161 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3162 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3163 DWORD dwFlags, DWORD_PTR dwContext)
3164{
Juan Langb49b2432011-03-01 10:59:39 -08003165 http_session_t *session;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003166 HINTERNET handle = NULL;
Jacek Caban85a057e2009-11-30 20:00:44 +01003167 DWORD res;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003168
3169 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
3170 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
3171 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
3172 dwFlags, dwContext);
3173 if(lpszAcceptTypes!=NULL)
3174 {
3175 int i;
3176 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
3177 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
3178 }
3179
Juan Langb49b2432011-03-01 10:59:39 -08003180 session = (http_session_t*) get_handle_object( hHttpSession );
3181 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban47c71fc2009-11-30 20:00:28 +01003182 {
Jacek Caban85a057e2009-11-30 20:00:44 +01003183 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3184 goto lend;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003185 }
3186
3187 /*
3188 * My tests seem to show that the windows version does not
3189 * become asynchronous until after this point. And anyhow
3190 * if this call was asynchronous then how would you get the
3191 * necessary HINTERNET pointer returned by this function.
3192 *
3193 */
Juan Langb49b2432011-03-01 10:59:39 -08003194 res = HTTP_HttpOpenRequestW(session, lpszVerb, lpszObjectName,
Jacek Caban85a057e2009-11-30 20:00:44 +01003195 lpszVersion, lpszReferrer, lpszAcceptTypes,
3196 dwFlags, dwContext, &handle);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003197lend:
Juan Langb49b2432011-03-01 10:59:39 -08003198 if( session )
3199 WININET_Release( &session->hdr );
Jacek Caban47c71fc2009-11-30 20:00:28 +01003200 TRACE("returning %p\n", handle);
Jacek Caban85a057e2009-11-30 20:00:44 +01003201 if(res != ERROR_SUCCESS)
3202 SetLastError(res);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003203 return handle;
3204}
3205
Mike McCormack7f5e2732006-03-30 18:02:54 +09003206static const LPCWSTR header_lookup[] = {
3207 szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
3208 szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
3209 szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
3210 szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
3211 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
3212 szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
3213 szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
3214 szAllow, /* HTTP_QUERY_ALLOW = 7 */
3215 szPublic, /* HTTP_QUERY_PUBLIC = 8 */
3216 szDate, /* HTTP_QUERY_DATE = 9 */
3217 szExpires, /* HTTP_QUERY_EXPIRES = 10 */
3218 szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
3219 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
3220 szURI, /* HTTP_QUERY_URI = 13 */
3221 szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
3222 NULL, /* HTTP_QUERY_COST = 15 */
3223 NULL, /* HTTP_QUERY_LINK = 16 */
3224 szPragma, /* HTTP_QUERY_PRAGMA = 17 */
3225 NULL, /* HTTP_QUERY_VERSION = 18 */
3226 szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
3227 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
3228 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
3229 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
3230 szConnection, /* HTTP_QUERY_CONNECTION = 23 */
3231 szAccept, /* HTTP_QUERY_ACCEPT = 24 */
3232 szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
3233 szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
3234 szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
3235 szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
3236 szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
3237 NULL, /* HTTP_QUERY_FORWARDED = 30 */
3238 NULL, /* HTTP_QUERY_FROM = 31 */
3239 szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
3240 szLocation, /* HTTP_QUERY_LOCATION = 33 */
3241 NULL, /* HTTP_QUERY_ORIG_URI = 34 */
3242 szReferer, /* HTTP_QUERY_REFERER = 35 */
3243 szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
3244 szServer, /* HTTP_QUERY_SERVER = 37 */
3245 NULL, /* HTTP_TITLE = 38 */
3246 szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
3247 szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
3248 szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
3249 szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
3250 szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
3251 szCookie, /* HTTP_QUERY_COOKIE = 44 */
3252 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
3253 NULL, /* HTTP_QUERY_REFRESH = 46 */
3254 NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
3255 szAge, /* HTTP_QUERY_AGE = 48 */
3256 szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
3257 szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
3258 szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
3259 szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
3260 szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
3261 szETag, /* HTTP_QUERY_ETAG = 54 */
Jacek Caban83170892009-05-29 23:34:14 +02003262 hostW, /* HTTP_QUERY_HOST = 55 */
Mike McCormack7f5e2732006-03-30 18:02:54 +09003263 szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
3264 szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
3265 szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
3266 szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
3267 szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
3268 szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
3269 szRange, /* HTTP_QUERY_RANGE = 62 */
3270 szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
3271 szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
3272 szVary, /* HTTP_QUERY_VARY = 65 */
3273 szVia, /* HTTP_QUERY_VIA = 66 */
3274 szWarning, /* HTTP_QUERY_WARNING = 67 */
3275 szExpect, /* HTTP_QUERY_EXPECT = 68 */
3276 szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
3277 szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
Aric Stewart1e946d32005-12-13 17:07:41 +01003278};
3279
Mike McCormack7f5e2732006-03-30 18:02:54 +09003280#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
3281
Alexandre Julliard48243e32004-07-15 18:57:32 +00003282/***********************************************************************
Mike McCormackb288f712004-06-14 17:57:26 +00003283 * HTTP_HttpQueryInfoW (internal)
3284 */
Juan Langb49b2432011-03-01 10:59:39 -08003285static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003286 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Mike McCormackb288f712004-06-14 17:57:26 +00003287{
3288 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01003289 BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
Mike McCormackae300882006-03-30 18:01:48 +09003290 INT requested_index = lpdwIndex ? *lpdwIndex : 0;
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003291 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
Mike McCormackae300882006-03-30 18:01:48 +09003292 INT index = -1;
Mike McCormackb288f712004-06-14 17:57:26 +00003293
3294 /* Find requested header structure */
Mike McCormackae300882006-03-30 18:01:48 +09003295 switch (level)
Mike McCormackb288f712004-06-14 17:57:26 +00003296 {
Mike McCormackae300882006-03-30 18:01:48 +09003297 case HTTP_QUERY_CUSTOM:
Jacek Caban9823c232009-12-14 02:27:29 +01003298 if (!lpBuffer) return ERROR_INVALID_PARAMETER;
Juan Langb49b2432011-03-01 10:59:39 -08003299 index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only);
Mike McCormackae300882006-03-30 18:01:48 +09003300 break;
Mike McCormackae300882006-03-30 18:01:48 +09003301 case HTTP_QUERY_RAW_HEADERS_CRLF:
Robert Shearmandee87512004-07-19 20:09:20 +00003302 {
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003303 LPWSTR headers;
Lei Zhangbc9e2142008-08-27 16:54:17 -07003304 DWORD len = 0;
Jacek Caban9823c232009-12-14 02:27:29 +01003305 DWORD res = ERROR_INVALID_PARAMETER;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003306
3307 if (request_only)
Juan Lang20980062011-03-01 11:18:22 -08003308 headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003309 else
Juan Lang20980062011-03-01 11:18:22 -08003310 headers = request->rawHeaders;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003311
Lei Zhangbc9e2142008-08-27 16:54:17 -07003312 if (headers)
3313 len = strlenW(headers) * sizeof(WCHAR);
3314
Dan Kegel1e7f8912008-07-30 06:49:04 -07003315 if (len + sizeof(WCHAR) > *lpdwBufferLength)
Robert Shearmandee87512004-07-19 20:09:20 +00003316 {
Dan Kegel1e7f8912008-07-30 06:49:04 -07003317 len += sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003318 res = ERROR_INSUFFICIENT_BUFFER;
Hans Leidekker694a0922008-05-18 21:09:50 +02003319 }
3320 else if (lpBuffer)
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003321 {
Lei Zhangbc9e2142008-08-27 16:54:17 -07003322 if (headers)
3323 memcpy(lpBuffer, headers, len + sizeof(WCHAR));
3324 else
3325 {
Lei Zhangf7e56d12008-08-27 17:03:13 -07003326 len = strlenW(szCrLf) * sizeof(WCHAR);
3327 memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
Lei Zhangbc9e2142008-08-27 16:54:17 -07003328 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003329 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
Jacek Caban9823c232009-12-14 02:27:29 +01003330 res = ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003331 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003332 *lpdwBufferLength = len;
Robert Shearman4385d302004-07-21 21:17:03 +00003333
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003334 if (request_only) heap_free(headers);
Jacek Caban9823c232009-12-14 02:27:29 +01003335 return res;
Robert Shearmandee87512004-07-19 20:09:20 +00003336 }
Mike McCormackae300882006-03-30 18:01:48 +09003337 case HTTP_QUERY_RAW_HEADERS:
Robert Shearmandee87512004-07-19 20:09:20 +00003338 {
Juan Lang20980062011-03-01 11:18:22 -08003339 LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf);
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003340 DWORD i, size = 0;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003341 LPWSTR pszString = lpBuffer;
Robert Shearmandee87512004-07-19 20:09:20 +00003342
3343 for (i = 0; ppszRawHeaderLines[i]; i++)
3344 size += strlenW(ppszRawHeaderLines[i]) + 1;
3345
3346 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
3347 {
3348 HTTP_FreeTokens(ppszRawHeaderLines);
3349 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003350 return ERROR_INSUFFICIENT_BUFFER;
Robert Shearmandee87512004-07-19 20:09:20 +00003351 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003352 if (pszString)
Robert Shearmandee87512004-07-19 20:09:20 +00003353 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003354 for (i = 0; ppszRawHeaderLines[i]; i++)
3355 {
3356 DWORD len = strlenW(ppszRawHeaderLines[i]);
3357 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
3358 pszString += len+1;
3359 }
3360 *pszString = '\0';
3361 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
Robert Shearmandee87512004-07-19 20:09:20 +00003362 }
Robert Shearman4385d302004-07-21 21:17:03 +00003363 *lpdwBufferLength = size * sizeof(WCHAR);
Robert Shearmandee87512004-07-19 20:09:20 +00003364 HTTP_FreeTokens(ppszRawHeaderLines);
3365
Jacek Caban9823c232009-12-14 02:27:29 +01003366 return ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003367 }
Mike McCormackae300882006-03-30 18:01:48 +09003368 case HTTP_QUERY_STATUS_TEXT:
Juan Lang20980062011-03-01 11:18:22 -08003369 if (request->statusText)
Aric Stewart1e946d32005-12-13 17:07:41 +01003370 {
Juan Lang20980062011-03-01 11:18:22 -08003371 DWORD len = strlenW(request->statusText);
Aric Stewart1e946d32005-12-13 17:07:41 +01003372 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3373 {
3374 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003375 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003376 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003377 if (lpBuffer)
3378 {
Juan Lang20980062011-03-01 11:18:22 -08003379 memcpy(lpBuffer, request->statusText, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003380 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3381 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003382 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003383 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003384 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003385 break;
Mike McCormackae300882006-03-30 18:01:48 +09003386 case HTTP_QUERY_VERSION:
Juan Lang20980062011-03-01 11:18:22 -08003387 if (request->version)
Aric Stewart1e946d32005-12-13 17:07:41 +01003388 {
Juan Lang20980062011-03-01 11:18:22 -08003389 DWORD len = strlenW(request->version);
Aric Stewart1e946d32005-12-13 17:07:41 +01003390 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3391 {
3392 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003393 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003394 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003395 if (lpBuffer)
3396 {
Juan Lang20980062011-03-01 11:18:22 -08003397 memcpy(lpBuffer, request->version, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003398 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3399 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003400 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003401 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003402 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003403 break;
Jacek Caban11ca05f2009-05-29 23:35:13 +02003404 case HTTP_QUERY_CONTENT_ENCODING:
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003405 index = HTTP_GetCustomHeaderIndex(request, header_lookup[request->read_gzip ? HTTP_QUERY_CONTENT_TYPE : level],
Jacek Caban11ca05f2009-05-29 23:35:13 +02003406 requested_index,request_only);
3407 break;
Mike McCormackae300882006-03-30 18:01:48 +09003408 default:
Mike McCormack7f5e2732006-03-30 18:02:54 +09003409 assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
3410
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003411 if (level < LAST_TABLE_HEADER && header_lookup[level])
Juan Langb49b2432011-03-01 10:59:39 -08003412 index = HTTP_GetCustomHeaderIndex(request, header_lookup[level],
Mike McCormack7f5e2732006-03-30 18:02:54 +09003413 requested_index,request_only);
Mike McCormackb288f712004-06-14 17:57:26 +00003414 }
3415
Mike McCormackae300882006-03-30 18:01:48 +09003416 if (index >= 0)
Juan Lang20980062011-03-01 11:18:22 -08003417 lphttpHdr = &request->custHeaders[index];
Mike McCormackae300882006-03-30 18:01:48 +09003418
Austin English0e4adae2008-01-04 13:37:14 -06003419 /* Ensure header satisfies requested attributes */
Mike McCormackae300882006-03-30 18:01:48 +09003420 if (!lphttpHdr ||
3421 ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
3422 (~lphttpHdr->wFlags & HDR_ISREQUEST)))
Alexandre Julliard48243e32004-07-15 18:57:32 +00003423 {
Jacek Caban9823c232009-12-14 02:27:29 +01003424 return ERROR_HTTP_HEADER_NOT_FOUND;
Alexandre Julliard48243e32004-07-15 18:57:32 +00003425 }
Mike McCormackb288f712004-06-14 17:57:26 +00003426
Hans Leidekkerd1076ae2008-12-01 15:35:05 +01003427 if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
Mike McCormackae300882006-03-30 18:01:48 +09003428
Austin English0e4adae2008-01-04 13:37:14 -06003429 /* coalesce value to requested type */
Hans Leidekker128b8a52008-10-06 15:48:28 +02003430 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003431 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003432 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
3433 TRACE(" returning number: %d\n", *(int *)lpBuffer);
Jacek Caban9823c232009-12-14 02:27:29 +01003434 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003435 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003436 {
3437 time_t tmpTime;
3438 struct tm tmpTM;
3439 SYSTEMTIME *STHook;
3440
3441 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
3442
3443 tmpTM = *gmtime(&tmpTime);
Hans Leidekker128b8a52008-10-06 15:48:28 +02003444 STHook = (SYSTEMTIME *)lpBuffer;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003445 STHook->wDay = tmpTM.tm_mday;
3446 STHook->wHour = tmpTM.tm_hour;
3447 STHook->wMilliseconds = 0;
3448 STHook->wMinute = tmpTM.tm_min;
3449 STHook->wDayOfWeek = tmpTM.tm_wday;
3450 STHook->wMonth = tmpTM.tm_mon + 1;
3451 STHook->wSecond = tmpTM.tm_sec;
3452 STHook->wYear = tmpTM.tm_year;
Jacek Caban9823c232009-12-14 02:27:29 +01003453
Hans Leidekker128b8a52008-10-06 15:48:28 +02003454 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
3455 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
3456 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
Mike McCormackb288f712004-06-14 17:57:26 +00003457 }
Aric Stewart7bca41a2005-12-08 12:44:45 +01003458 else if (lphttpHdr->lpszValue)
Mike McCormackb288f712004-06-14 17:57:26 +00003459 {
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003460 DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003461
3462 if (len > *lpdwBufferLength)
3463 {
3464 *lpdwBufferLength = len;
Jacek Caban9823c232009-12-14 02:27:29 +01003465 return ERROR_INSUFFICIENT_BUFFER;
Mike McCormackb288f712004-06-14 17:57:26 +00003466 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003467 if (lpBuffer)
3468 {
3469 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
Jacek Caban9823c232009-12-14 02:27:29 +01003470 TRACE("! returning string: %s\n", debugstr_w(lpBuffer));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003471 }
Mike McCormackb288f712004-06-14 17:57:26 +00003472 *lpdwBufferLength = len - sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003473 }
Jacek Caban9823c232009-12-14 02:27:29 +01003474 return ERROR_SUCCESS;
Mike McCormackb288f712004-06-14 17:57:26 +00003475}
3476
3477/***********************************************************************
Mike McCormack1baf39f2004-03-30 20:37:49 +00003478 * HttpQueryInfoW (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003479 *
3480 * Queries for information about an HTTP request
3481 *
3482 * RETURNS
3483 * TRUE on success
3484 * FALSE on failure
3485 *
3486 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003487BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003488 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003489{
Juan Langb49b2432011-03-01 10:59:39 -08003490 http_request_t *request;
Jacek Caban9823c232009-12-14 02:27:29 +01003491 DWORD res;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003492
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003493 if (TRACE_ON(wininet)) {
3494#define FE(x) { x, #x }
3495 static const wininet_flag_info query_flags[] = {
3496 FE(HTTP_QUERY_MIME_VERSION),
3497 FE(HTTP_QUERY_CONTENT_TYPE),
3498 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
3499 FE(HTTP_QUERY_CONTENT_ID),
3500 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
3501 FE(HTTP_QUERY_CONTENT_LENGTH),
3502 FE(HTTP_QUERY_CONTENT_LANGUAGE),
3503 FE(HTTP_QUERY_ALLOW),
3504 FE(HTTP_QUERY_PUBLIC),
3505 FE(HTTP_QUERY_DATE),
3506 FE(HTTP_QUERY_EXPIRES),
3507 FE(HTTP_QUERY_LAST_MODIFIED),
3508 FE(HTTP_QUERY_MESSAGE_ID),
3509 FE(HTTP_QUERY_URI),
3510 FE(HTTP_QUERY_DERIVED_FROM),
3511 FE(HTTP_QUERY_COST),
3512 FE(HTTP_QUERY_LINK),
3513 FE(HTTP_QUERY_PRAGMA),
3514 FE(HTTP_QUERY_VERSION),
3515 FE(HTTP_QUERY_STATUS_CODE),
3516 FE(HTTP_QUERY_STATUS_TEXT),
3517 FE(HTTP_QUERY_RAW_HEADERS),
3518 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
3519 FE(HTTP_QUERY_CONNECTION),
3520 FE(HTTP_QUERY_ACCEPT),
3521 FE(HTTP_QUERY_ACCEPT_CHARSET),
3522 FE(HTTP_QUERY_ACCEPT_ENCODING),
3523 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
3524 FE(HTTP_QUERY_AUTHORIZATION),
3525 FE(HTTP_QUERY_CONTENT_ENCODING),
3526 FE(HTTP_QUERY_FORWARDED),
3527 FE(HTTP_QUERY_FROM),
3528 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
3529 FE(HTTP_QUERY_LOCATION),
3530 FE(HTTP_QUERY_ORIG_URI),
3531 FE(HTTP_QUERY_REFERER),
3532 FE(HTTP_QUERY_RETRY_AFTER),
3533 FE(HTTP_QUERY_SERVER),
3534 FE(HTTP_QUERY_TITLE),
3535 FE(HTTP_QUERY_USER_AGENT),
3536 FE(HTTP_QUERY_WWW_AUTHENTICATE),
3537 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
3538 FE(HTTP_QUERY_ACCEPT_RANGES),
Aric Stewart1e946d32005-12-13 17:07:41 +01003539 FE(HTTP_QUERY_SET_COOKIE),
3540 FE(HTTP_QUERY_COOKIE),
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003541 FE(HTTP_QUERY_REQUEST_METHOD),
3542 FE(HTTP_QUERY_REFRESH),
3543 FE(HTTP_QUERY_CONTENT_DISPOSITION),
3544 FE(HTTP_QUERY_AGE),
3545 FE(HTTP_QUERY_CACHE_CONTROL),
3546 FE(HTTP_QUERY_CONTENT_BASE),
3547 FE(HTTP_QUERY_CONTENT_LOCATION),
3548 FE(HTTP_QUERY_CONTENT_MD5),
3549 FE(HTTP_QUERY_CONTENT_RANGE),
3550 FE(HTTP_QUERY_ETAG),
3551 FE(HTTP_QUERY_HOST),
3552 FE(HTTP_QUERY_IF_MATCH),
3553 FE(HTTP_QUERY_IF_NONE_MATCH),
3554 FE(HTTP_QUERY_IF_RANGE),
3555 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
3556 FE(HTTP_QUERY_MAX_FORWARDS),
3557 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
3558 FE(HTTP_QUERY_RANGE),
3559 FE(HTTP_QUERY_TRANSFER_ENCODING),
3560 FE(HTTP_QUERY_UPGRADE),
3561 FE(HTTP_QUERY_VARY),
3562 FE(HTTP_QUERY_VIA),
3563 FE(HTTP_QUERY_WARNING),
3564 FE(HTTP_QUERY_CUSTOM)
3565 };
3566 static const wininet_flag_info modifier_flags[] = {
3567 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
3568 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
3569 FE(HTTP_QUERY_FLAG_NUMBER),
3570 FE(HTTP_QUERY_FLAG_COALESCE)
3571 };
3572#undef FE
3573 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
3574 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003575 DWORD i;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003576
Juan Lang66b4ad22009-12-04 14:39:37 -08003577 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003578 TRACE(" Attribute:");
3579 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
3580 if (query_flags[i].val == info) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003581 TRACE(" %s", query_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003582 break;
3583 }
3584 }
3585 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003586 TRACE(" Unknown (%08x)", info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003587 }
3588
Diego Pettenò869a66a2005-01-07 17:09:39 +00003589 TRACE(" Modifier:");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003590 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
3591 if (modifier_flags[i].val & info_mod) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003592 TRACE(" %s", modifier_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003593 info_mod &= ~ modifier_flags[i].val;
3594 }
3595 }
3596
3597 if (info_mod) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003598 TRACE(" Unknown (%08x)", info_mod);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003599 }
Diego Pettenò869a66a2005-01-07 17:09:39 +00003600 TRACE("\n");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003601 }
3602
Juan Langb49b2432011-03-01 10:59:39 -08003603 request = (http_request_t*) get_handle_object( hHttpRequest );
3604 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003605 {
Jacek Caban9823c232009-12-14 02:27:29 +01003606 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3607 goto lend;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003608 }
3609
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003610 if (lpBuffer == NULL)
3611 *lpdwBufferLength = 0;
Juan Langb49b2432011-03-01 10:59:39 -08003612 res = HTTP_HttpQueryInfoW( request, dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003613 lpBuffer, lpdwBufferLength, lpdwIndex);
Ulrich Czekallac2757242000-06-11 20:04:44 +00003614
Mike McCormack3a1391b2004-07-19 21:49:39 +00003615lend:
Juan Langb49b2432011-03-01 10:59:39 -08003616 if( request )
3617 WININET_Release( &request->hdr );
Mike McCormack3a1391b2004-07-19 21:49:39 +00003618
Jacek Caban9823c232009-12-14 02:27:29 +01003619 TRACE("%u <--\n", res);
3620 if(res != ERROR_SUCCESS)
3621 SetLastError(res);
3622 return res == ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003623}
3624
Alberto Massarid476a5a2002-11-12 02:13:04 +00003625/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003626 * HttpQueryInfoA (WININET.@)
Alberto Massarid476a5a2002-11-12 02:13:04 +00003627 *
3628 * Queries for information about an HTTP request
3629 *
3630 * RETURNS
3631 * TRUE on success
3632 * FALSE on failure
3633 *
3634 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003635BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Alberto Massarid476a5a2002-11-12 02:13:04 +00003636 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3637{
3638 BOOL result;
Mike McCormack1baf39f2004-03-30 20:37:49 +00003639 DWORD len;
3640 WCHAR* bufferW;
3641
Alberto Massarid476a5a2002-11-12 02:13:04 +00003642 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3643 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3644 {
Mike McCormack1baf39f2004-03-30 20:37:49 +00003645 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3646 lpdwBufferLength, lpdwIndex );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003647 }
Mike McCormack1baf39f2004-03-30 20:37:49 +00003648
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003649 if (lpBuffer)
3650 {
Rob Shearman719cd822008-02-18 19:37:35 +00003651 DWORD alloclen;
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003652 len = (*lpdwBufferLength)*sizeof(WCHAR);
Rob Shearman719cd822008-02-18 19:37:35 +00003653 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3654 {
3655 alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3656 if (alloclen < len)
3657 alloclen = len;
3658 }
3659 else
3660 alloclen = len;
Jacek Caban354a74e2011-04-21 13:39:03 +02003661 bufferW = heap_alloc(alloclen);
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003662 /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3663 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
Rob Shearman719cd822008-02-18 19:37:35 +00003664 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003665 } else
3666 {
3667 bufferW = NULL;
3668 len = 0;
3669 }
3670
Mike McCormack1baf39f2004-03-30 20:37:49 +00003671 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3672 &len, lpdwIndex );
3673 if( result )
Alberto Massarid476a5a2002-11-12 02:13:04 +00003674 {
Robert Shearman4385d302004-07-21 21:17:03 +00003675 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
Mike McCormack1baf39f2004-03-30 20:37:49 +00003676 lpBuffer, *lpdwBufferLength, NULL, NULL );
Robert Shearman4385d302004-07-21 21:17:03 +00003677 *lpdwBufferLength = len - 1;
3678
3679 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
Alberto Massarid476a5a2002-11-12 02:13:04 +00003680 }
Robert Shearman907ac442004-07-20 01:21:08 +00003681 else
3682 /* since the strings being returned from HttpQueryInfoW should be
3683 * only ASCII characters, it is reasonable to assume that all of
3684 * the Unicode characters can be reduced to a single byte */
3685 *lpdwBufferLength = len / sizeof(WCHAR);
Robert Shearman4385d302004-07-21 21:17:03 +00003686
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003687 heap_free( bufferW );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003688 return result;
3689}
Huw D M Daviesf9b6d7b2000-10-28 00:30:23 +00003690
3691/***********************************************************************
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003692 * HTTP_GetRedirectURL (internal)
3693 */
Juan Langb49b2432011-03-01 10:59:39 -08003694static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003695{
3696 static WCHAR szHttp[] = {'h','t','t','p',0};
3697 static WCHAR szHttps[] = {'h','t','t','p','s',0};
Juan Lang20980062011-03-01 11:18:22 -08003698 http_session_t *session = request->session;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003699 URL_COMPONENTSW urlComponents;
3700 DWORD url_length = 0;
3701 LPWSTR orig_url;
3702 LPWSTR combined_url;
3703
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003704 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Juan Langb49b2432011-03-01 10:59:39 -08003705 urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003706 urlComponents.dwSchemeLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003707 urlComponents.lpszHostName = session->hostName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003708 urlComponents.dwHostNameLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003709 urlComponents.nPort = session->hostPort;
3710 urlComponents.lpszUserName = session->userName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003711 urlComponents.dwUserNameLength = 0;
3712 urlComponents.lpszPassword = NULL;
3713 urlComponents.dwPasswordLength = 0;
Juan Lang20980062011-03-01 11:18:22 -08003714 urlComponents.lpszUrlPath = request->path;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003715 urlComponents.dwUrlPathLength = 0;
3716 urlComponents.lpszExtraInfo = NULL;
3717 urlComponents.dwExtraInfoLength = 0;
3718
3719 if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
3720 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3721 return NULL;
3722
Jacek Caban354a74e2011-04-21 13:39:03 +02003723 orig_url = heap_alloc(url_length);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003724
3725 /* convert from bytes to characters */
3726 url_length = url_length / sizeof(WCHAR) - 1;
3727 if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
3728 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003729 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003730 return NULL;
3731 }
3732
3733 url_length = 0;
3734 if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
3735 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3736 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003737 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003738 return NULL;
3739 }
Jacek Caban354a74e2011-04-21 13:39:03 +02003740 combined_url = heap_alloc(url_length * sizeof(WCHAR));
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003741
3742 if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
3743 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003744 heap_free(orig_url);
3745 heap_free(combined_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003746 return NULL;
3747 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003748 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003749 return combined_url;
3750}
3751
3752
3753/***********************************************************************
Alberto Massaribc8bd722002-12-06 23:20:31 +00003754 * HTTP_HandleRedirect (internal)
3755 */
Juan Langb49b2432011-03-01 10:59:39 -08003756static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003757{
Juan Lang20980062011-03-01 11:18:22 -08003758 http_session_t *session = request->session;
Juan Lang8e050392011-03-01 11:02:14 -08003759 appinfo_t *hIC = session->appInfo;
Juan Lang72431562011-03-01 11:00:49 -08003760 BOOL using_proxy = hIC->proxy && hIC->proxy[0];
Hans Leidekker612f3c12008-03-31 20:26:16 +02003761 WCHAR path[INTERNET_MAX_URL_LENGTH];
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003762 int index;
Mike McCormack7cc70c02004-02-07 01:03:41 +00003763
Alberto Massaribc8bd722002-12-06 23:20:31 +00003764 if(lpszUrl[0]=='/')
3765 {
3766 /* if it's an absolute path, keep the same session info */
Hans Leidekker612f3c12008-03-31 20:26:16 +02003767 lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003768 }
3769 else
3770 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00003771 URL_COMPONENTSW urlComponents;
3772 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
Hans Leidekker781f3f72006-10-13 15:43:54 +02003773 static WCHAR szHttp[] = {'h','t','t','p',0};
3774 static WCHAR szHttps[] = {'h','t','t','p','s',0};
Robert Shearman05900252006-03-09 15:11:59 +00003775
Aric Stewart1fc760d2005-11-28 17:31:02 +01003776 userName[0] = 0;
3777 hostName[0] = 0;
3778 protocol[0] = 0;
3779
Mike McCormacka4e902c2004-03-30 04:36:09 +00003780 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003781 urlComponents.lpszScheme = protocol;
3782 urlComponents.dwSchemeLength = 32;
3783 urlComponents.lpszHostName = hostName;
3784 urlComponents.dwHostNameLength = MAXHOSTNAME;
3785 urlComponents.lpszUserName = userName;
3786 urlComponents.dwUserNameLength = 1024;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003787 urlComponents.lpszPassword = NULL;
3788 urlComponents.dwPasswordLength = 0;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003789 urlComponents.lpszUrlPath = path;
3790 urlComponents.dwUrlPathLength = 2048;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003791 urlComponents.lpszExtraInfo = NULL;
3792 urlComponents.dwExtraInfoLength = 0;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003793 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003794 return INTERNET_GetLastError();
Robert Shearmanefac01b2005-11-29 11:25:31 +01003795
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003796 if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
Juan Langb49b2432011-03-01 10:59:39 -08003797 (request->hdr.dwFlags & INTERNET_FLAG_SECURE))
Robert Shearmanefac01b2005-11-29 11:25:31 +01003798 {
3799 TRACE("redirect from secure page to non-secure page\n");
3800 /* FIXME: warn about from secure redirect to non-secure page */
Juan Langb49b2432011-03-01 10:59:39 -08003801 request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
Robert Shearmanefac01b2005-11-29 11:25:31 +01003802 }
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003803 if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) &&
Juan Langb49b2432011-03-01 10:59:39 -08003804 !(request->hdr.dwFlags & INTERNET_FLAG_SECURE))
Robert Shearmanefac01b2005-11-29 11:25:31 +01003805 {
3806 TRACE("redirect from non-secure page to secure page\n");
3807 /* FIXME: notify about redirect to secure page */
Juan Langb49b2432011-03-01 10:59:39 -08003808 request->hdr.dwFlags |= INTERNET_FLAG_SECURE;
Robert Shearmanefac01b2005-11-29 11:25:31 +01003809 }
3810
Alberto Massaribc8bd722002-12-06 23:20:31 +00003811 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
Aric Stewart1fc760d2005-11-28 17:31:02 +01003812 {
3813 if (lstrlenW(protocol)>4) /*https*/
3814 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3815 else /*http*/
3816 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3817 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003818
Mike McCormacka1c16d22003-07-22 03:17:52 +00003819#if 0
3820 /*
3821 * This upsets redirects to binary files on sourceforge.net
3822 * and gives an html page instead of the target file
3823 * Examination of the HTTP request sent by native wininet.dll
3824 * reveals that it doesn't send a referrer in that case.
3825 * Maybe there's a flag that enables this, or maybe a referrer
3826 * shouldn't be added in case of a redirect.
3827 */
3828
3829 /* consider the current host as the referrer */
Juan Langb49b2432011-03-01 10:59:39 -08003830 if (session->lpszServerName && *session->lpszServerName)
3831 HTTP_ProcessHeader(request, HTTP_REFERER, session->lpszServerName,
Mike McCormacka1c16d22003-07-22 03:17:52 +00003832 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
3833 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
3834#endif
Alberto Massaribc8bd722002-12-06 23:20:31 +00003835
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003836 heap_free(session->hostName);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003837 if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
Hans Leidekker8210e1b2008-03-31 20:25:57 +02003838 urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
Aric Stewart1fc760d2005-11-28 17:31:02 +01003839 {
3840 int len;
André Hentschel1a39e292011-03-27 15:27:46 +02003841 static const WCHAR fmt[] = {'%','s',':','%','u',0};
Aric Stewart1fc760d2005-11-28 17:31:02 +01003842 len = lstrlenW(hostName);
Robert Shearman8a8ce9c2005-11-29 11:35:19 +01003843 len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
Jacek Caban354a74e2011-04-21 13:39:03 +02003844 session->hostName = heap_alloc(len*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08003845 sprintfW(session->hostName, fmt, hostName, urlComponents.nPort);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003846 }
3847 else
Juan Lang8e050392011-03-01 11:02:14 -08003848 session->hostName = heap_strdupW(hostName);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003849
Juan Lang8e050392011-03-01 11:02:14 -08003850 HTTP_ProcessHeader(request, hostW, session->hostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003851
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003852 heap_free(session->userName);
Juan Lang8e050392011-03-01 11:02:14 -08003853 session->userName = NULL;
Robert Shearmanef209362006-03-10 12:28:52 +00003854 if (userName[0])
Juan Lang8e050392011-03-01 11:02:14 -08003855 session->userName = heap_strdupW(userName);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003856
Jacek Caban8a1df202011-05-10 09:26:43 +00003857 reset_data_stream(request);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003858
Jacek Caban8a1df202011-05-10 09:26:43 +00003859 if(!using_proxy) {
3860 if(strcmpiW(session->serverName, hostName)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003861 heap_free(session->serverName);
Juan Lang8e050392011-03-01 11:02:14 -08003862 session->serverName = heap_strdupW(hostName);
Hans Leidekkerbdf311f2008-06-29 16:03:39 +02003863 }
Jacek Caban8a1df202011-05-10 09:26:43 +00003864 session->serverPort = urlComponents.nPort;
Hans Leidekker8210e1b2008-03-31 20:25:57 +02003865 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003866 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003867 heap_free(request->path);
Juan Lang20980062011-03-01 11:18:22 -08003868 request->path=NULL;
Jacek Cabanf9791342008-02-13 13:34:05 +01003869 if (*path)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003870 {
3871 DWORD needed = 0;
3872 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003873
3874 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003875 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003876 needed = strlenW(path)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003877 request->path = heap_alloc(needed*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003878 rc = UrlEscapeW(path, request->path, &needed,
Alberto Massaribc8bd722002-12-06 23:20:31 +00003879 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003880 if (rc != S_OK)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003881 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003882 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
Juan Lang20980062011-03-01 11:18:22 -08003883 strcpyW(request->path,path);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003884 }
3885 }
3886
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003887 /* Remove custom content-type/length headers on redirects. */
Juan Langb49b2432011-03-01 10:59:39 -08003888 index = HTTP_GetCustomHeaderIndex(request, szContent_Type, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003889 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003890 HTTP_DeleteCustomHeader(request, index);
3891 index = HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003892 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003893 HTTP_DeleteCustomHeader(request, index);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003894
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003895 return ERROR_SUCCESS;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003896}
3897
3898/***********************************************************************
Mike McCormacka4969062004-07-04 00:24:47 +00003899 * HTTP_build_req (internal)
3900 *
3901 * concatenate all the strings in the request together
3902 */
3903static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
3904{
3905 LPCWSTR *t;
3906 LPWSTR str;
3907
3908 for( t = list; *t ; t++ )
3909 len += strlenW( *t );
3910 len++;
3911
Jacek Caban354a74e2011-04-21 13:39:03 +02003912 str = heap_alloc(len*sizeof(WCHAR));
Mike McCormacka4969062004-07-04 00:24:47 +00003913 *str = 0;
3914
3915 for( t = list; *t ; t++ )
3916 strcatW( str, *t );
3917
3918 return str;
3919}
3920
Juan Langb49b2432011-03-01 10:59:39 -08003921static DWORD HTTP_SecureProxyConnect(http_request_t *request)
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003922{
3923 LPWSTR lpszPath;
3924 LPWSTR requestString;
3925 INT len;
3926 INT cnt;
3927 INT responseLen;
3928 char *ascii_req;
Jacek Cabanb77868c2009-11-30 00:13:21 +01003929 DWORD res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003930 static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
André Hentschel1a39e292011-03-27 15:27:46 +02003931 static const WCHAR szFormat[] = {'%','s',':','%','u',0};
Juan Lang20980062011-03-01 11:18:22 -08003932 http_session_t *session = request->session;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003933
3934 TRACE("\n");
3935
Jacek Caban354a74e2011-04-21 13:39:03 +02003936 lpszPath = heap_alloc((lstrlenW( session->hostName ) + 13)*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08003937 sprintfW( lpszPath, szFormat, session->hostName, session->hostPort );
Juan Langb49b2432011-03-01 10:59:39 -08003938 requestString = HTTP_BuildHeaderRequestString( request, szConnect, lpszPath, g_szHttp1_1 );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003939 heap_free( lpszPath );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003940
3941 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3942 NULL, 0, NULL, NULL );
3943 len--; /* the nul terminator isn't needed */
Jacek Caban354a74e2011-04-21 13:39:03 +02003944 ascii_req = heap_alloc(len);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003945 WideCharToMultiByte( CP_ACP, 0, requestString, -1, ascii_req, len, NULL, NULL );
3946 heap_free( requestString );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003947
3948 TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
3949
Jacek Caban8a1df202011-05-10 09:26:43 +00003950 res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003951 heap_free( ascii_req );
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003952 if (res != ERROR_SUCCESS)
3953 return res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003954
Juan Langb49b2432011-03-01 10:59:39 -08003955 responseLen = HTTP_GetResponseHeaders( request, TRUE );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003956 if (!responseLen)
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003957 return ERROR_HTTP_INVALID_HEADER;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003958
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003959 return ERROR_SUCCESS;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003960}
3961
Juan Langb49b2432011-03-01 10:59:39 -08003962static void HTTP_InsertCookies(http_request_t *request)
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003963{
Jacek Cabandce91812011-05-19 16:11:30 +02003964 DWORD cookie_size, size, cnt = 0;
3965 HTTPHEADERW *host;
3966 WCHAR *cookies;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003967
Jacek Cabandce91812011-05-19 16:11:30 +02003968 static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' ',0};
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003969
Jacek Cabandce91812011-05-19 16:11:30 +02003970 host = HTTP_GetHeader(request, hostW);
3971 if(!host)
3972 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003973
Jacek Cabandce91812011-05-19 16:11:30 +02003974 if(!get_cookie(host->lpszValue, request->path, NULL, &cookie_size))
3975 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003976
Jacek Cabandce91812011-05-19 16:11:30 +02003977 size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf);
3978 if(!(cookies = heap_alloc(size)))
3979 return;
3980
3981 cnt += sprintfW(cookies, cookieW);
3982 get_cookie(host->lpszValue, request->path, cookies+cnt, &cookie_size);
3983 strcatW(cookies, szCrLf);
3984
3985 HTTP_HttpAddRequestHeadersW(request, cookies, strlenW(cookies), HTTP_ADDREQ_FLAG_REPLACE);
3986
3987 heap_free(cookies);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003988}
3989
Juan Lang0b5ea6f2011-03-03 11:20:11 -08003990static WORD HTTP_ParseDay(LPCWSTR day)
3991{
Francois Gouget4bacb3f2011-03-11 18:22:23 +01003992 static const WCHAR days[7][4] = {{ 's','u','n',0 },
3993 { 'm','o','n',0 },
3994 { 't','u','e',0 },
3995 { 'w','e','d',0 },
3996 { 't','h','u',0 },
3997 { 'f','r','i',0 },
3998 { 's','a','t',0 }};
3999 int i;
4000 for (i = 0; i < sizeof(days)/sizeof(*days); i++)
4001 if (!strcmpiW(day, days[i]))
4002 return i;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004003
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004004 /* Invalid */
4005 return 7;
4006}
4007
4008static WORD HTTP_ParseMonth(LPCWSTR month)
4009{
4010 static const WCHAR jan[] = { 'j','a','n',0 };
4011 static const WCHAR feb[] = { 'f','e','b',0 };
4012 static const WCHAR mar[] = { 'm','a','r',0 };
4013 static const WCHAR apr[] = { 'a','p','r',0 };
4014 static const WCHAR may[] = { 'm','a','y',0 };
4015 static const WCHAR jun[] = { 'j','u','n',0 };
4016 static const WCHAR jul[] = { 'j','u','l',0 };
4017 static const WCHAR aug[] = { 'a','u','g',0 };
4018 static const WCHAR sep[] = { 's','e','p',0 };
4019 static const WCHAR oct[] = { 'o','c','t',0 };
4020 static const WCHAR nov[] = { 'n','o','v',0 };
4021 static const WCHAR dec[] = { 'd','e','c',0 };
4022
4023 if (!strcmpiW(month, jan)) return 1;
4024 if (!strcmpiW(month, feb)) return 2;
4025 if (!strcmpiW(month, mar)) return 3;
4026 if (!strcmpiW(month, apr)) return 4;
4027 if (!strcmpiW(month, may)) return 5;
4028 if (!strcmpiW(month, jun)) return 6;
4029 if (!strcmpiW(month, jul)) return 7;
4030 if (!strcmpiW(month, aug)) return 8;
4031 if (!strcmpiW(month, sep)) return 9;
4032 if (!strcmpiW(month, oct)) return 10;
4033 if (!strcmpiW(month, nov)) return 11;
4034 if (!strcmpiW(month, dec)) return 12;
4035 /* Invalid */
4036 return 0;
4037}
4038
Juan Lang28e92292011-03-04 11:43:54 -08004039/* Parses the string pointed to by *str, assumed to be a 24-hour time HH:MM:SS,
4040 * optionally preceded by whitespace.
4041 * Upon success, returns TRUE, sets the wHour, wMinute, and wSecond fields of
4042 * st, and sets *str to the first character after the time format.
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004043 */
Juan Lang28e92292011-03-04 11:43:54 -08004044static BOOL HTTP_ParseTime(SYSTEMTIME *st, LPCWSTR *str)
4045{
4046 LPCWSTR ptr = *str;
4047 WCHAR *nextPtr;
4048 unsigned long num;
4049
4050 while (isspaceW(*ptr))
4051 ptr++;
4052
4053 num = strtoulW(ptr, &nextPtr, 10);
4054 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4055 {
4056 ERR("unexpected time format %s\n", debugstr_w(ptr));
4057 return FALSE;
4058 }
4059 if (num > 23)
4060 {
4061 ERR("unexpected hour in time format %s\n", debugstr_w(ptr));
4062 return FALSE;
4063 }
4064 ptr = nextPtr + 1;
4065 st->wHour = (WORD)num;
4066 num = strtoulW(ptr, &nextPtr, 10);
4067 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4068 {
4069 ERR("unexpected time format %s\n", debugstr_w(ptr));
4070 return FALSE;
4071 }
4072 if (num > 59)
4073 {
4074 ERR("unexpected minute in time format %s\n", debugstr_w(ptr));
4075 return FALSE;
4076 }
4077 ptr = nextPtr + 1;
4078 st->wMinute = (WORD)num;
4079 num = strtoulW(ptr, &nextPtr, 10);
4080 if (!nextPtr || nextPtr <= ptr)
4081 {
4082 ERR("unexpected time format %s\n", debugstr_w(ptr));
4083 return FALSE;
4084 }
4085 if (num > 59)
4086 {
4087 ERR("unexpected second in time format %s\n", debugstr_w(ptr));
4088 return FALSE;
4089 }
4090 ptr = nextPtr + 1;
4091 *str = ptr;
4092 st->wSecond = (WORD)num;
4093 return TRUE;
4094}
4095
4096static BOOL HTTP_ParseDateAsAsctime(LPCWSTR value, FILETIME *ft)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004097{
4098 static const WCHAR gmt[]= { 'G','M','T',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004099 WCHAR day[4], *dayPtr, month[4], *monthPtr, *nextPtr;
4100 LPCWSTR ptr;
4101 SYSTEMTIME st = { 0 };
4102 unsigned long num;
4103
4104 for (ptr = value, dayPtr = day; *ptr && !isspaceW(*ptr) &&
4105 dayPtr - day < sizeof(day) / sizeof(day[0]) - 1; ptr++, dayPtr++)
4106 *dayPtr = *ptr;
4107 *dayPtr = 0;
4108 st.wDayOfWeek = HTTP_ParseDay(day);
4109 if (st.wDayOfWeek >= 7)
4110 {
4111 ERR("unexpected weekday %s\n", debugstr_w(day));
4112 return FALSE;
4113 }
4114
4115 while (isspaceW(*ptr))
4116 ptr++;
4117
4118 for (monthPtr = month; !isspace(*ptr) &&
4119 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4120 monthPtr++, ptr++)
4121 *monthPtr = *ptr;
4122 *monthPtr = 0;
4123 st.wMonth = HTTP_ParseMonth(month);
4124 if (!st.wMonth || st.wMonth > 12)
4125 {
4126 ERR("unexpected month %s\n", debugstr_w(month));
4127 return FALSE;
4128 }
4129
4130 while (isspaceW(*ptr))
4131 ptr++;
4132
4133 num = strtoulW(ptr, &nextPtr, 10);
4134 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4135 {
4136 ERR("unexpected day %s\n", debugstr_w(ptr));
4137 return FALSE;
4138 }
4139 ptr = nextPtr;
4140 st.wDay = (WORD)num;
4141
4142 while (isspaceW(*ptr))
4143 ptr++;
4144
4145 if (!HTTP_ParseTime(&st, &ptr))
4146 return FALSE;
4147
4148 while (isspaceW(*ptr))
4149 ptr++;
4150
4151 num = strtoulW(ptr, &nextPtr, 10);
4152 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4153 {
4154 ERR("unexpected year %s\n", debugstr_w(ptr));
4155 return FALSE;
4156 }
4157 ptr = nextPtr;
4158 st.wYear = (WORD)num;
4159
4160 while (isspaceW(*ptr))
4161 ptr++;
4162
4163 /* asctime() doesn't report a timezone, but some web servers do, so accept
4164 * with or without GMT.
4165 */
4166 if (*ptr && strcmpW(ptr, gmt))
4167 {
4168 ERR("unexpected timezone %s\n", debugstr_w(ptr));
4169 return FALSE;
4170 }
4171 return SystemTimeToFileTime(&st, ft);
4172}
4173
4174static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft)
4175{
4176 static const WCHAR gmt[]= { 'G','M','T',0 };
4177 WCHAR *nextPtr, day[4], month[4], *monthPtr;
4178 LPCWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004179 unsigned long num;
Juan Langb9673bc2011-03-07 13:13:11 -08004180 SYSTEMTIME st = { 0 };
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004181
4182 ptr = strchrW(value, ',');
4183 if (!ptr)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004184 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004185 if (ptr - value != 3)
4186 {
4187 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4188 return FALSE;
4189 }
4190 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4191 day[3] = 0;
4192 st.wDayOfWeek = HTTP_ParseDay(day);
4193 if (st.wDayOfWeek > 6)
4194 {
4195 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4196 return FALSE;
4197 }
4198 ptr++;
4199
4200 while (isspaceW(*ptr))
4201 ptr++;
4202
4203 num = strtoulW(ptr, &nextPtr, 10);
4204 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4205 {
4206 ERR("unexpected day %s\n", debugstr_w(value));
4207 return FALSE;
4208 }
4209 ptr = nextPtr;
4210 st.wDay = (WORD)num;
4211
4212 while (isspaceW(*ptr))
4213 ptr++;
4214
4215 for (monthPtr = month; !isspace(*ptr) &&
4216 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4217 monthPtr++, ptr++)
4218 *monthPtr = *ptr;
4219 *monthPtr = 0;
4220 st.wMonth = HTTP_ParseMonth(month);
4221 if (!st.wMonth || st.wMonth > 12)
4222 {
4223 ERR("unexpected month %s\n", debugstr_w(month));
4224 return FALSE;
4225 }
4226
4227 while (isspaceW(*ptr))
4228 ptr++;
4229
4230 num = strtoulW(ptr, &nextPtr, 10);
4231 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4232 {
4233 ERR("unexpected year %s\n", debugstr_w(value));
4234 return FALSE;
4235 }
4236 ptr = nextPtr;
4237 st.wYear = (WORD)num;
4238
Juan Lang28e92292011-03-04 11:43:54 -08004239 if (!HTTP_ParseTime(&st, &ptr))
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004240 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004241
4242 while (isspaceW(*ptr))
4243 ptr++;
4244
4245 if (strcmpW(ptr, gmt))
4246 {
4247 ERR("unexpected time zone %s\n", debugstr_w(ptr));
4248 return FALSE;
4249 }
4250 return SystemTimeToFileTime(&st, ft);
4251}
4252
Juan Lang28e92292011-03-04 11:43:54 -08004253/* FIXME: only accepts dates in RFC 1123 format and asctime() format,
4254 * which may not be the only formats actually seen in the wild.
4255 * http://www.hackcraft.net/web/datetime/ suggests at least RFC 850 dates
4256 * should be accepted as well.
4257 */
4258static BOOL HTTP_ParseDate(LPCWSTR value, FILETIME *ft)
4259{
Juan Langd797e5f2011-05-13 06:47:49 -07004260 static const WCHAR zero[] = { '0',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004261 BOOL ret;
4262
Juan Langd797e5f2011-05-13 06:47:49 -07004263 if (!strcmpW(value, zero))
4264 {
4265 ft->dwLowDateTime = ft->dwHighDateTime = 0;
4266 ret = TRUE;
4267 }
4268 else if (strchrW(value, ','))
Juan Lang28e92292011-03-04 11:43:54 -08004269 ret = HTTP_ParseRfc1123Date(value, ft);
4270 else
4271 {
4272 ret = HTTP_ParseDateAsAsctime(value, ft);
4273 if (!ret)
4274 ERR("unexpected date format %s\n", debugstr_w(value));
4275 }
4276 return ret;
4277}
4278
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004279static void HTTP_ProcessExpires(http_request_t *request)
4280{
Juan Langab16c752011-03-03 10:54:07 -08004281 BOOL expirationFound = FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004282 int headerIndex;
4283
Juan Lang488c2d02011-03-03 10:54:47 -08004284 /* Look for a Cache-Control header with a max-age directive, as it takes
4285 * precedence over the Expires header.
4286 */
4287 headerIndex = HTTP_GetCustomHeaderIndex(request, szCache_Control, 0, FALSE);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004288 if (headerIndex != -1)
4289 {
Juan Lang488c2d02011-03-03 10:54:47 -08004290 LPHTTPHEADERW ccHeader = &request->custHeaders[headerIndex];
4291 LPWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004292
Juan Lang488c2d02011-03-03 10:54:47 -08004293 for (ptr = ccHeader->lpszValue; ptr && *ptr; )
Juan Langab16c752011-03-03 10:54:07 -08004294 {
Juan Lang488c2d02011-03-03 10:54:47 -08004295 LPWSTR comma = strchrW(ptr, ','), end, equal;
4296
4297 if (comma)
4298 end = comma;
4299 else
4300 end = ptr + strlenW(ptr);
4301 for (equal = end - 1; equal > ptr && *equal != '='; equal--)
4302 ;
4303 if (*equal == '=')
4304 {
4305 static const WCHAR max_age[] = {
4306 'm','a','x','-','a','g','e',0 };
4307
4308 if (!strncmpiW(ptr, max_age, equal - ptr - 1))
4309 {
4310 LPWSTR nextPtr;
4311 unsigned long age;
4312
4313 age = strtoulW(equal + 1, &nextPtr, 10);
4314 if (nextPtr > equal + 1)
4315 {
4316 LARGE_INTEGER ft;
4317
4318 NtQuerySystemTime( &ft );
4319 /* Age is in seconds, FILETIME resolution is in
4320 * 100 nanosecond intervals.
4321 */
4322 ft.QuadPart += age * (ULONGLONG)1000000;
4323 request->expires.dwLowDateTime = ft.u.LowPart;
4324 request->expires.dwHighDateTime = ft.u.HighPart;
4325 expirationFound = TRUE;
4326 }
4327 }
4328 }
4329 if (comma)
4330 {
4331 ptr = comma + 1;
4332 while (isspaceW(*ptr))
4333 ptr++;
4334 }
4335 else
4336 ptr = NULL;
4337 }
4338 }
4339 if (!expirationFound)
4340 {
4341 headerIndex = HTTP_GetCustomHeaderIndex(request, szExpires, 0, FALSE);
4342 if (headerIndex != -1)
4343 {
4344 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4345 FILETIME ft;
4346
4347 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4348 {
4349 expirationFound = TRUE;
4350 request->expires = ft;
4351 }
Juan Langab16c752011-03-03 10:54:07 -08004352 }
4353 }
4354 if (!expirationFound)
4355 {
Juan Lang2d323432011-03-03 10:54:07 -08004356 LARGE_INTEGER t;
Juan Langab16c752011-03-03 10:54:07 -08004357
4358 /* With no known age, default to 10 minutes until expiration. */
Juan Lang2d323432011-03-03 10:54:07 -08004359 NtQuerySystemTime( &t );
4360 t.QuadPart += 10 * 60 * (ULONGLONG)10000000;
4361 request->expires.dwLowDateTime = t.u.LowPart;
4362 request->expires.dwHighDateTime = t.u.HighPart;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004363 }
4364}
4365
Juan Lang28e92292011-03-04 11:43:54 -08004366static void HTTP_ProcessLastModified(http_request_t *request)
4367{
4368 int headerIndex;
4369
4370 headerIndex = HTTP_GetCustomHeaderIndex(request, szLast_Modified, 0, FALSE);
4371 if (headerIndex != -1)
4372 {
4373 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4374 FILETIME ft;
4375
4376 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4377 request->last_modified = ft;
4378 }
4379}
4380
Jacek Caban8a1df202011-05-10 09:26:43 +00004381static void http_process_keep_alive(http_request_t *req)
4382{
4383 int index;
4384
4385 index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE);
4386 if(index != -1)
4387 req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive);
4388 else
4389 req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1);
4390}
4391
Juan Lang666353d2011-03-02 10:06:37 -08004392static void HTTP_CacheRequest(http_request_t *request)
4393{
4394 WCHAR url[INTERNET_MAX_URL_LENGTH];
4395 WCHAR cacheFileName[MAX_PATH+1];
4396 BOOL b;
4397
4398 b = HTTP_GetRequestURL(request, url);
4399 if(!b) {
4400 WARN("Could not get URL\n");
4401 return;
4402 }
4403
Juan Lang7685dad2011-03-03 08:55:32 -08004404 b = CreateUrlCacheEntryW(url, request->contentLength, NULL, cacheFileName, 0);
Juan Lang666353d2011-03-02 10:06:37 -08004405 if(b) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004406 heap_free(request->cacheFile);
Juan Lang666353d2011-03-02 10:06:37 -08004407 CloseHandle(request->hCacheFile);
4408
4409 request->cacheFile = heap_strdupW(cacheFileName);
4410 request->hCacheFile = CreateFileW(request->cacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
4411 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
4412 if(request->hCacheFile == INVALID_HANDLE_VALUE) {
4413 WARN("Could not create file: %u\n", GetLastError());
4414 request->hCacheFile = NULL;
4415 }
4416 }else {
4417 WARN("Could not create cache entry: %08x\n", GetLastError());
4418 }
4419}
4420
Jacek Caban8a1df202011-05-10 09:26:43 +00004421static DWORD open_http_connection(http_request_t *request, BOOL *reusing)
4422{
4423 const BOOL is_https = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) != 0;
4424 http_session_t *session = request->session;
4425 netconn_t *netconn = NULL;
4426 server_t *server;
4427 DWORD res;
4428
4429 assert(!request->netconn);
4430 reset_data_stream(request);
4431
4432 server = get_server(session->serverName, session->serverPort);
4433 if(!server)
4434 return ERROR_OUTOFMEMORY;
4435
4436 res = HTTP_ResolveName(request, server);
4437 if(res != ERROR_SUCCESS) {
4438 server_release(server);
4439 return res;
4440 }
4441
4442 EnterCriticalSection(&connection_pool_cs);
4443
4444 while(!list_empty(&server->conn_pool)) {
4445 netconn = LIST_ENTRY(list_head(&server->conn_pool), netconn_t, pool_entry);
4446 list_remove(&netconn->pool_entry);
4447
4448 if(NETCON_is_alive(netconn))
4449 break;
4450
4451 TRACE("connection %p closed during idle\n", netconn);
4452 free_netconn(netconn);
4453 netconn = NULL;
4454 }
4455
4456 LeaveCriticalSection(&connection_pool_cs);
4457
4458 if(netconn) {
4459 TRACE("<-- reusing %p netconn\n", netconn);
4460 request->netconn = netconn;
4461 *reusing = TRUE;
4462 return ERROR_SUCCESS;
4463 }
4464
4465 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4466 INTERNET_STATUS_CONNECTING_TO_SERVER,
4467 server->addr_str,
4468 strlen(server->addr_str)+1);
4469
4470 res = create_netconn(is_https, server, request->security_flags, &netconn);
4471 server_release(server);
4472 if(res != ERROR_SUCCESS) {
4473 ERR("create_netconn failed: %u\n", res);
4474 return res;
4475 }
4476
4477 request->netconn = netconn;
4478
4479 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4480 INTERNET_STATUS_CONNECTED_TO_SERVER,
4481 server->addr_str, strlen(server->addr_str)+1);
4482
4483 if(is_https) {
4484 /* Note: we differ from Microsoft's WinINet here. they seem to have
4485 * a bug that causes no status callbacks to be sent when starting
4486 * a tunnel to a proxy server using the CONNECT verb. i believe our
4487 * behaviour to be more correct and to not cause any incompatibilities
4488 * because using a secure connection through a proxy server is a rare
4489 * case that would be hard for anyone to depend on */
4490 if(session->appInfo->proxy)
4491 res = HTTP_SecureProxyConnect(request);
4492 if(res == ERROR_SUCCESS)
4493 res = NETCON_secure_connect(request->netconn, session->hostName);
4494 if(res != ERROR_SUCCESS)
4495 {
4496 WARN("Couldn't connect securely to host\n");
4497
4498 if((request->hdr.ErrorMask&INTERNET_ERROR_MASK_COMBINED_SEC_CERT) && (
4499 res == ERROR_INTERNET_SEC_CERT_DATE_INVALID
4500 || res == ERROR_INTERNET_INVALID_CA
4501 || res == ERROR_INTERNET_SEC_CERT_NO_REV
4502 || res == ERROR_INTERNET_SEC_CERT_REV_FAILED
4503 || res == ERROR_INTERNET_SEC_CERT_REVOKED
4504 || res == ERROR_INTERNET_SEC_INVALID_CERT
4505 || res == ERROR_INTERNET_SEC_CERT_CN_INVALID))
4506 res = ERROR_INTERNET_SEC_CERT_ERRORS;
4507 }
4508 }
4509
4510 if(res != ERROR_SUCCESS) {
4511 http_release_netconn(request, FALSE);
4512 return res;
4513 }
4514
4515 *reusing = FALSE;
4516 TRACE("Created connection to %s: %p\n", debugstr_w(server->name), netconn);
4517 return ERROR_SUCCESS;
4518}
4519
Mike McCormacka4969062004-07-04 00:24:47 +00004520/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00004521 * HTTP_HttpSendRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004522 *
4523 * Sends the specified request to the HTTP server
4524 *
4525 * RETURNS
Juan Langb2ed9c52011-03-02 17:09:45 -08004526 * ERROR_SUCCESS on success
4527 * win32 error code on failure
Ulrich Czekallac2757242000-06-11 20:04:44 +00004528 *
4529 */
Juan Langb49b2432011-03-01 10:59:39 -08004530static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004531 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
4532 DWORD dwContentLength, BOOL bEndRequest)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004533{
4534 INT cnt;
Jacek Cabanc952e812009-12-03 14:48:54 +01004535 BOOL redirected = FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00004536 LPWSTR requestString = NULL;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004537 INT responseLen;
Rob Shearman14fb4182007-01-04 18:21:13 +00004538 BOOL loop_next;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004539 static const WCHAR szPost[] = { 'P','O','S','T',0 };
Hans Leidekker64359c22007-10-28 16:32:46 +01004540 static const WCHAR szContentLength[] =
4541 { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
4542 WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004543 DWORD res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00004544
Juan Langb49b2432011-03-01 10:59:39 -08004545 TRACE("--> %p\n", request);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004546
Juan Langb49b2432011-03-01 10:59:39 -08004547 assert(request->hdr.htype == WH_HHTTPREQ);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004548
Jacek Cabanf9791342008-02-13 13:34:05 +01004549 /* if the verb is NULL default to GET */
Juan Lang20980062011-03-01 11:18:22 -08004550 if (!request->verb)
4551 request->verb = heap_strdupW(szGET);
Jacek Cabanf9791342008-02-13 13:34:05 +01004552
Juan Lang20980062011-03-01 11:18:22 -08004553 if (dwContentLength || strcmpW(request->verb, szGET))
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004554 {
4555 sprintfW(contentLengthStr, szContentLength, dwContentLength);
Juan Langb49b2432011-03-01 10:59:39 -08004556 HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
Juan Lang20980062011-03-01 11:18:22 -08004557 request->bytesToWrite = dwContentLength;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004558 }
Juan Lang20980062011-03-01 11:18:22 -08004559 if (request->session->appInfo->agent)
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004560 {
4561 WCHAR *agent_header;
4562 static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
4563 int len;
4564
Juan Lang20980062011-03-01 11:18:22 -08004565 len = strlenW(request->session->appInfo->agent) + strlenW(user_agent);
Jacek Caban354a74e2011-04-21 13:39:03 +02004566 agent_header = heap_alloc(len * sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08004567 sprintfW(agent_header, user_agent, request->session->appInfo->agent);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004568
Juan Langb49b2432011-03-01 10:59:39 -08004569 HTTP_HttpAddRequestHeadersW(request, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004570 heap_free(agent_header);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004571 }
Juan Langb49b2432011-03-01 10:59:39 -08004572 if (request->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE)
Hans Leidekker34ff5552008-06-23 20:58:25 +02004573 {
4574 static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0};
Juan Langb49b2432011-03-01 10:59:39 -08004575 HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker34ff5552008-06-23 20:58:25 +02004576 }
Juan Lang20980062011-03-01 11:18:22 -08004577 if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost))
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004578 {
4579 static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
4580 ' ','n','o','-','c','a','c','h','e','\r','\n',0};
Juan Langb49b2432011-03-01 10:59:39 -08004581 HTTP_HttpAddRequestHeadersW(request, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004582 }
David Hammerton6226f3f2003-08-05 18:31:02 +00004583
David Hammerton852c7ae2003-06-20 23:26:56 +00004584 do
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004585 {
Aric Stewartbe918f42005-11-21 15:17:55 +00004586 DWORD len;
Piotr Cabanee684732010-06-29 12:20:51 +02004587 BOOL reusing_connection;
Mike McCormacka4969062004-07-04 00:24:47 +00004588 char *ascii_req;
4589
Rob Shearman14fb4182007-01-04 18:21:13 +00004590 loop_next = FALSE;
Rob Shearman272954b2007-01-04 18:23:17 +00004591
4592 /* like native, just in case the caller forgot to call InternetReadFile
4593 * for all the data */
Jacek Caban8a1df202011-05-10 09:26:43 +00004594 drain_content(request);
Piotr Caban224af0d2010-05-20 02:35:38 +02004595 if(redirected) {
Juan Lang20980062011-03-01 11:18:22 -08004596 request->contentLength = ~0u;
4597 request->bytesToWrite = 0;
Piotr Caban224af0d2010-05-20 02:35:38 +02004598 }
Rob Shearman14fb4182007-01-04 18:21:13 +00004599
Rob Shearman4319ec62006-12-07 00:53:27 +00004600 if (TRACE_ON(wininet))
4601 {
Juan Langb49b2432011-03-01 10:59:39 -08004602 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Juan Lang20980062011-03-01 11:18:22 -08004603 TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(request->path));
Rob Shearman4319ec62006-12-07 00:53:27 +00004604 }
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004605
Juan Langb49b2432011-03-01 10:59:39 -08004606 HTTP_FixURL(request);
4607 if (request->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION)
Hans Leidekker656a0352008-05-31 21:47:24 +02004608 {
Juan Langb49b2432011-03-01 10:59:39 -08004609 HTTP_ProcessHeader(request, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
Hans Leidekker656a0352008-05-31 21:47:24 +02004610 }
Juan Lang20980062011-03-01 11:18:22 -08004611 HTTP_InsertAuthorization(request, request->authInfo, szAuthorization);
4612 HTTP_InsertAuthorization(request, request->proxyAuthInfo, szProxy_Authorization);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004613
Juan Langb49b2432011-03-01 10:59:39 -08004614 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
4615 HTTP_InsertCookies(request);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004616
Mike McCormackf1d7b142004-07-21 19:36:34 +00004617 /* add the headers the caller supplied */
Mike McCormack08c6c692004-08-10 23:41:35 +00004618 if( lpszHeaders && dwHeaderLength )
Mike McCormackf1d7b142004-07-21 19:36:34 +00004619 {
Juan Langb49b2432011-03-01 10:59:39 -08004620 HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength,
Mike McCormack08c6c692004-08-10 23:41:35 +00004621 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
Mike McCormackf1d7b142004-07-21 19:36:34 +00004622 }
4623
Juan Lang20980062011-03-01 11:18:22 -08004624 if (request->session->appInfo->proxy && request->session->appInfo->proxy[0])
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004625 {
Juan Langb49b2432011-03-01 10:59:39 -08004626 WCHAR *url = HTTP_BuildProxyRequestUrl(request);
Juan Lang20980062011-03-01 11:18:22 -08004627 requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004628 heap_free(url);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004629 }
4630 else
Juan Lang20980062011-03-01 11:18:22 -08004631 requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004632
Mike McCormacka4969062004-07-04 00:24:47 +00004633
4634 TRACE("Request header -> %s\n", debugstr_w(requestString) );
Aric Stewartff9b9d42002-06-21 23:59:49 +00004635
Jacek Caban8a1df202011-05-10 09:26:43 +00004636 if ((res = open_http_connection(request, &reusing_connection)) != ERROR_SUCCESS)
4637 break;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004638
Mike McCormacka4969062004-07-04 00:24:47 +00004639 /* send the request as ASCII, tack on the optional data */
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004640 if (!lpOptional || redirected)
Mike McCormacka4969062004-07-04 00:24:47 +00004641 dwOptionalLength = 0;
4642 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4643 NULL, 0, NULL, NULL );
Jacek Caban354a74e2011-04-21 13:39:03 +02004644 ascii_req = heap_alloc(len + dwOptionalLength);
Mike McCormacka4969062004-07-04 00:24:47 +00004645 WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4646 ascii_req, len, NULL, NULL );
4647 if( lpOptional )
Mike McCormackf1d7b142004-07-21 19:36:34 +00004648 memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
4649 len = (len + dwOptionalLength - 1);
4650 ascii_req[len] = 0;
Aric Stewart44cbdf22005-10-19 18:28:35 +00004651 TRACE("full request -> %s\n", debugstr_a(ascii_req) );
Mike McCormackf1d7b142004-07-21 19:36:34 +00004652
Juan Langb49b2432011-03-01 10:59:39 -08004653 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004654 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Mike McCormackf1d7b142004-07-21 19:36:34 +00004655
Jacek Caban8a1df202011-05-10 09:26:43 +00004656 res = NETCON_send(request->netconn, ascii_req, len, 0, &cnt);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004657 heap_free( ascii_req );
Jacek Caban8a1df202011-05-10 09:26:43 +00004658 if(res != ERROR_SUCCESS) {
4659 TRACE("send failed: %u\n", res);
4660 if(!reusing_connection)
4661 break;
4662 http_release_netconn(request, FALSE);
4663 loop_next = TRUE;
4664 continue;
4665 }
David Hammerton852c7ae2003-06-20 23:26:56 +00004666
Juan Lang20980062011-03-01 11:18:22 -08004667 request->bytesWritten = dwOptionalLength;
Hans Leidekker0fabf542009-04-08 15:21:28 +02004668
Juan Langb49b2432011-03-01 10:59:39 -08004669 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004670 INTERNET_STATUS_REQUEST_SENT,
4671 &len, sizeof(DWORD));
David Hammerton852c7ae2003-06-20 23:26:56 +00004672
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004673 if (bEndRequest)
4674 {
Rob Shearmanac1b5272007-01-04 18:21:49 +00004675 DWORD dwBufferSize;
Rob Shearmancb289692007-06-05 19:49:58 +01004676 DWORD dwStatusCode;
Rob Shearmanac1b5272007-01-04 18:21:49 +00004677
Juan Langb49b2432011-03-01 10:59:39 -08004678 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004679 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
4680
Juan Langb49b2432011-03-01 10:59:39 -08004681 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Piotr Cabanee684732010-06-29 12:20:51 +02004682 /* FIXME: We should know that connection is closed before sending
4683 * headers. Otherwise wrong callbacks are executed */
4684 if(!responseLen && reusing_connection) {
4685 TRACE("Connection closed by server, reconnecting\n");
Jacek Caban8a1df202011-05-10 09:26:43 +00004686 http_release_netconn(request, FALSE);
Piotr Cabanee684732010-06-29 12:20:51 +02004687 loop_next = TRUE;
4688 continue;
4689 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004690
Juan Langb49b2432011-03-01 10:59:39 -08004691 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004692 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
4693 sizeof(DWORD));
Rob Shearman4319ec62006-12-07 00:53:27 +00004694
Jacek Caban8a1df202011-05-10 09:26:43 +00004695 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08004696 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004697 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08004698 HTTP_ProcessLastModified(request);
Rob Shearman4319ec62006-12-07 00:53:27 +00004699
Rob Shearmancb289692007-06-05 19:49:58 +01004700 dwBufferSize = sizeof(dwStatusCode);
Juan Langb49b2432011-03-01 10:59:39 -08004701 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
Jacek Caban9823c232009-12-14 02:27:29 +01004702 &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS)
Rob Shearmancb289692007-06-05 19:49:58 +01004703 dwStatusCode = 0;
4704
Jacek Cabana890e3a2011-05-13 13:48:15 +02004705 res = set_content_length(request, dwStatusCode);
4706 if(res != ERROR_SUCCESS)
4707 goto lend;
4708 if(!request->contentLength)
4709 http_release_netconn(request, TRUE);
4710
Juan Langb49b2432011-03-01 10:59:39 -08004711 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
Rob Shearman4319ec62006-12-07 00:53:27 +00004712 {
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004713 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
Rob Shearman9efe0832007-01-12 19:19:18 -06004714 dwBufferSize=sizeof(szNewLocation);
Hans Leidekker94deb852010-08-27 10:50:59 +02004715 if ((dwStatusCode == HTTP_STATUS_REDIRECT ||
4716 dwStatusCode == HTTP_STATUS_MOVED ||
Karsten Elfenbein5b173cb2011-05-08 12:29:06 +02004717 dwStatusCode == HTTP_STATUS_REDIRECT_KEEP_VERB ||
Hans Leidekker94deb852010-08-27 10:50:59 +02004718 dwStatusCode == HTTP_STATUS_REDIRECT_METHOD) &&
Juan Langb49b2432011-03-01 10:59:39 -08004719 HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS)
Rob Shearman4319ec62006-12-07 00:53:27 +00004720 {
Hans Leidekker14d4d192011-06-01 11:50:32 +02004721 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
4722 dwStatusCode != HTTP_STATUS_REDIRECT_KEEP_VERB)
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004723 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004724 heap_free(request->verb);
Juan Lang20980062011-03-01 11:18:22 -08004725 request->verb = heap_strdupW(szGET);
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004726 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004727 drain_content(request);
Juan Langb49b2432011-03-01 10:59:39 -08004728 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
Rob Shearman4319ec62006-12-07 00:53:27 +00004729 {
Juan Langb49b2432011-03-01 10:59:39 -08004730 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004731 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
Juan Langb49b2432011-03-01 10:59:39 -08004732 res = HTTP_HandleRedirect(request, new_url);
Jacek Cabana9ecdc62009-12-03 14:49:56 +01004733 if (res == ERROR_SUCCESS)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004734 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004735 heap_free(requestString);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004736 loop_next = TRUE;
4737 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004738 heap_free( new_url );
Rob Shearman4319ec62006-12-07 00:53:27 +00004739 }
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004740 redirected = TRUE;
Rob Shearman4319ec62006-12-07 00:53:27 +00004741 }
4742 }
Juan Langb49b2432011-03-01 10:59:39 -08004743 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004744 {
Rob Shearman4b507682007-05-21 14:26:26 +01004745 WCHAR szAuthValue[2048];
4746 dwBufferSize=2048;
Rob Shearmancb289692007-06-05 19:49:58 +01004747 if (dwStatusCode == HTTP_STATUS_DENIED)
Rob Shearman4b507682007-05-21 14:26:26 +01004748 {
Juan Langb49b2432011-03-01 10:59:39 -08004749 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Rob Shearman4b507682007-05-21 14:26:26 +01004750 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004751 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004752 {
Juan Langb49b2432011-03-01 10:59:39 -08004753 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004754 &request->authInfo,
4755 request->session->userName,
4756 request->session->password,
Aric Stewartfc508932009-10-12 14:24:18 -05004757 Host->lpszValue))
Rob Shearmancb289692007-06-05 19:49:58 +01004758 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004759 heap_free(requestString);
Rob Shearmancb289692007-06-05 19:49:58 +01004760 loop_next = TRUE;
4761 break;
4762 }
4763 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004764
4765 if(!loop_next) {
4766 TRACE("Cleaning wrong authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004767 destroy_authinfo(request->authInfo);
4768 request->authInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004769 }
Rob Shearmancb289692007-06-05 19:49:58 +01004770 }
4771 if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
4772 {
4773 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004774 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearmancb289692007-06-05 19:49:58 +01004775 {
Juan Langb49b2432011-03-01 10:59:39 -08004776 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004777 &request->proxyAuthInfo,
4778 request->session->appInfo->proxyUsername,
4779 request->session->appInfo->proxyPassword,
Aric Stewartfc508932009-10-12 14:24:18 -05004780 NULL))
Rob Shearman4b507682007-05-21 14:26:26 +01004781 {
4782 loop_next = TRUE;
4783 break;
4784 }
4785 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004786
4787 if(!loop_next) {
4788 TRACE("Cleaning wrong proxy authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004789 destroy_authinfo(request->proxyAuthInfo);
4790 request->proxyAuthInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004791 }
Rob Shearman4b507682007-05-21 14:26:26 +01004792 }
4793 }
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004794 }
4795 else
Jacek Cabanc952e812009-12-03 14:48:54 +01004796 res = ERROR_SUCCESS;
David Hammerton852c7ae2003-06-20 23:26:56 +00004797 }
4798 while (loop_next);
Aric Stewartff9b9d42002-06-21 23:59:49 +00004799
Juan Lang666353d2011-03-02 10:06:37 -08004800 if(res == ERROR_SUCCESS)
4801 HTTP_CacheRequest(request);
Jacek Caband7a49e82008-02-13 13:32:49 +01004802
Ulrich Czekallac2757242000-06-11 20:04:44 +00004803lend:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004804 heap_free(requestString);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004805
Alberto Massaribc8bd722002-12-06 23:20:31 +00004806 /* TODO: send notification for P3P header */
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00004807
Juan Lang20980062011-03-01 11:18:22 -08004808 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Hans Leidekker3a711fb2009-04-08 15:22:26 +02004809 {
Jacek Caban8e37ed52011-06-10 14:47:16 +02004810 if (res == ERROR_SUCCESS) {
4811 if(request->contentLength && request->bytesWritten == request->bytesToWrite)
4812 HTTP_ReceiveRequestData(request, TRUE);
4813 else
4814 send_request_complete(request,
4815 request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0);
4816 }else {
4817 send_request_complete(request, 0, res);
4818 }
Jacek Caban12931062009-01-13 00:28:25 +01004819 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00004820
4821 TRACE("<--\n");
Jacek Cabanc952e812009-12-03 14:48:54 +01004822 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00004823}
4824
Ulrich Czekallac2757242000-06-11 20:04:44 +00004825/***********************************************************************
Jacek Caban34fcbb52009-11-30 20:01:17 +01004826 *
4827 * Helper functions for the HttpSendRequest(Ex) functions
4828 *
4829 */
4830static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
4831{
4832 struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08004833 http_request_t *request = (http_request_t*) workRequest->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004834
Juan Langb49b2432011-03-01 10:59:39 -08004835 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004836
Juan Langb49b2432011-03-01 10:59:39 -08004837 HTTP_HttpSendRequestW(request, req->lpszHeader,
Jacek Caban34fcbb52009-11-30 20:01:17 +01004838 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
4839 req->dwContentLength, req->bEndRequest);
4840
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004841 heap_free(req->lpszHeader);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004842}
4843
4844
Juan Langb49b2432011-03-01 10:59:39 -08004845static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004846{
Jacek Caban34fcbb52009-11-30 20:01:17 +01004847 INT responseLen;
Jacek Cabana890e3a2011-05-13 13:48:15 +02004848 DWORD dwCode, dwCodeLength;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004849 DWORD dwBufferSize;
Jacek Caban741b6612009-12-03 14:49:29 +01004850 DWORD res = ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004851
Juan Langb49b2432011-03-01 10:59:39 -08004852 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01004853 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
4854
Juan Langb49b2432011-03-01 10:59:39 -08004855 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Jacek Caban741b6612009-12-03 14:49:29 +01004856 if (!responseLen)
4857 res = ERROR_HTTP_HEADER_NOT_FOUND;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004858
Juan Langb49b2432011-03-01 10:59:39 -08004859 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01004860 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
4861
4862 /* process cookies here. Is this right? */
Jacek Caban8a1df202011-05-10 09:26:43 +00004863 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08004864 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004865 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08004866 HTTP_ProcessLastModified(request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004867
Jacek Cabana890e3a2011-05-13 13:48:15 +02004868 dwCodeLength = sizeof(dwCode);
4869 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
4870 &dwCode,&dwCodeLength,NULL) != ERROR_SUCCESS)
4871 dwCode = 0;
4872
4873 if ((res = set_content_length( request, dwCode )) == ERROR_SUCCESS) {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02004874 if(!request->contentLength)
Jacek Caban8a1df202011-05-10 09:26:43 +00004875 http_release_netconn(request, TRUE);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02004876 }
Jacek Caban34fcbb52009-11-30 20:01:17 +01004877
Jacek Cabanccd11eb2011-04-02 15:20:33 +02004878 if (res == ERROR_SUCCESS && !(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
Jacek Caban34fcbb52009-11-30 20:01:17 +01004879 {
Jacek Cabana890e3a2011-05-13 13:48:15 +02004880 if (dwCode == HTTP_STATUS_REDIRECT ||
Karsten Elfenbein5b173cb2011-05-08 12:29:06 +02004881 dwCode == HTTP_STATUS_MOVED ||
4882 dwCode == HTTP_STATUS_REDIRECT_METHOD ||
Jacek Cabana890e3a2011-05-13 13:48:15 +02004883 dwCode == HTTP_STATUS_REDIRECT_KEEP_VERB)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004884 {
4885 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
4886 dwBufferSize=sizeof(szNewLocation);
Juan Langb49b2432011-03-01 10:59:39 -08004887 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004888 {
Hans Leidekker14d4d192011-06-01 11:50:32 +02004889 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
4890 dwCode != HTTP_STATUS_REDIRECT_KEEP_VERB)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004891 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004892 heap_free(request->verb);
Juan Lang20980062011-03-01 11:18:22 -08004893 request->verb = heap_strdupW(szGET);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004894 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004895 drain_content(request);
Juan Langb49b2432011-03-01 10:59:39 -08004896 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
Jacek Caban34fcbb52009-11-30 20:01:17 +01004897 {
Juan Langb49b2432011-03-01 10:59:39 -08004898 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
Jacek Caban34fcbb52009-11-30 20:01:17 +01004899 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
Juan Langb49b2432011-03-01 10:59:39 -08004900 res = HTTP_HandleRedirect(request, new_url);
Jacek Cabana9ecdc62009-12-03 14:49:56 +01004901 if (res == ERROR_SUCCESS)
Juan Langb49b2432011-03-01 10:59:39 -08004902 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004903 heap_free( new_url );
Jacek Caban34fcbb52009-11-30 20:01:17 +01004904 }
4905 }
4906 }
4907 }
4908
Jacek Cabanc0293df2011-06-10 14:47:04 +02004909 if (res == ERROR_SUCCESS && request->contentLength)
Jacek Caban685daf22011-03-17 01:01:49 +01004910 HTTP_ReceiveRequestData(request, TRUE);
Jacek Cabanc0293df2011-06-10 14:47:04 +02004911 else
Jacek Caban8e37ed52011-06-10 14:47:16 +02004912 send_request_complete(request, res == ERROR_SUCCESS, res);
Jacek Caban685daf22011-03-17 01:01:49 +01004913
Jacek Caban741b6612009-12-03 14:49:29 +01004914 return res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004915}
4916
4917/***********************************************************************
4918 * HttpEndRequestA (WININET.@)
4919 *
4920 * Ends an HTTP request that was started by HttpSendRequestEx
4921 *
4922 * RETURNS
4923 * TRUE if successful
4924 * FALSE on failure
4925 *
4926 */
4927BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
4928 LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
4929{
4930 TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
4931
4932 if (lpBuffersOut)
4933 {
Jacek Cabane1958a62009-12-21 13:58:18 +01004934 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004935 return FALSE;
4936 }
4937
4938 return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
4939}
4940
4941static void AsyncHttpEndRequestProc(WORKREQUEST *work)
4942{
4943 struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08004944 http_request_t *request = (http_request_t*)work->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004945
Juan Langb49b2432011-03-01 10:59:39 -08004946 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004947
Juan Langb49b2432011-03-01 10:59:39 -08004948 HTTP_HttpEndRequestW(request, req->dwFlags, req->dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004949}
4950
4951/***********************************************************************
4952 * HttpEndRequestW (WININET.@)
4953 *
4954 * Ends an HTTP request that was started by HttpSendRequestEx
4955 *
4956 * RETURNS
4957 * TRUE if successful
4958 * FALSE on failure
4959 *
4960 */
4961BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
4962 LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
4963{
Juan Langb49b2432011-03-01 10:59:39 -08004964 http_request_t *request;
Jacek Caban741b6612009-12-03 14:49:29 +01004965 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004966
Jacek Cabanc0293df2011-06-10 14:47:04 +02004967 TRACE("%p %p %x %lx -->\n", hRequest, lpBuffersOut, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004968
4969 if (lpBuffersOut)
4970 {
Jacek Caban741b6612009-12-03 14:49:29 +01004971 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004972 return FALSE;
4973 }
4974
Juan Langb49b2432011-03-01 10:59:39 -08004975 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01004976
Juan Langb49b2432011-03-01 10:59:39 -08004977 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004978 {
Jacek Caban741b6612009-12-03 14:49:29 +01004979 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
Juan Langb49b2432011-03-01 10:59:39 -08004980 if (request)
4981 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01004982 return FALSE;
4983 }
Juan Langb49b2432011-03-01 10:59:39 -08004984 request->hdr.dwFlags |= dwFlags;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004985
Juan Lang20980062011-03-01 11:18:22 -08004986 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004987 {
4988 WORKREQUEST work;
Juan Langb49b2432011-03-01 10:59:39 -08004989 struct WORKREQ_HTTPENDREQUESTW *work_endrequest;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004990
4991 work.asyncproc = AsyncHttpEndRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08004992 work.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01004993
Juan Langb49b2432011-03-01 10:59:39 -08004994 work_endrequest = &work.u.HttpEndRequestW;
4995 work_endrequest->dwFlags = dwFlags;
4996 work_endrequest->dwContext = dwContext;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004997
4998 INTERNET_AsyncCall(&work);
Jacek Caban741b6612009-12-03 14:49:29 +01004999 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005000 }
5001 else
Juan Langb49b2432011-03-01 10:59:39 -08005002 res = HTTP_HttpEndRequestW(request, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005003
Juan Langb49b2432011-03-01 10:59:39 -08005004 WININET_Release( &request->hdr );
Jacek Caban741b6612009-12-03 14:49:29 +01005005 TRACE("%u <--\n", res);
5006 if(res != ERROR_SUCCESS)
5007 SetLastError(res);
5008 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005009}
5010
5011/***********************************************************************
5012 * HttpSendRequestExA (WININET.@)
5013 *
5014 * Sends the specified request to the HTTP server and allows chunked
5015 * transfers.
5016 *
5017 * RETURNS
5018 * Success: TRUE
5019 * Failure: FALSE, call GetLastError() for more information.
5020 */
5021BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
5022 LPINTERNET_BUFFERSA lpBuffersIn,
5023 LPINTERNET_BUFFERSA lpBuffersOut,
5024 DWORD dwFlags, DWORD_PTR dwContext)
5025{
5026 INTERNET_BUFFERSW BuffersInW;
5027 BOOL rc = FALSE;
5028 DWORD headerlen;
5029 LPWSTR header = NULL;
5030
5031 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5032 lpBuffersOut, dwFlags, dwContext);
5033
5034 if (lpBuffersIn)
5035 {
5036 BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
5037 if (lpBuffersIn->lpcszHeader)
5038 {
5039 headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
5040 lpBuffersIn->dwHeadersLength,0,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005041 header = heap_alloc(headerlen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005042 if (!(BuffersInW.lpcszHeader = header))
5043 {
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005044 SetLastError(ERROR_OUTOFMEMORY);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005045 return FALSE;
5046 }
5047 BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
5048 lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
5049 header, headerlen);
5050 }
5051 else
5052 BuffersInW.lpcszHeader = NULL;
5053 BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
5054 BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
5055 BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
5056 BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
5057 BuffersInW.Next = NULL;
5058 }
5059
5060 rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
5061
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005062 heap_free(header);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005063 return rc;
5064}
5065
5066/***********************************************************************
5067 * HttpSendRequestExW (WININET.@)
5068 *
5069 * Sends the specified request to the HTTP server and allows chunked
5070 * transfers
5071 *
5072 * RETURNS
5073 * Success: TRUE
5074 * Failure: FALSE, call GetLastError() for more information.
5075 */
5076BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
5077 LPINTERNET_BUFFERSW lpBuffersIn,
5078 LPINTERNET_BUFFERSW lpBuffersOut,
5079 DWORD dwFlags, DWORD_PTR dwContext)
5080{
Juan Langb49b2432011-03-01 10:59:39 -08005081 http_request_t *request;
5082 http_session_t *session;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005083 appinfo_t *hIC;
Jacek Cabanc952e812009-12-03 14:48:54 +01005084 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005085
5086 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5087 lpBuffersOut, dwFlags, dwContext);
5088
Juan Langb49b2432011-03-01 10:59:39 -08005089 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005090
Juan Langb49b2432011-03-01 10:59:39 -08005091 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005092 {
Jacek Cabanc952e812009-12-03 14:48:54 +01005093 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005094 goto lend;
5095 }
5096
Juan Lang20980062011-03-01 11:18:22 -08005097 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005098 assert(session->hdr.htype == WH_HHTTPSESSION);
Juan Lang8e050392011-03-01 11:02:14 -08005099 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005100 assert(hIC->hdr.htype == WH_HINIT);
5101
5102 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5103 {
5104 WORKREQUEST workRequest;
5105 struct WORKREQ_HTTPSENDREQUESTW *req;
5106
5107 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005108 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005109 req = &workRequest.u.HttpSendRequestW;
5110 if (lpBuffersIn)
5111 {
5112 DWORD size = 0;
5113
5114 if (lpBuffersIn->lpcszHeader)
5115 {
5116 if (lpBuffersIn->dwHeadersLength == ~0u)
5117 size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
5118 else
5119 size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
5120
Jacek Caban354a74e2011-04-21 13:39:03 +02005121 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005122 memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
5123 }
5124 else req->lpszHeader = NULL;
5125
5126 req->dwHeaderLength = size / sizeof(WCHAR);
5127 req->lpOptional = lpBuffersIn->lpvBuffer;
5128 req->dwOptionalLength = lpBuffersIn->dwBufferLength;
5129 req->dwContentLength = lpBuffersIn->dwBufferTotal;
5130 }
5131 else
5132 {
5133 req->lpszHeader = NULL;
5134 req->dwHeaderLength = 0;
5135 req->lpOptional = NULL;
5136 req->dwOptionalLength = 0;
5137 req->dwContentLength = 0;
5138 }
5139
5140 req->bEndRequest = FALSE;
5141
5142 INTERNET_AsyncCall(&workRequest);
5143 /*
5144 * This is from windows.
5145 */
Jacek Cabanc952e812009-12-03 14:48:54 +01005146 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005147 }
5148 else
5149 {
5150 if (lpBuffersIn)
Juan Langb49b2432011-03-01 10:59:39 -08005151 res = HTTP_HttpSendRequestW(request, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005152 lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
5153 lpBuffersIn->dwBufferTotal, FALSE);
5154 else
Juan Langb49b2432011-03-01 10:59:39 -08005155 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, FALSE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005156 }
5157
5158lend:
Juan Langb49b2432011-03-01 10:59:39 -08005159 if ( request )
5160 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005161
5162 TRACE("<---\n");
Hans Leidekker68453a52009-12-21 11:13:44 +01005163 SetLastError(res);
Jacek Cabanc952e812009-12-03 14:48:54 +01005164 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005165}
5166
5167/***********************************************************************
5168 * HttpSendRequestW (WININET.@)
5169 *
5170 * Sends the specified request to the HTTP server
5171 *
5172 * RETURNS
5173 * TRUE on success
5174 * FALSE on failure
5175 *
5176 */
5177BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
5178 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5179{
Juan Langb49b2432011-03-01 10:59:39 -08005180 http_request_t *request;
5181 http_session_t *session = NULL;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005182 appinfo_t *hIC = NULL;
5183 DWORD res = ERROR_SUCCESS;
5184
5185 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
5186 debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
5187
Juan Langb49b2432011-03-01 10:59:39 -08005188 request = (http_request_t*) get_handle_object( hHttpRequest );
5189 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005190 {
5191 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5192 goto lend;
5193 }
5194
Juan Lang20980062011-03-01 11:18:22 -08005195 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005196 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005197 {
5198 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5199 goto lend;
5200 }
5201
Juan Lang8e050392011-03-01 11:02:14 -08005202 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005203 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
5204 {
5205 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5206 goto lend;
5207 }
5208
5209 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5210 {
5211 WORKREQUEST workRequest;
5212 struct WORKREQ_HTTPSENDREQUESTW *req;
5213
5214 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005215 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005216 req = &workRequest.u.HttpSendRequestW;
5217 if (lpszHeaders)
5218 {
5219 DWORD size;
5220
5221 if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
5222 else size = dwHeaderLength * sizeof(WCHAR);
5223
Jacek Caban354a74e2011-04-21 13:39:03 +02005224 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005225 memcpy(req->lpszHeader, lpszHeaders, size);
5226 }
5227 else
5228 req->lpszHeader = 0;
5229 req->dwHeaderLength = dwHeaderLength;
5230 req->lpOptional = lpOptional;
5231 req->dwOptionalLength = dwOptionalLength;
5232 req->dwContentLength = dwOptionalLength;
5233 req->bEndRequest = TRUE;
5234
5235 INTERNET_AsyncCall(&workRequest);
5236 /*
5237 * This is from windows.
5238 */
5239 res = ERROR_IO_PENDING;
5240 }
5241 else
5242 {
Juan Langb49b2432011-03-01 10:59:39 -08005243 res = HTTP_HttpSendRequestW(request, lpszHeaders,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005244 dwHeaderLength, lpOptional, dwOptionalLength,
5245 dwOptionalLength, TRUE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005246 }
5247lend:
Juan Langb49b2432011-03-01 10:59:39 -08005248 if( request )
5249 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005250
Hans Leidekker68453a52009-12-21 11:13:44 +01005251 SetLastError(res);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005252 return res == ERROR_SUCCESS;
5253}
5254
5255/***********************************************************************
5256 * HttpSendRequestA (WININET.@)
5257 *
5258 * Sends the specified request to the HTTP server
5259 *
5260 * RETURNS
5261 * TRUE on success
5262 * FALSE on failure
5263 *
5264 */
5265BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
5266 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5267{
5268 BOOL result;
5269 LPWSTR szHeaders=NULL;
5270 DWORD nLen=dwHeaderLength;
5271 if(lpszHeaders!=NULL)
5272 {
5273 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005274 szHeaders = heap_alloc(nLen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005275 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
5276 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005277 result = HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
5278 heap_free(szHeaders);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005279 return result;
5280}
5281
5282/***********************************************************************
Jacek Caban5a535d62008-02-26 20:20:41 +01005283 * HTTPSESSION_Destroy (internal)
5284 *
5285 * Deallocate session handle
5286 *
5287 */
Jacek Caban44d633a2009-07-07 21:46:09 +02005288static void HTTPSESSION_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01005289{
Juan Langb49b2432011-03-01 10:59:39 -08005290 http_session_t *session = (http_session_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01005291
Juan Langb49b2432011-03-01 10:59:39 -08005292 TRACE("%p\n", session);
Jacek Caban5a535d62008-02-26 20:20:41 +01005293
Juan Lang8e050392011-03-01 11:02:14 -08005294 WININET_Release(&session->appInfo->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01005295
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005296 heap_free(session->hostName);
5297 heap_free(session->serverName);
5298 heap_free(session->password);
5299 heap_free(session->userName);
Jacek Caban5a535d62008-02-26 20:20:41 +01005300}
5301
Jacek Caban44d633a2009-07-07 21:46:09 +02005302static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01005303{
5304 switch(option) {
5305 case INTERNET_OPTION_HANDLE_TYPE:
5306 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
5307
5308 if (*size < sizeof(ULONG))
5309 return ERROR_INSUFFICIENT_BUFFER;
5310
5311 *size = sizeof(DWORD);
5312 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
5313 return ERROR_SUCCESS;
5314 }
5315
Hans Leidekker80dd3672010-05-25 12:19:32 +02005316 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01005317}
Jacek Caban5a535d62008-02-26 20:20:41 +01005318
Jacek Caban44d633a2009-07-07 21:46:09 +02005319static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Hans Leidekker8c201242008-09-24 16:54:37 +02005320{
Jacek Cabane9f4a402009-07-13 01:41:18 +02005321 http_session_t *ses = (http_session_t*)hdr;
Hans Leidekker8c201242008-09-24 16:54:37 +02005322
5323 switch(option) {
5324 case INTERNET_OPTION_USERNAME:
5325 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005326 heap_free(ses->userName);
Juan Lang8e050392011-03-01 11:02:14 -08005327 if (!(ses->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005328 return ERROR_SUCCESS;
5329 }
5330 case INTERNET_OPTION_PASSWORD:
5331 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005332 heap_free(ses->password);
Juan Lang8e050392011-03-01 11:02:14 -08005333 if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005334 return ERROR_SUCCESS;
5335 }
5336 default: break;
5337 }
5338
5339 return ERROR_INTERNET_INVALID_OPTION;
5340}
5341
Jacek Caban44d633a2009-07-07 21:46:09 +02005342static const object_vtbl_t HTTPSESSIONVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005343 HTTPSESSION_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01005344 NULL,
Jacek Cabane2933c22008-03-12 02:23:20 +01005345 HTTPSESSION_QueryOption,
Hans Leidekker8c201242008-09-24 16:54:37 +02005346 HTTPSESSION_SetOption,
Jacek Caban8c45eec2008-02-27 18:55:09 +01005347 NULL,
Jacek Caban33141842008-02-29 12:57:57 +01005348 NULL,
Jacek Caban3b4ca692008-03-02 19:35:11 +01005349 NULL,
Jacek Caband597fd12008-03-03 18:07:20 +01005350 NULL,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005351 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01005352};
5353
5354
5355/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005356 * HTTP_Connect (internal)
5357 *
5358 * Create http session handle
5359 *
5360 * RETURNS
5361 * HINTERNET a session handle on success
5362 * NULL on failure
5363 *
5364 */
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005365DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
Juan Lang8e050392011-03-01 11:02:14 -08005366 INTERNET_PORT serverPort, LPCWSTR lpszUserName,
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005367 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
5368 DWORD dwInternalFlags, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005369{
Juan Langb49b2432011-03-01 10:59:39 -08005370 http_session_t *session = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005371
Aric Stewartff9b9d42002-06-21 23:59:49 +00005372 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005373
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005374 if (!lpszServerName || !lpszServerName[0])
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005375 return ERROR_INVALID_PARAMETER;
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005376
Mike McCormack3a1391b2004-07-19 21:49:39 +00005377 assert( hIC->hdr.htype == WH_HINIT );
Ulrich Czekallac2757242000-06-11 20:04:44 +00005378
Juan Langb49b2432011-03-01 10:59:39 -08005379 session = alloc_object(&hIC->hdr, &HTTPSESSIONVtbl, sizeof(http_session_t));
5380 if (!session)
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005381 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005382
Aric Stewartff9b9d42002-06-21 23:59:49 +00005383 /*
5384 * According to my tests. The name is not resolved until a request is sent
5385 */
Ulrich Czekallac2757242000-06-11 20:04:44 +00005386
Juan Langb49b2432011-03-01 10:59:39 -08005387 session->hdr.htype = WH_HHTTPSESSION;
5388 session->hdr.dwFlags = dwFlags;
5389 session->hdr.dwContext = dwContext;
5390 session->hdr.dwInternalFlags |= dwInternalFlags;
Mike McCormack3a1391b2004-07-19 21:49:39 +00005391
Jacek Cabanc2506172006-10-29 18:48:48 +01005392 WININET_AddRef( &hIC->hdr );
Juan Lang8e050392011-03-01 11:02:14 -08005393 session->appInfo = hIC;
Juan Langb49b2432011-03-01 10:59:39 -08005394 list_add_head( &hIC->hdr.children, &session->hdr.entry );
Jacek Cabanc2506172006-10-29 18:48:48 +01005395
Juan Lang72431562011-03-01 11:00:49 -08005396 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) {
5397 if(hIC->proxyBypass)
Dominik Strasser94c02fe2003-04-14 21:32:36 +00005398 FIXME("Proxy bypass is ignored.\n");
5399 }
Juan Lang8e050392011-03-01 11:02:14 -08005400 session->serverName = heap_strdupW(lpszServerName);
5401 session->hostName = heap_strdupW(lpszServerName);
Robert Shearmanef209362006-03-10 12:28:52 +00005402 if (lpszUserName && lpszUserName[0])
Juan Lang8e050392011-03-01 11:02:14 -08005403 session->userName = heap_strdupW(lpszUserName);
Rob Shearman4b507682007-05-21 14:26:26 +01005404 if (lpszPassword && lpszPassword[0])
Juan Lang8e050392011-03-01 11:02:14 -08005405 session->password = heap_strdupW(lpszPassword);
5406 session->serverPort = serverPort;
5407 session->hostPort = serverPort;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005408
Kevin Koltzau917df922004-05-13 05:17:25 +00005409 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
Juan Langb49b2432011-03-01 10:59:39 -08005410 if (!(session->hdr.dwInternalFlags & INET_OPENURL))
Ulrich Czekallac2757242000-06-11 20:04:44 +00005411 {
Robert Shearmande2666f2005-11-29 10:44:05 +01005412 INTERNET_SendCallback(&hIC->hdr, dwContext,
Juan Langb49b2432011-03-01 10:59:39 -08005413 INTERNET_STATUS_HANDLE_CREATED, &session->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01005414 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005415 }
5416
Aric Stewartff9b9d42002-06-21 23:59:49 +00005417/*
Francois Gouget93416cd2005-03-23 13:15:18 +00005418 * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
Aric Stewartff9b9d42002-06-21 23:59:49 +00005419 * windows
5420 */
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00005421
Juan Langb49b2432011-03-01 10:59:39 -08005422 TRACE("%p --> %p\n", hIC, session);
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005423
Juan Langb49b2432011-03-01 10:59:39 -08005424 *ret = session->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01005425 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005426}
5427
Ulrich Czekallac2757242000-06-11 20:04:44 +00005428/***********************************************************************
Alexandre Julliard48243e32004-07-15 18:57:32 +00005429 * HTTP_clear_response_headers (internal)
5430 *
5431 * clear out any old response headers
5432 */
Juan Langb49b2432011-03-01 10:59:39 -08005433static void HTTP_clear_response_headers( http_request_t *request )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005434{
5435 DWORD i;
5436
Juan Langb49b2432011-03-01 10:59:39 -08005437 for( i=0; i<request->nCustHeaders; i++)
Alexandre Julliard48243e32004-07-15 18:57:32 +00005438 {
Juan Lang20980062011-03-01 11:18:22 -08005439 if( !request->custHeaders[i].lpszField )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005440 continue;
Juan Lang20980062011-03-01 11:18:22 -08005441 if( !request->custHeaders[i].lpszValue )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005442 continue;
Juan Lang20980062011-03-01 11:18:22 -08005443 if ( request->custHeaders[i].wFlags & HDR_ISREQUEST )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005444 continue;
Juan Langb49b2432011-03-01 10:59:39 -08005445 HTTP_DeleteCustomHeader( request, i );
Robert Shearman7707a762005-03-10 11:14:24 +00005446 i--;
Alexandre Julliard48243e32004-07-15 18:57:32 +00005447 }
5448}
5449
5450/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005451 * HTTP_GetResponseHeaders (internal)
5452 *
5453 * Read server response
5454 *
5455 * RETURNS
5456 *
5457 * TRUE on success
5458 * FALSE on error
5459 */
Juan Langb49b2432011-03-01 10:59:39 -08005460static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005461{
5462 INT cbreaks = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005463 WCHAR buffer[MAX_REPLY_LEN];
Ulrich Czekallac2757242000-06-11 20:04:44 +00005464 DWORD buflen = MAX_REPLY_LEN;
5465 BOOL bSuccess = FALSE;
Aric Stewartff9b9d42002-06-21 23:59:49 +00005466 INT rc = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005467 char bufferA[MAX_REPLY_LEN];
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005468 LPWSTR status_code = NULL, status_text = NULL;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005469 DWORD cchMaxRawHeaders = 1024;
Hans Leidekker911d0df2010-02-23 13:03:37 +01005470 LPWSTR lpszRawHeaders = NULL;
Eric van Beurden5caf8092009-06-04 10:52:16 -04005471 LPWSTR temp;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005472 DWORD cchRawHeaders = 0;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005473 BOOL codeHundred = FALSE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005474
Aric Stewartff9b9d42002-06-21 23:59:49 +00005475 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005476
Jacek Caban8a1df202011-05-10 09:26:43 +00005477 if(!request->netconn)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005478 goto lend;
5479
Hans Leidekker2617fb62008-02-17 20:41:56 +01005480 do {
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005481 static const WCHAR szHundred[] = {'1','0','0',0};
Hans Leidekker2617fb62008-02-17 20:41:56 +01005482 /*
Hans Leidekker2617fb62008-02-17 20:41:56 +01005483 * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
5484 */
Hans Leidekker96b639d2009-03-04 12:42:43 +01005485 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005486 if (!read_line(request, bufferA, &buflen))
Hans Leidekker2617fb62008-02-17 20:41:56 +01005487 goto lend;
Piotr Cabanee684732010-06-29 12:20:51 +02005488
5489 /* clear old response headers (eg. from a redirect response) */
5490 if (clear) {
Juan Langb49b2432011-03-01 10:59:39 -08005491 HTTP_clear_response_headers( request );
Piotr Cabanee684732010-06-29 12:20:51 +02005492 clear = FALSE;
5493 }
5494
Hans Leidekker96b639d2009-03-04 12:42:43 +01005495 rc += buflen;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005496 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005497 /* check is this a status code line? */
5498 if (!strncmpW(buffer, g_szHttp1_0, 4))
5499 {
5500 /* split the version from the status code */
5501 status_code = strchrW( buffer, ' ' );
5502 if( !status_code )
5503 goto lend;
5504 *status_code++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005505
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005506 /* split the status code from the status text */
5507 status_text = strchrW( status_code, ' ' );
5508 if( !status_text )
5509 goto lend;
5510 *status_text++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005511
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005512 TRACE("version [%s] status code [%s] status text [%s]\n",
5513 debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
Hans Leidekker2617fb62008-02-17 20:41:56 +01005514
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005515 codeHundred = (!strcmpW(status_code, szHundred));
5516 }
5517 else if (!codeHundred)
5518 {
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005519 WARN("No status line at head of response (%s)\n", debugstr_w(buffer));
5520
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005521 heap_free(request->version);
5522 heap_free(request->statusText);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005523
Juan Lang20980062011-03-01 11:18:22 -08005524 request->version = heap_strdupW(g_szHttp1_0);
5525 request->statusText = heap_strdupW(szOK);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005526
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005527 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005528 request->rawHeaders = heap_strdupW(szDefaultHeader);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005529
5530 bSuccess = TRUE;
Erik Inge Bolsø5af1a492009-09-29 21:50:12 +02005531 goto lend;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005532 }
5533 } while (codeHundred);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005534
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005535 /* Add status code */
Juan Langb49b2432011-03-01 10:59:39 -08005536 HTTP_ProcessHeader(request, szStatus, status_code,
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005537 HTTP_ADDHDR_FLAG_REPLACE);
5538
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005539 heap_free(request->version);
5540 heap_free(request->statusText);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005541
Juan Lang20980062011-03-01 11:18:22 -08005542 request->version = heap_strdupW(buffer);
5543 request->statusText = heap_strdupW(status_text);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005544
5545 /* Restore the spaces */
5546 *(status_code-1) = ' ';
5547 *(status_text-1) = ' ';
5548
Robert Shearmandee87512004-07-19 20:09:20 +00005549 /* regenerate raw headers */
Jacek Caban354a74e2011-04-21 13:39:03 +02005550 lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR));
Hans Leidekker911d0df2010-02-23 13:03:37 +01005551 if (!lpszRawHeaders) goto lend;
5552
Robert Shearmandee87512004-07-19 20:09:20 +00005553 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
Robert Shearmandee87512004-07-19 20:09:20 +00005554 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005555 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden5caf8092009-06-04 10:52:16 -04005556 if (temp == NULL) goto lend;
5557 lpszRawHeaders = temp;
Robert Shearmandee87512004-07-19 20:09:20 +00005558 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5559 cchRawHeaders += (buflen-1);
5560 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5561 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5562 lpszRawHeaders[cchRawHeaders] = '\0';
5563
Ulrich Czekallac2757242000-06-11 20:04:44 +00005564 /* Parse each response line */
5565 do
5566 {
5567 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005568 if (read_line(request, bufferA, &buflen))
Robert Shearmanb72a6822004-09-23 22:53:50 +00005569 {
5570 LPWSTR * pFieldAndValue;
5571
Francois Gougetda8b3dd2005-01-26 21:09:04 +00005572 TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
Hans Leidekker100ee0a2009-03-04 12:44:22 +01005573
5574 if (!bufferA[0]) break;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005575 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Robert Shearmandee87512004-07-19 20:09:20 +00005576
Robert Shearmanb72a6822004-09-23 22:53:50 +00005577 pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
Eric van Beurden59a21782009-06-04 10:52:59 -04005578 if (pFieldAndValue)
5579 {
5580 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
5581 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005582 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden59a21782009-06-04 10:52:59 -04005583 if (temp == NULL) goto lend;
5584 lpszRawHeaders = temp;
5585 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5586 cchRawHeaders += (buflen-1);
5587 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5588 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5589 lpszRawHeaders[cchRawHeaders] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005590
Juan Langb49b2432011-03-01 10:59:39 -08005591 HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1],
Eric van Beurden59a21782009-06-04 10:52:59 -04005592 HTTP_ADDREQ_FLAG_ADD );
Robert Shearmanb72a6822004-09-23 22:53:50 +00005593
Eric van Beurden59a21782009-06-04 10:52:59 -04005594 HTTP_FreeTokens(pFieldAndValue);
5595 }
5596 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005597 else
5598 {
5599 cbreaks++;
5600 if (cbreaks >= 2)
5601 break;
5602 }
5603 }while(1);
5604
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005605 /* make sure the response header is terminated with an empty line. Some apps really
5606 truly care about that empty line being there for some reason. Just add it to the
5607 header. */
5608 if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
5609 {
5610 cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
Jacek Caban55b27222011-04-22 12:35:05 +02005611 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005612 if (temp == NULL) goto lend;
5613 lpszRawHeaders = temp;
5614 }
5615
5616 memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
5617
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005618 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005619 request->rawHeaders = lpszRawHeaders;
Robert Shearmandee87512004-07-19 20:09:20 +00005620 TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005621 bSuccess = TRUE;
5622
5623lend:
5624
Aric Stewartff9b9d42002-06-21 23:59:49 +00005625 TRACE("<--\n");
5626 if (bSuccess)
5627 return rc;
5628 else
Hans Leidekkere3e26222008-07-19 19:52:47 +02005629 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005630 heap_free(lpszRawHeaders);
Robert Shearman0e7c41e2005-11-28 11:55:16 +01005631 return 0;
Hans Leidekkere3e26222008-07-19 19:52:47 +02005632 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005633}
5634
Ulrich Czekallac2757242000-06-11 20:04:44 +00005635/***********************************************************************
5636 * HTTP_InterpretHttpHeader (internal)
5637 *
5638 * Parse server response
5639 *
5640 * RETURNS
5641 *
Robert Shearmanb72a6822004-09-23 22:53:50 +00005642 * Pointer to array of field, value, NULL on success.
5643 * NULL on error.
Ulrich Czekallac2757242000-06-11 20:04:44 +00005644 */
Jacek Caban02708c62005-10-26 10:07:58 +00005645static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005646{
Robert Shearmanb72a6822004-09-23 22:53:50 +00005647 LPWSTR * pTokenPair;
5648 LPWSTR pszColon;
5649 INT len;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005650
Jacek Caban354a74e2011-04-21 13:39:03 +02005651 pTokenPair = heap_alloc_zero(sizeof(*pTokenPair)*3);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005652
Robert Shearmanb72a6822004-09-23 22:53:50 +00005653 pszColon = strchrW(buffer, ':');
5654 /* must have two tokens */
5655 if (!pszColon)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005656 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005657 HTTP_FreeTokens(pTokenPair);
Robert Shearman7707a762005-03-10 11:14:24 +00005658 if (buffer[0])
5659 TRACE("No ':' in line: %s\n", debugstr_w(buffer));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005660 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005661 }
5662
Jacek Caban354a74e2011-04-21 13:39:03 +02005663 pTokenPair[0] = heap_alloc((pszColon - buffer + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005664 if (!pTokenPair[0])
Ulrich Czekallac2757242000-06-11 20:04:44 +00005665 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005666 HTTP_FreeTokens(pTokenPair);
5667 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005668 }
Robert Shearmanb72a6822004-09-23 22:53:50 +00005669 memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
5670 pTokenPair[0][pszColon - buffer] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005671
Robert Shearmanb72a6822004-09-23 22:53:50 +00005672 /* skip colon */
5673 pszColon++;
5674 len = strlenW(pszColon);
Jacek Caban354a74e2011-04-21 13:39:03 +02005675 pTokenPair[1] = heap_alloc((len + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005676 if (!pTokenPair[1])
5677 {
5678 HTTP_FreeTokens(pTokenPair);
5679 return NULL;
5680 }
5681 memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
5682
5683 strip_spaces(pTokenPair[0]);
5684 strip_spaces(pTokenPair[1]);
5685
5686 TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
5687 return pTokenPair;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005688}
5689
Ulrich Czekallac2757242000-06-11 20:04:44 +00005690/***********************************************************************
5691 * HTTP_ProcessHeader (internal)
5692 *
5693 * Stuff header into header tables according to <dwModifier>
5694 *
5695 */
5696
Juan Langa1ab4a72007-11-07 14:45:06 -08005697#define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005698
Juan Langb49b2432011-03-01 10:59:39 -08005699static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005700{
Mike McCormacka4e902c2004-03-30 04:36:09 +00005701 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01005702 INT index = -1;
Aric Stewart1e946d32005-12-13 17:07:41 +01005703 BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
Jacek Cabane9749652009-11-30 20:01:00 +01005704 DWORD res = ERROR_HTTP_INVALID_HEADER;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005705
Hans Leidekkercd2c4582006-10-05 13:18:56 +02005706 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005707
Aric Stewart1e946d32005-12-13 17:07:41 +01005708 /* REPLACE wins out over ADD */
5709 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5710 dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
5711
5712 if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
5713 index = -1;
5714 else
Juan Langb49b2432011-03-01 10:59:39 -08005715 index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only);
Aric Stewart1e946d32005-12-13 17:07:41 +01005716
5717 if (index >= 0)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005718 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005719 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
Jacek Cabane9749652009-11-30 20:01:00 +01005720 return ERROR_HTTP_INVALID_HEADER;
Juan Lang20980062011-03-01 11:18:22 -08005721 lphttpHdr = &request->custHeaders[index];
Aric Stewart1e946d32005-12-13 17:07:41 +01005722 }
5723 else if (value)
5724 {
5725 HTTPHEADERW hdr;
5726
5727 hdr.lpszField = (LPWSTR)field;
5728 hdr.lpszValue = (LPWSTR)value;
5729 hdr.wFlags = hdr.wCount = 0;
5730
5731 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5732 hdr.wFlags |= HDR_ISREQUEST;
5733
Juan Langb49b2432011-03-01 10:59:39 -08005734 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewart1e946d32005-12-13 17:07:41 +01005735 }
Rob Shearman7b002a32007-01-12 19:16:49 -06005736 /* no value to delete */
Jacek Cabane9749652009-11-30 20:01:00 +01005737 else return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01005738
5739 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5740 lphttpHdr->wFlags |= HDR_ISREQUEST;
5741 else
5742 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
5743
5744 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5745 {
Juan Langb49b2432011-03-01 10:59:39 -08005746 HTTP_DeleteCustomHeader( request, index );
Aric Stewart1e946d32005-12-13 17:07:41 +01005747
5748 if (value)
Aric Stewartff9b9d42002-06-21 23:59:49 +00005749 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00005750 HTTPHEADERW hdr;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005751
Mike McCormacka4e902c2004-03-30 04:36:09 +00005752 hdr.lpszField = (LPWSTR)field;
5753 hdr.lpszValue = (LPWSTR)value;
Aric Stewartff9b9d42002-06-21 23:59:49 +00005754 hdr.wFlags = hdr.wCount = 0;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005755
5756 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5757 hdr.wFlags |= HDR_ISREQUEST;
5758
Juan Langb49b2432011-03-01 10:59:39 -08005759 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewartff9b9d42002-06-21 23:59:49 +00005760 }
Aric Stewart1e946d32005-12-13 17:07:41 +01005761
Jacek Cabane9749652009-11-30 20:01:00 +01005762 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005763 }
Juan Langa1ab4a72007-11-07 14:45:06 -08005764 else if (dwModifier & COALESCEFLAGS)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005765 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005766 LPWSTR lpsztmp;
5767 WCHAR ch = 0;
5768 INT len = 0;
5769 INT origlen = strlenW(lphttpHdr->lpszValue);
5770 INT valuelen = strlenW(value);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005771
Aric Stewart1e946d32005-12-13 17:07:41 +01005772 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005773 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005774 ch = ',';
5775 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
5776 }
5777 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
5778 {
5779 ch = ';';
5780 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005781 }
5782
Aric Stewart1e946d32005-12-13 17:07:41 +01005783 len = origlen + valuelen + ((ch > 0) ? 2 : 0);
5784
Jacek Caban55b27222011-04-22 12:35:05 +02005785 lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
Aric Stewart1e946d32005-12-13 17:07:41 +01005786 if (lpsztmp)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005787 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005788 lphttpHdr->lpszValue = lpsztmp;
5789 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
5790 if (ch > 0)
5791 {
5792 lphttpHdr->lpszValue[origlen] = ch;
5793 origlen++;
5794 lphttpHdr->lpszValue[origlen] = ' ';
5795 origlen++;
5796 }
5797
5798 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
5799 lphttpHdr->lpszValue[len] = '\0';
Jacek Cabane9749652009-11-30 20:01:00 +01005800 res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005801 }
5802 else
5803 {
Jacek Caban55b27222011-04-22 12:35:05 +02005804 WARN("heap_realloc (%d bytes) failed\n",len+1);
Jacek Cabane9749652009-11-30 20:01:00 +01005805 res = ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005806 }
5807 }
Jacek Cabane9749652009-11-30 20:01:00 +01005808 TRACE("<-- %d\n", res);
5809 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005810}
5811
Ulrich Czekallac2757242000-06-11 20:04:44 +00005812/***********************************************************************
5813 * HTTP_GetCustomHeaderIndex (internal)
5814 *
5815 * Return index of custom header from header array
5816 *
5817 */
Juan Langb49b2432011-03-01 10:59:39 -08005818static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField,
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005819 int requested_index, BOOL request_only)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005820{
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005821 DWORD index;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005822
Juan Lang3cd54552009-12-04 14:37:46 -08005823 TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005824
Juan Langb49b2432011-03-01 10:59:39 -08005825 for (index = 0; index < request->nCustHeaders; index++)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005826 {
Juan Lang20980062011-03-01 11:18:22 -08005827 if (strcmpiW(request->custHeaders[index].lpszField, lpszField))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005828 continue;
5829
Juan Lang20980062011-03-01 11:18:22 -08005830 if (request_only && !(request->custHeaders[index].wFlags & HDR_ISREQUEST))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005831 continue;
5832
Juan Lang20980062011-03-01 11:18:22 -08005833 if (!request_only && (request->custHeaders[index].wFlags & HDR_ISREQUEST))
Aric Stewart1e946d32005-12-13 17:07:41 +01005834 continue;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005835
Aric Stewart1e946d32005-12-13 17:07:41 +01005836 if (requested_index == 0)
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005837 break;
5838 requested_index --;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005839 }
5840
Juan Langb49b2432011-03-01 10:59:39 -08005841 if (index >= request->nCustHeaders)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005842 index = -1;
5843
Hans Leidekkercd2c4582006-10-05 13:18:56 +02005844 TRACE("Return: %d\n", index);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005845 return index;
5846}
5847
5848
5849/***********************************************************************
5850 * HTTP_InsertCustomHeader (internal)
5851 *
5852 * Insert header into array
5853 *
5854 */
Juan Langb49b2432011-03-01 10:59:39 -08005855static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHdr)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005856{
5857 INT count;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005858 LPHTTPHEADERW lph = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005859
Mike McCormacka4e902c2004-03-30 04:36:09 +00005860 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
Juan Langb49b2432011-03-01 10:59:39 -08005861 count = request->nCustHeaders + 1;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005862 if (count > 1)
Jacek Caban55b27222011-04-22 12:35:05 +02005863 lph = heap_realloc_zero(request->custHeaders, sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005864 else
Jacek Caban354a74e2011-04-21 13:39:03 +02005865 lph = heap_alloc_zero(sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005866
Jacek Cabane9749652009-11-30 20:01:00 +01005867 if (!lph)
5868 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005869
Juan Lang20980062011-03-01 11:18:22 -08005870 request->custHeaders = lph;
5871 request->custHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
5872 request->custHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
5873 request->custHeaders[count-1].wFlags = lpHdr->wFlags;
5874 request->custHeaders[count-1].wCount= lpHdr->wCount;
Juan Langb49b2432011-03-01 10:59:39 -08005875 request->nCustHeaders++;
Jacek Cabane9749652009-11-30 20:01:00 +01005876
5877 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005878}
5879
5880
5881/***********************************************************************
5882 * HTTP_DeleteCustomHeader (internal)
5883 *
5884 * Delete header from array
Mike McCormacka1c16d22003-07-22 03:17:52 +00005885 * If this function is called, the indexs may change.
Ulrich Czekallac2757242000-06-11 20:04:44 +00005886 */
Juan Langb49b2432011-03-01 10:59:39 -08005887static BOOL HTTP_DeleteCustomHeader(http_request_t *request, DWORD index)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005888{
Juan Langb49b2432011-03-01 10:59:39 -08005889 if( request->nCustHeaders <= 0 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00005890 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08005891 if( index >= request->nCustHeaders )
Mike McCormacka1c16d22003-07-22 03:17:52 +00005892 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08005893 request->nCustHeaders--;
Mike McCormacka1c16d22003-07-22 03:17:52 +00005894
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005895 heap_free(request->custHeaders[index].lpszField);
5896 heap_free(request->custHeaders[index].lpszValue);
Rob Shearman62e0a8c2008-06-20 10:14:38 +01005897
Juan Lang20980062011-03-01 11:18:22 -08005898 memmove( &request->custHeaders[index], &request->custHeaders[index+1],
Juan Langb49b2432011-03-01 10:59:39 -08005899 (request->nCustHeaders - index)* sizeof(HTTPHEADERW) );
Juan Lang20980062011-03-01 11:18:22 -08005900 memset( &request->custHeaders[request->nCustHeaders], 0, sizeof(HTTPHEADERW) );
Mike McCormacka1c16d22003-07-22 03:17:52 +00005901
5902 return TRUE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005903}
Alberto Massarib09eef22002-11-13 04:08:26 +00005904
Aric Stewartc8dfc022007-07-26 08:59:00 -05005905
5906/***********************************************************************
5907 * HTTP_VerifyValidHeader (internal)
5908 *
5909 * Verify the given header is not invalid for the given http request
5910 *
5911 */
Juan Langb49b2432011-03-01 10:59:39 -08005912static BOOL HTTP_VerifyValidHeader(http_request_t *request, LPCWSTR field)
Aric Stewartc8dfc022007-07-26 08:59:00 -05005913{
Aric Stewartc8dfc022007-07-26 08:59:00 -05005914 /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
Juan Lang20980062011-03-01 11:18:22 -08005915 if (!strcmpW(request->version, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
Jacek Cabane9749652009-11-30 20:01:00 +01005916 return ERROR_HTTP_INVALID_HEADER;
Aric Stewartc8dfc022007-07-26 08:59:00 -05005917
Jacek Cabane9749652009-11-30 20:01:00 +01005918 return ERROR_SUCCESS;
Aric Stewartc8dfc022007-07-26 08:59:00 -05005919}
5920
Alberto Massarib09eef22002-11-13 04:08:26 +00005921/***********************************************************************
5922 * IsHostInProxyBypassList (@)
5923 *
5924 * Undocumented
5925 *
5926 */
5927BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
5928{
Hans Leidekkercd2c4582006-10-05 13:18:56 +02005929 FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
Alberto Massarib09eef22002-11-13 04:08:26 +00005930 return FALSE;
5931}
Austin English1c7d3492010-11-25 06:59:25 -08005932
5933/***********************************************************************
5934 * InternetShowSecurityInfoByURLA (@)
5935 */
5936BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window)
5937{
5938 FIXME("stub: %s %p\n", url, window);
5939 return FALSE;
5940}
5941
5942/***********************************************************************
5943 * InternetShowSecurityInfoByURLW (@)
5944 */
5945BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window)
5946{
5947 FIXME("stub: %s %p\n", debugstr_w(url), window);
5948 return FALSE;
5949}