blob: ca8cc60580db25dba83b44b65fdd5ba3ac163d00 [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"
Juan Lang044f6452011-10-31 12:55:15 -070068#include "winuser.h"
69#include "cryptuiapi.h"
Guy Albertelliaafec982001-11-06 22:31:19 +000070
Ulrich Czekallac2757242000-06-11 20:04:44 +000071#include "internet.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000072#include "wine/debug.h"
Hans Leidekkerbd805292008-10-24 11:08:12 +020073#include "wine/exception.h"
Alberto Massarid476a5a2002-11-12 02:13:04 +000074#include "wine/unicode.h"
Ulrich Czekallac2757242000-06-11 20:04:44 +000075
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000076WINE_DEFAULT_DEBUG_CHANNEL(wininet);
Ulrich Czekallac2757242000-06-11 20:04:44 +000077
Hans Leidekker3a577112008-03-24 21:31:53 +010078static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0};
Hans Leidekkerd0033db2008-02-17 20:41:42 +010079static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
Hans Leidekker2ed570e2010-02-22 12:28:03 +010080static const WCHAR szOK[] = {'O','K',0};
81static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0};
Jacek Caban83170892009-05-29 23:34:14 +020082static const WCHAR hostW[] = { 'H','o','s','t',0 };
Rob Shearman4b507682007-05-21 14:26:26 +010083static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
Aric Stewart1e946d32005-12-13 17:07:41 +010084static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
85static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
Rob Shearman272954b2007-01-04 18:23:17 +000086static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
Jacek Cabanf9791342008-02-13 13:34:05 +010087static const WCHAR szGET[] = { 'G','E','T', 0 };
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +020088static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
Lei Zhangf7e56d12008-08-27 17:03:13 -070089static const WCHAR szCrLf[] = {'\r','\n', 0};
Mike McCormacka4e902c2004-03-30 04:36:09 +000090
Jacek Caban83170892009-05-29 23:34:14 +020091static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
92static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
93static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
94static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
95static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
96static const WCHAR szAge[] = { 'A','g','e',0 };
97static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
98static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
99static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
100static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
101static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
102static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
103static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
104static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
105static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
106static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
107static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
108static 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 };
109static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
110static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
111static const WCHAR szDate[] = { 'D','a','t','e',0 };
112static const WCHAR szFrom[] = { 'F','r','o','m',0 };
113static const WCHAR szETag[] = { 'E','T','a','g',0 };
114static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
115static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
116static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
117static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
118static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
119static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
120static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
121static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
122static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
123static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
124static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
125static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
126static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
127static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
128static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
129static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
130static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
131static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
132static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
133static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
134static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
135static 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 };
136static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
137static const WCHAR szURI[] = { 'U','R','I',0 };
138static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
139static const WCHAR szVary[] = { 'V','a','r','y',0 };
140static const WCHAR szVia[] = { 'V','i','a',0 };
141static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
142static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
143
Jacek Caban83170892009-05-29 23:34:14 +0200144#define HTTP_REFERER szReferer
145#define HTTP_ACCEPT szAccept
146#define HTTP_USERAGENT szUser_Agent
Ulrich Czekallac2757242000-06-11 20:04:44 +0000147
148#define HTTP_ADDHDR_FLAG_ADD 0x20000000
149#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
150#define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
151#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
152#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
153#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
154#define HTTP_ADDHDR_FLAG_REQ 0x02000000
155
Jacek Caban8a1df202011-05-10 09:26:43 +0000156#define COLLECT_TIME 60000
157
Rob Shearman4b507682007-05-21 14:26:26 +0100158#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
159
160struct HttpAuthInfo
161{
162 LPWSTR scheme;
163 CredHandle cred;
164 CtxtHandle ctx;
165 TimeStamp exp;
166 ULONG attr;
Rob Shearman0be05ab2008-03-10 16:41:44 +0000167 ULONG max_token;
Rob Shearman4b507682007-05-21 14:26:26 +0100168 void *auth_data;
169 unsigned int auth_data_len;
170 BOOL finished; /* finished authenticating */
171};
Ulrich Czekallac2757242000-06-11 20:04:44 +0000172
Jacek Caban11ca05f2009-05-29 23:35:13 +0200173
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200174typedef struct _basicAuthorizationData
Aric Stewartfc508932009-10-12 14:24:18 -0500175{
176 struct list entry;
177
Juan Lang2c6ad542011-03-01 10:30:46 -0800178 LPWSTR host;
179 LPWSTR realm;
180 LPSTR authorization;
181 UINT authorizationLen;
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200182} basicAuthorizationData;
183
184typedef struct _authorizationData
185{
186 struct list entry;
187
188 LPWSTR host;
189 LPWSTR scheme;
190 LPWSTR domain;
191 UINT domain_len;
192 LPWSTR user;
193 UINT user_len;
194 LPWSTR password;
195 UINT password_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500196} authorizationData;
197
198static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200199static struct list authorizationCache = LIST_INIT(authorizationCache);
Aric Stewartfc508932009-10-12 14:24:18 -0500200
201static CRITICAL_SECTION authcache_cs;
202static CRITICAL_SECTION_DEBUG critsect_debug =
203{
204 0, 0, &authcache_cs,
205 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
206 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
207};
208static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
209
Jacek Caban34abacd2009-07-13 01:41:50 +0200210static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
Jacek Cabane9749652009-11-30 20:01:00 +0100211static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
Jacek Caban02708c62005-10-26 10:07:58 +0000212static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
Jacek Cabane9749652009-11-30 20:01:00 +0100213static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
Jacek Caban34abacd2009-07-13 01:41:50 +0200214static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
215static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
Aric Stewartbe918f42005-11-21 15:17:55 +0000216static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
Jacek Caban9823c232009-12-14 02:27:29 +0100217static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
Jacek Caban34abacd2009-07-13 01:41:50 +0200218static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
Rob Shearman4b507682007-05-21 14:26:26 +0100219static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
Jacek Caban34abacd2009-07-13 01:41:50 +0200220static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
Jacek Caban8a1df202011-05-10 09:26:43 +0000221
222static CRITICAL_SECTION connection_pool_cs;
223static CRITICAL_SECTION_DEBUG connection_pool_debug =
224{
225 0, 0, &connection_pool_cs,
226 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
227 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
228};
229static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
230
231static struct list connection_pool = LIST_INIT(connection_pool);
232static BOOL collector_running;
233
234void server_addref(server_t *server)
235{
236 InterlockedIncrement(&server->ref);
237}
238
239void server_release(server_t *server)
240{
241 if(InterlockedDecrement(&server->ref))
242 return;
243
244 if(!server->ref)
245 server->keep_until = GetTickCount64() + COLLECT_TIME;
246}
247
248static server_t *get_server(const WCHAR *name, INTERNET_PORT port)
249{
250 server_t *iter, *server = NULL;
251
252 EnterCriticalSection(&connection_pool_cs);
253
254 LIST_FOR_EACH_ENTRY(iter, &connection_pool, server_t, entry) {
255 if(iter->port == port && !strcmpW(iter->name, name)) {
256 server = iter;
257 server_addref(server);
258 break;
259 }
260 }
261
262 if(!server) {
263 server = heap_alloc(sizeof(*server));
264 if(server) {
265 server->addr_len = 0;
266 server->ref = 1;
267 server->port = port;
268 list_init(&server->conn_pool);
269 server->name = heap_strdupW(name);
270 if(server->name) {
271 list_add_head(&connection_pool, &server->entry);
272 }else {
273 heap_free(server);
274 server = NULL;
275 }
276 }
277 }
278
279 LeaveCriticalSection(&connection_pool_cs);
280
281 return server;
282}
283
284BOOL collect_connections(BOOL collect_all)
285{
286 netconn_t *netconn, *netconn_safe;
287 server_t *server, *server_safe;
288 BOOL remaining = FALSE;
289 DWORD64 now;
290
291 now = GetTickCount64();
292
293 LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) {
294 LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
295 if(collect_all || netconn->keep_until < now) {
296 TRACE("freeing %p\n", netconn);
297 list_remove(&netconn->pool_entry);
298 free_netconn(netconn);
299 }else {
300 remaining = TRUE;
301 }
302 }
303
304 if(!server->ref) {
305 if(collect_all || server->keep_until < now) {
306 list_remove(&server->entry);
307
308 heap_free(server->name);
309 heap_free(server);
310 }else {
311 remaining = TRUE;
312 }
313 }
314 }
315
316 return remaining;
317}
318
319static DWORD WINAPI collect_connections_proc(void *arg)
320{
321 BOOL remaining_conns;
322
323 do {
324 /* FIXME: Use more sophisticated method */
325 Sleep(5000);
326
327 EnterCriticalSection(&connection_pool_cs);
328
329 remaining_conns = collect_connections(FALSE);
330 if(!remaining_conns)
331 collector_running = FALSE;
332
333 LeaveCriticalSection(&connection_pool_cs);
334 }while(remaining_conns);
335
336 FreeLibraryAndExitThread(WININET_hModule, 0);
337}
Aric Stewart1e946d32005-12-13 17:07:41 +0100338
Jacek Caban34abacd2009-07-13 01:41:50 +0200339static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
Aric Stewart1e946d32005-12-13 17:07:41 +0100340{
341 int HeaderIndex = 0;
342 HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
343 if (HeaderIndex == -1)
344 return NULL;
345 else
Juan Lang20980062011-03-01 11:18:22 -0800346 return &req->custHeaders[HeaderIndex];
Aric Stewart1e946d32005-12-13 17:07:41 +0100347}
Ulrich Czekallac2757242000-06-11 20:04:44 +0000348
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200349typedef enum {
350 READMODE_SYNC,
351 READMODE_ASYNC,
352 READMODE_NOBLOCK
353} read_mode_t;
354
355struct data_stream_vtbl_t {
356 DWORD (*get_avail_data)(data_stream_t*,http_request_t*);
357 BOOL (*end_of_data)(data_stream_t*,http_request_t*);
358 DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,read_mode_t);
Jacek Caban8a1df202011-05-10 09:26:43 +0000359 BOOL (*drain_content)(data_stream_t*,http_request_t*);
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200360 void (*destroy)(data_stream_t*);
361};
362
363typedef struct {
364 data_stream_t data_stream;
365
366 BYTE buf[READ_BUFFER_SIZE];
367 DWORD buf_size;
368 DWORD buf_pos;
369 DWORD chunk_size;
370} chunked_stream_t;
371
Michael Stefaniuc9bf247d2011-04-05 16:18:38 +0200372static inline void destroy_data_stream(data_stream_t *stream)
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200373{
374 stream->vtbl->destroy(stream);
375}
376
377static void reset_data_stream(http_request_t *req)
378{
379 destroy_data_stream(req->data_stream);
380 req->data_stream = &req->netconn_stream.data_stream;
381 req->read_pos = req->read_size = req->netconn_stream.content_read = 0;
382 req->read_chunked = req->read_gzip = FALSE;
383}
384
Jacek Caban11ca05f2009-05-29 23:35:13 +0200385#ifdef HAVE_ZLIB
386
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200387typedef struct {
388 data_stream_t stream;
389 data_stream_t *parent_stream;
390 z_stream zstream;
391 BYTE buf[READ_BUFFER_SIZE];
392 DWORD buf_size;
393 DWORD buf_pos;
394 BOOL end_of_data;
395} gzip_stream_t;
396
397static DWORD gzip_get_avail_data(data_stream_t *stream, http_request_t *req)
398{
399 /* Allow reading only from read buffer */
400 return 0;
401}
402
403static BOOL gzip_end_of_data(data_stream_t *stream, http_request_t *req)
404{
405 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
406 return gzip_stream->end_of_data;
407}
408
409static DWORD gzip_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
410 DWORD *read, read_mode_t read_mode)
411{
412 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
413 z_stream *zstream = &gzip_stream->zstream;
414 DWORD current_read, ret_read = 0;
415 BOOL end;
416 int zres;
417 DWORD res = ERROR_SUCCESS;
418
419 while(size && !gzip_stream->end_of_data) {
420 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req);
421
422 if(gzip_stream->buf_size <= 64 && !end) {
423 if(gzip_stream->buf_pos) {
424 if(gzip_stream->buf_size)
425 memmove(gzip_stream->buf, gzip_stream->buf+gzip_stream->buf_pos, gzip_stream->buf_size);
426 gzip_stream->buf_pos = 0;
427 }
428 res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size,
429 sizeof(gzip_stream->buf)-gzip_stream->buf_size, &current_read, read_mode);
430 gzip_stream->buf_size += current_read;
431 if(res != ERROR_SUCCESS)
432 break;
433 end = gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req);
434 if(!current_read && !end) {
435 if(read_mode != READMODE_NOBLOCK) {
436 WARN("unexpected end of data\n");
437 gzip_stream->end_of_data = TRUE;
438 }
439 break;
440 }
441 if(gzip_stream->buf_size <= 64 && !end)
442 continue;
443 }
444
445 zstream->next_in = gzip_stream->buf+gzip_stream->buf_pos;
446 zstream->avail_in = gzip_stream->buf_size-(end ? 0 : 64);
447 zstream->next_out = buf+ret_read;
448 zstream->avail_out = size;
449 zres = inflate(&gzip_stream->zstream, 0);
450 current_read = size - zstream->avail_out;
451 size -= current_read;
452 ret_read += current_read;
453 gzip_stream->buf_size -= zstream->next_in - (gzip_stream->buf+gzip_stream->buf_pos);
454 gzip_stream->buf_pos = zstream->next_in-gzip_stream->buf;
455 if(zres == Z_STREAM_END) {
456 TRACE("end of data\n");
457 gzip_stream->end_of_data = TRUE;
458 inflateEnd(zstream);
459 }else if(zres != Z_OK) {
460 WARN("inflate failed %d: %s\n", zres, debugstr_a(zstream->msg));
461 if(!ret_read)
462 res = ERROR_INTERNET_DECODING_FAILED;
463 break;
464 }
465
466 if(ret_read && read_mode == READMODE_ASYNC)
467 read_mode = READMODE_NOBLOCK;
468 }
469
470 TRACE("read %u bytes\n", ret_read);
471 *read = ret_read;
472 return res;
473}
474
Jacek Caban8a1df202011-05-10 09:26:43 +0000475static BOOL gzip_drain_content(data_stream_t *stream, http_request_t *req)
476{
477 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
478 return gzip_stream->parent_stream->vtbl->drain_content(gzip_stream->parent_stream, req);
479}
480
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200481static void gzip_destroy(data_stream_t *stream)
482{
483 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
484
485 destroy_data_stream(gzip_stream->parent_stream);
486
487 if(!gzip_stream->end_of_data)
488 inflateEnd(&gzip_stream->zstream);
489 heap_free(gzip_stream);
490}
491
492static const data_stream_vtbl_t gzip_stream_vtbl = {
493 gzip_get_avail_data,
494 gzip_end_of_data,
495 gzip_read,
Jacek Caban8a1df202011-05-10 09:26:43 +0000496 gzip_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200497 gzip_destroy
498};
499
Jacek Caban11ca05f2009-05-29 23:35:13 +0200500static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
501{
Jacek Caban354a74e2011-04-21 13:39:03 +0200502 return heap_alloc(items*size);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200503}
504
505static void wininet_zfree(voidpf opaque, voidpf address)
506{
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200507 heap_free(address);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200508}
509
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200510static DWORD init_gzip_stream(http_request_t *req)
Jacek Caban11ca05f2009-05-29 23:35:13 +0200511{
512 gzip_stream_t *gzip_stream;
Jacek Caban3858e352009-07-31 21:07:42 +0200513 int index, zres;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200514
Jacek Cabanec966042011-03-15 00:08:34 +0100515 gzip_stream = heap_alloc_zero(sizeof(gzip_stream_t));
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200516 if(!gzip_stream)
517 return ERROR_OUTOFMEMORY;
518
519 gzip_stream->stream.vtbl = &gzip_stream_vtbl;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200520 gzip_stream->zstream.zalloc = wininet_zalloc;
521 gzip_stream->zstream.zfree = wininet_zfree;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200522
523 zres = inflateInit2(&gzip_stream->zstream, 0x1f);
524 if(zres != Z_OK) {
525 ERR("inflateInit failed: %d\n", zres);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200526 heap_free(gzip_stream);
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200527 return ERROR_OUTOFMEMORY;
Jacek Caban11ca05f2009-05-29 23:35:13 +0200528 }
529
Jacek Caban3858e352009-07-31 21:07:42 +0200530 index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
531 if(index != -1)
532 HTTP_DeleteCustomHeader(req, index);
Jacek Caban11ca05f2009-05-29 23:35:13 +0200533
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200534 if(req->read_size) {
535 memcpy(gzip_stream->buf, req->read_buf+req->read_pos, req->read_size);
536 gzip_stream->buf_size = req->read_size;
537 req->read_pos = req->read_size = 0;
538 }
539
540 req->read_gzip = TRUE;
541 gzip_stream->parent_stream = req->data_stream;
542 req->data_stream = &gzip_stream->stream;
543 return ERROR_SUCCESS;
Jacek Cabanec966042011-03-15 00:08:34 +0100544}
545
Jacek Caban11ca05f2009-05-29 23:35:13 +0200546#else
547
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200548static DWORD init_gzip_stream(http_request_t *req)
Jacek Caban11ca05f2009-05-29 23:35:13 +0200549{
550 ERR("gzip stream not supported, missing zlib.\n");
Jacek Cabanccd11eb2011-04-02 15:20:33 +0200551 return ERROR_SUCCESS;
Jacek Cabanec966042011-03-15 00:08:34 +0100552}
553
Jacek Caban11ca05f2009-05-29 23:35:13 +0200554#endif
555
Ulrich Czekallac2757242000-06-11 20:04:44 +0000556/***********************************************************************
Robert Shearmandee87512004-07-19 20:09:20 +0000557 * HTTP_Tokenize (internal)
558 *
559 * Tokenize a string, allocating memory for the tokens.
560 */
561static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
562{
563 LPWSTR * token_array;
564 int tokens = 0;
565 int i;
566 LPCWSTR next_token;
567
Rob Shearman0715d9c2008-10-07 15:39:50 +0100568 if (string)
569 {
570 /* empty string has no tokens */
571 if (*string)
Robert Shearmandee87512004-07-19 20:09:20 +0000572 tokens++;
Rob Shearman0715d9c2008-10-07 15:39:50 +0100573 /* count tokens */
574 for (i = 0; string[i]; i++)
575 {
576 if (!strncmpW(string+i, token_string, strlenW(token_string)))
577 {
578 DWORD j;
579 tokens++;
580 /* we want to skip over separators, but not the null terminator */
581 for (j = 0; j < strlenW(token_string) - 1; j++)
582 if (!string[i+j])
583 break;
584 i += j;
585 }
Robert Shearmandee87512004-07-19 20:09:20 +0000586 }
Rob Shearman0715d9c2008-10-07 15:39:50 +0100587 }
Robert Shearmandee87512004-07-19 20:09:20 +0000588
589 /* add 1 for terminating NULL */
Jacek Caban354a74e2011-04-21 13:39:03 +0200590 token_array = heap_alloc((tokens+1) * sizeof(*token_array));
Robert Shearmandee87512004-07-19 20:09:20 +0000591 token_array[tokens] = NULL;
592 if (!tokens)
593 return token_array;
594 for (i = 0; i < tokens; i++)
595 {
596 int len;
597 next_token = strstrW(string, token_string);
598 if (!next_token) next_token = string+strlenW(string);
599 len = next_token - string;
Jacek Caban354a74e2011-04-21 13:39:03 +0200600 token_array[i] = heap_alloc((len+1)*sizeof(WCHAR));
Robert Shearmandee87512004-07-19 20:09:20 +0000601 memcpy(token_array[i], string, len*sizeof(WCHAR));
602 token_array[i][len] = '\0';
603 string = next_token+strlenW(token_string);
604 }
605 return token_array;
606}
607
608/***********************************************************************
609 * HTTP_FreeTokens (internal)
610 *
611 * Frees memory returned from HTTP_Tokenize.
612 */
613static void HTTP_FreeTokens(LPWSTR * token_array)
614{
615 int i;
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200616 for (i = 0; token_array[i]; i++) heap_free(token_array[i]);
617 heap_free(token_array);
Robert Shearmandee87512004-07-19 20:09:20 +0000618}
619
Juan Langb49b2432011-03-01 10:59:39 -0800620static void HTTP_FixURL(http_request_t *request)
Aric Stewartbe918f42005-11-21 15:17:55 +0000621{
622 static const WCHAR szSlash[] = { '/',0 };
623 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
624
625 /* If we don't have a path we set it to root */
Juan Lang20980062011-03-01 11:18:22 -0800626 if (NULL == request->path)
627 request->path = heap_strdupW(szSlash);
Aric Stewartbe918f42005-11-21 15:17:55 +0000628 else /* remove \r and \n*/
629 {
Juan Lang20980062011-03-01 11:18:22 -0800630 int nLen = strlenW(request->path);
631 while ((nLen >0 ) && ((request->path[nLen-1] == '\r')||(request->path[nLen-1] == '\n')))
Aric Stewartbe918f42005-11-21 15:17:55 +0000632 {
633 nLen--;
Juan Lang20980062011-03-01 11:18:22 -0800634 request->path[nLen]='\0';
Aric Stewartbe918f42005-11-21 15:17:55 +0000635 }
636 /* Replace '\' with '/' */
637 while (nLen>0) {
638 nLen--;
Juan Lang20980062011-03-01 11:18:22 -0800639 if (request->path[nLen] == '\\') request->path[nLen]='/';
Aric Stewartbe918f42005-11-21 15:17:55 +0000640 }
641 }
642
643 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
Juan Lang20980062011-03-01 11:18:22 -0800644 request->path, strlenW(request->path), szHttp, strlenW(szHttp) )
645 && request->path[0] != '/') /* not an absolute path ?? --> fix it !! */
Aric Stewartbe918f42005-11-21 15:17:55 +0000646 {
Jacek Caban354a74e2011-04-21 13:39:03 +0200647 WCHAR *fixurl = heap_alloc((strlenW(request->path) + 2)*sizeof(WCHAR));
Aric Stewartbe918f42005-11-21 15:17:55 +0000648 *fixurl = '/';
Juan Lang20980062011-03-01 11:18:22 -0800649 strcpyW(fixurl + 1, request->path);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200650 heap_free( request->path );
Juan Lang20980062011-03-01 11:18:22 -0800651 request->path = fixurl;
Aric Stewartbe918f42005-11-21 15:17:55 +0000652 }
653}
654
Juan Langb49b2432011-03-01 10:59:39 -0800655static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
Aric Stewartbe918f42005-11-21 15:17:55 +0000656{
657 LPWSTR requestString;
658 DWORD len, n;
659 LPCWSTR *req;
Gerald Pfeifer3f1a20b2008-01-12 20:14:04 +0100660 UINT i;
Aric Stewartbe918f42005-11-21 15:17:55 +0000661 LPWSTR p;
662
663 static const WCHAR szSpace[] = { ' ',0 };
Aric Stewartbe918f42005-11-21 15:17:55 +0000664 static const WCHAR szColon[] = { ':',' ',0 };
665 static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
666
667 /* allocate space for an array of all the string pointers to be added */
Juan Langb49b2432011-03-01 10:59:39 -0800668 len = (request->nCustHeaders)*4 + 10;
Jacek Caban354a74e2011-04-21 13:39:03 +0200669 req = heap_alloc(len*sizeof(LPCWSTR));
Aric Stewartbe918f42005-11-21 15:17:55 +0000670
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100671 /* add the verb, path and HTTP version string */
Aric Stewartbe918f42005-11-21 15:17:55 +0000672 n = 0;
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100673 req[n++] = verb;
Aric Stewartbe918f42005-11-21 15:17:55 +0000674 req[n++] = szSpace;
Robert Shearman0e7c41e2005-11-28 11:55:16 +0100675 req[n++] = path;
Hans Leidekkerd0033db2008-02-17 20:41:42 +0100676 req[n++] = szSpace;
677 req[n++] = version;
Aric Stewartbe918f42005-11-21 15:17:55 +0000678
Austin English0e4adae2008-01-04 13:37:14 -0600679 /* Append custom request headers */
Juan Langb49b2432011-03-01 10:59:39 -0800680 for (i = 0; i < request->nCustHeaders; i++)
Aric Stewartbe918f42005-11-21 15:17:55 +0000681 {
Juan Lang20980062011-03-01 11:18:22 -0800682 if (request->custHeaders[i].wFlags & HDR_ISREQUEST)
Aric Stewartbe918f42005-11-21 15:17:55 +0000683 {
Lei Zhangf7e56d12008-08-27 17:03:13 -0700684 req[n++] = szCrLf;
Juan Lang20980062011-03-01 11:18:22 -0800685 req[n++] = request->custHeaders[i].lpszField;
Aric Stewartbe918f42005-11-21 15:17:55 +0000686 req[n++] = szColon;
Juan Lang20980062011-03-01 11:18:22 -0800687 req[n++] = request->custHeaders[i].lpszValue;
Aric Stewartbe918f42005-11-21 15:17:55 +0000688
689 TRACE("Adding custom header %s (%s)\n",
Juan Lang20980062011-03-01 11:18:22 -0800690 debugstr_w(request->custHeaders[i].lpszField),
691 debugstr_w(request->custHeaders[i].lpszValue));
Aric Stewartbe918f42005-11-21 15:17:55 +0000692 }
693 }
694
695 if( n >= len )
696 ERR("oops. buffer overrun\n");
697
698 req[n] = NULL;
699 requestString = HTTP_build_req( req, 4 );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200700 heap_free( req );
Aric Stewartbe918f42005-11-21 15:17:55 +0000701
702 /*
703 * Set (header) termination string for request
704 * Make sure there's exactly two new lines at the end of the request
705 */
706 p = &requestString[strlenW(requestString)-1];
707 while ( (*p == '\n') || (*p == '\r') )
708 p--;
709 strcpyW( p+1, sztwocrlf );
710
711 return requestString;
712}
713
Juan Langb49b2432011-03-01 10:59:39 -0800714static void HTTP_ProcessCookies( http_request_t *request )
Aric Stewartbe918f42005-11-21 15:17:55 +0000715{
Aric Stewart1e946d32005-12-13 17:07:41 +0100716 int HeaderIndex;
Jan-Peter Nilssonb2618362008-09-24 22:42:36 +0200717 int numCookies = 0;
Aric Stewart1e946d32005-12-13 17:07:41 +0100718 LPHTTPHEADERW setCookieHeader;
719
Jacek Caban2e2ed522011-05-19 16:11:45 +0200720 if(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES)
721 return;
722
723 while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, szSet_Cookie, numCookies++, FALSE)) != -1)
Aric Stewartbe918f42005-11-21 15:17:55 +0000724 {
Jacek Caban2e2ed522011-05-19 16:11:45 +0200725 HTTPHEADERW *host;
726 const WCHAR *data;
727 WCHAR *name;
728
Juan Lang20980062011-03-01 11:18:22 -0800729 setCookieHeader = &request->custHeaders[HeaderIndex];
Aric Stewartbe918f42005-11-21 15:17:55 +0000730
Jacek Caban2e2ed522011-05-19 16:11:45 +0200731 if (!setCookieHeader->lpszValue)
732 continue;
Aric Stewart1e946d32005-12-13 17:07:41 +0100733
Jacek Caban2e2ed522011-05-19 16:11:45 +0200734 host = HTTP_GetHeader(request, hostW);
735 if(!host)
736 continue;
Jan-Peter Nilssonb2618362008-09-24 22:42:36 +0200737
Jacek Caban2e2ed522011-05-19 16:11:45 +0200738 data = strchrW(setCookieHeader->lpszValue, '=');
739 if(!data)
740 continue;
741
742 name = heap_strndupW(setCookieHeader->lpszValue, data-setCookieHeader->lpszValue);
743 if(!name)
744 continue;
745
746 data++;
747 set_cookie(host->lpszValue, request->path, name, data);
748 heap_free(name);
Aric Stewartbe918f42005-11-21 15:17:55 +0000749 }
750}
751
Aric Stewartfc508932009-10-12 14:24:18 -0500752static void strip_spaces(LPWSTR start)
753{
754 LPWSTR str = start;
755 LPWSTR end;
756
757 while (*str == ' ' && *str != '\0')
758 str++;
759
760 if (str != start)
761 memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
762
763 end = start + strlenW(start) - 1;
764 while (end >= start && *end == ' ')
765 {
766 *end = '\0';
767 end--;
768 }
769}
770
771static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
Rob Shearman4b507682007-05-21 14:26:26 +0100772{
773 static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
Aric Stewartfc508932009-10-12 14:24:18 -0500774 static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
775 BOOL is_basic;
776 is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
Rob Shearman6021fa02008-05-15 21:05:21 +0100777 ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
Aric Stewartfc508932009-10-12 14:24:18 -0500778 if (is_basic && pszRealm)
779 {
780 LPCWSTR token;
781 LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)];
782 LPCWSTR realm;
783 ptr++;
784 *pszRealm=NULL;
785 token = strchrW(ptr,'=');
786 if (!token)
787 return TRUE;
788 realm = ptr;
789 while (*realm == ' ' && *realm != '\0')
790 realm++;
791 if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) &&
792 (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '='))
793 {
794 token++;
795 while (*token == ' ' && *token != '\0')
796 token++;
797 if (*token == '\0')
798 return TRUE;
799 *pszRealm = heap_strdupW(token);
800 strip_spaces(*pszRealm);
801 }
802 }
803
804 return is_basic;
Rob Shearman4b507682007-05-21 14:26:26 +0100805}
806
Hans Leidekker50fef742009-09-02 11:44:43 +0200807static void destroy_authinfo( struct HttpAuthInfo *authinfo )
808{
809 if (!authinfo) return;
810
811 if (SecIsValidHandle(&authinfo->ctx))
812 DeleteSecurityContext(&authinfo->ctx);
813 if (SecIsValidHandle(&authinfo->cred))
814 FreeCredentialsHandle(&authinfo->cred);
815
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200816 heap_free(authinfo->auth_data);
817 heap_free(authinfo->scheme);
818 heap_free(authinfo);
Hans Leidekker50fef742009-09-02 11:44:43 +0200819}
820
Aric Stewartfc508932009-10-12 14:24:18 -0500821static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
822{
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200823 basicAuthorizationData *ad;
Aric Stewartfc508932009-10-12 14:24:18 -0500824 UINT rc = 0;
825
826 TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
827
828 EnterCriticalSection(&authcache_cs);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200829 LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, basicAuthorizationData, entry)
Aric Stewartfc508932009-10-12 14:24:18 -0500830 {
Juan Lang2c6ad542011-03-01 10:30:46 -0800831 if (!strcmpiW(host,ad->host) && !strcmpW(realm,ad->realm))
Aric Stewartfc508932009-10-12 14:24:18 -0500832 {
833 TRACE("Authorization found in cache\n");
Jacek Caban354a74e2011-04-21 13:39:03 +0200834 *auth_data = heap_alloc(ad->authorizationLen);
Juan Lang2c6ad542011-03-01 10:30:46 -0800835 memcpy(*auth_data,ad->authorization,ad->authorizationLen);
836 rc = ad->authorizationLen;
Aric Stewartfc508932009-10-12 14:24:18 -0500837 break;
838 }
839 }
840 LeaveCriticalSection(&authcache_cs);
841 return rc;
842}
843
844static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
845{
846 struct list *cursor;
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200847 basicAuthorizationData* ad = NULL;
Aric Stewartfc508932009-10-12 14:24:18 -0500848
849 TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
850
851 EnterCriticalSection(&authcache_cs);
852 LIST_FOR_EACH(cursor, &basicAuthorizationCache)
853 {
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200854 basicAuthorizationData *check = LIST_ENTRY(cursor,basicAuthorizationData,entry);
Juan Lang2c6ad542011-03-01 10:30:46 -0800855 if (!strcmpiW(host,check->host) && !strcmpW(realm,check->realm))
Aric Stewartfc508932009-10-12 14:24:18 -0500856 {
857 ad = check;
858 break;
859 }
860 }
861
862 if (ad)
863 {
864 TRACE("Found match in cache, replacing\n");
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200865 heap_free(ad->authorization);
Jacek Caban354a74e2011-04-21 13:39:03 +0200866 ad->authorization = heap_alloc(auth_data_len);
Juan Lang2c6ad542011-03-01 10:30:46 -0800867 memcpy(ad->authorization, auth_data, auth_data_len);
868 ad->authorizationLen = auth_data_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500869 }
870 else
871 {
Jacek Caban354a74e2011-04-21 13:39:03 +0200872 ad = heap_alloc(sizeof(basicAuthorizationData));
Juan Lang2c6ad542011-03-01 10:30:46 -0800873 ad->host = heap_strdupW(host);
Jacek Caban0281b7d2011-07-28 16:53:57 +0200874 ad->realm = heap_strdupW(realm);
Jacek Caban354a74e2011-04-21 13:39:03 +0200875 ad->authorization = heap_alloc(auth_data_len);
Juan Lang2c6ad542011-03-01 10:30:46 -0800876 memcpy(ad->authorization, auth_data, auth_data_len);
877 ad->authorizationLen = auth_data_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500878 list_add_head(&basicAuthorizationCache,&ad->entry);
879 TRACE("authorization cached\n");
880 }
881 LeaveCriticalSection(&authcache_cs);
882}
883
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200884static BOOL retrieve_cached_authorization(LPWSTR host, LPWSTR scheme,
885 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
886{
887 authorizationData *ad;
888
889 TRACE("Looking for authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
890
891 EnterCriticalSection(&authcache_cs);
892 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry) {
893 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
894 TRACE("Authorization found in cache\n");
895
896 nt_auth_identity->User = heap_strdupW(ad->user);
897 nt_auth_identity->Password = heap_strdupW(ad->password);
Jacek Caban354a74e2011-04-21 13:39:03 +0200898 nt_auth_identity->Domain = heap_alloc(sizeof(WCHAR)*ad->domain_len);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200899 if(!nt_auth_identity->User || !nt_auth_identity->Password ||
900 (!nt_auth_identity->Domain && ad->domain_len)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200901 heap_free(nt_auth_identity->User);
902 heap_free(nt_auth_identity->Password);
903 heap_free(nt_auth_identity->Domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200904 break;
905 }
906
907 nt_auth_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
908 nt_auth_identity->UserLength = ad->user_len;
909 nt_auth_identity->PasswordLength = ad->password_len;
910 memcpy(nt_auth_identity->Domain, ad->domain, sizeof(WCHAR)*ad->domain_len);
911 nt_auth_identity->DomainLength = ad->domain_len;
912 LeaveCriticalSection(&authcache_cs);
913 return TRUE;
914 }
915 }
916 LeaveCriticalSection(&authcache_cs);
917
918 return FALSE;
919}
920
921static void cache_authorization(LPWSTR host, LPWSTR scheme,
922 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
923{
924 authorizationData *ad;
925 BOOL found = FALSE;
926
927 TRACE("Caching authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
928
929 EnterCriticalSection(&authcache_cs);
930 LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry)
931 if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
932 found = TRUE;
933 break;
934 }
935
936 if(found) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200937 heap_free(ad->user);
938 heap_free(ad->password);
939 heap_free(ad->domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200940 } else {
Jacek Caban354a74e2011-04-21 13:39:03 +0200941 ad = heap_alloc(sizeof(authorizationData));
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200942 if(!ad) {
943 LeaveCriticalSection(&authcache_cs);
944 return;
945 }
946
947 ad->host = heap_strdupW(host);
948 ad->scheme = heap_strdupW(scheme);
949 list_add_head(&authorizationCache, &ad->entry);
950 }
951
952 ad->user = heap_strndupW(nt_auth_identity->User, nt_auth_identity->UserLength);
953 ad->password = heap_strndupW(nt_auth_identity->Password, nt_auth_identity->PasswordLength);
954 ad->domain = heap_strndupW(nt_auth_identity->Domain, nt_auth_identity->DomainLength);
955 ad->user_len = nt_auth_identity->UserLength;
956 ad->password_len = nt_auth_identity->PasswordLength;
957 ad->domain_len = nt_auth_identity->DomainLength;
958
959 if(!ad->host || !ad->scheme || !ad->user || !ad->password
960 || (nt_auth_identity->Domain && !ad->domain)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200961 heap_free(ad->host);
962 heap_free(ad->scheme);
963 heap_free(ad->user);
964 heap_free(ad->password);
965 heap_free(ad->domain);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200966 list_remove(&ad->entry);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +0200967 heap_free(ad);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200968 }
969
970 LeaveCriticalSection(&authcache_cs);
971}
972
Juan Langb49b2432011-03-01 10:59:39 -0800973static BOOL HTTP_DoAuthorization( http_request_t *request, LPCWSTR pszAuthValue,
Rob Shearmancb289692007-06-05 19:49:58 +0100974 struct HttpAuthInfo **ppAuthInfo,
Aric Stewartfc508932009-10-12 14:24:18 -0500975 LPWSTR domain_and_username, LPWSTR password,
976 LPWSTR host )
Rob Shearman4b507682007-05-21 14:26:26 +0100977{
978 SECURITY_STATUS sec_status;
Rob Shearmancb289692007-06-05 19:49:58 +0100979 struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
Rob Shearman7b948712007-05-26 08:49:12 +0100980 BOOL first = FALSE;
Aric Stewartfc508932009-10-12 14:24:18 -0500981 LPWSTR szRealm = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +0100982
983 TRACE("%s\n", debugstr_w(pszAuthValue));
984
985 if (!pAuthInfo)
986 {
987 TimeStamp exp;
988
Rob Shearman7b948712007-05-26 08:49:12 +0100989 first = TRUE;
Jacek Caban354a74e2011-04-21 13:39:03 +0200990 pAuthInfo = heap_alloc(sizeof(*pAuthInfo));
Rob Shearman4b507682007-05-21 14:26:26 +0100991 if (!pAuthInfo)
992 return FALSE;
993
Rob Shearman4b507682007-05-21 14:26:26 +0100994 SecInvalidateHandle(&pAuthInfo->cred);
995 SecInvalidateHandle(&pAuthInfo->ctx);
996 memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
997 pAuthInfo->attr = 0;
998 pAuthInfo->auth_data = NULL;
999 pAuthInfo->auth_data_len = 0;
1000 pAuthInfo->finished = FALSE;
1001
Aric Stewartfc508932009-10-12 14:24:18 -05001002 if (is_basic_auth_value(pszAuthValue,NULL))
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001003 {
1004 static const WCHAR szBasic[] = {'B','a','s','i','c',0};
Jacek Cabanf5987092009-07-17 01:10:41 +02001005 pAuthInfo->scheme = heap_strdupW(szBasic);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001006 if (!pAuthInfo->scheme)
1007 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001008 heap_free(pAuthInfo);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001009 return FALSE;
1010 }
1011 }
1012 else
Rob Shearman4b507682007-05-21 14:26:26 +01001013 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001014 PVOID pAuthData;
Rob Shearman4b507682007-05-21 14:26:26 +01001015 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
Rob Shearman4b507682007-05-21 14:26:26 +01001016
Jacek Cabanf5987092009-07-17 01:10:41 +02001017 pAuthInfo->scheme = heap_strdupW(pszAuthValue);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001018 if (!pAuthInfo->scheme)
1019 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001020 heap_free(pAuthInfo);
Rob Shearman4d1b8b12007-05-25 12:06:11 +01001021 return FALSE;
1022 }
1023
Rob Shearman7631bdf2008-03-10 16:40:23 +00001024 if (domain_and_username)
Rob Shearman4b507682007-05-21 14:26:26 +01001025 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001026 WCHAR *user = strchrW(domain_and_username, '\\');
1027 WCHAR *domain = domain_and_username;
Rob Shearman4b507682007-05-21 14:26:26 +01001028
Rob Shearman7631bdf2008-03-10 16:40:23 +00001029 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
1030
1031 pAuthData = &nt_auth_identity;
1032
1033 if (user) user++;
1034 else
1035 {
1036 user = domain_and_username;
1037 domain = NULL;
1038 }
1039
1040 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1041 nt_auth_identity.User = user;
1042 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
1043 nt_auth_identity.Domain = domain;
1044 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
1045 nt_auth_identity.Password = password;
1046 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001047
1048 cache_authorization(host, pAuthInfo->scheme, &nt_auth_identity);
Rob Shearman7631bdf2008-03-10 16:40:23 +00001049 }
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001050 else if(retrieve_cached_authorization(host, pAuthInfo->scheme, &nt_auth_identity))
1051 pAuthData = &nt_auth_identity;
Rob Shearman7631bdf2008-03-10 16:40:23 +00001052 else
1053 /* use default credentials */
1054 pAuthData = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001055
1056 sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
1057 SECPKG_CRED_OUTBOUND, NULL,
Rob Shearman7631bdf2008-03-10 16:40:23 +00001058 pAuthData, NULL,
Rob Shearman4b507682007-05-21 14:26:26 +01001059 NULL, &pAuthInfo->cred,
1060 &exp);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001061
1062 if(pAuthData && !domain_and_username) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001063 heap_free(nt_auth_identity.User);
1064 heap_free(nt_auth_identity.Domain);
1065 heap_free(nt_auth_identity.Password);
Piotr Cabanc398e6f2010-07-17 14:08:44 +02001066 }
1067
Rob Shearman0be05ab2008-03-10 16:41:44 +00001068 if (sec_status == SEC_E_OK)
1069 {
1070 PSecPkgInfoW sec_pkg_info;
1071 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
1072 if (sec_status == SEC_E_OK)
1073 {
1074 pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
1075 FreeContextBuffer(sec_pkg_info);
1076 }
1077 }
Rob Shearman4b507682007-05-21 14:26:26 +01001078 if (sec_status != SEC_E_OK)
1079 {
1080 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
1081 debugstr_w(pAuthInfo->scheme), sec_status);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001082 heap_free(pAuthInfo->scheme);
1083 heap_free(pAuthInfo);
Rob Shearman4b507682007-05-21 14:26:26 +01001084 return FALSE;
1085 }
1086 }
Rob Shearmancb289692007-06-05 19:49:58 +01001087 *ppAuthInfo = pAuthInfo;
Rob Shearman4b507682007-05-21 14:26:26 +01001088 }
1089 else if (pAuthInfo->finished)
1090 return FALSE;
1091
1092 if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
1093 strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
1094 {
1095 ERR("authentication scheme changed from %s to %s\n",
1096 debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
1097 return FALSE;
1098 }
1099
Aric Stewartfc508932009-10-12 14:24:18 -05001100 if (is_basic_auth_value(pszAuthValue,&szRealm))
Rob Shearman4b507682007-05-21 14:26:26 +01001101 {
Rob Shearman7631bdf2008-03-10 16:40:23 +00001102 int userlen;
1103 int passlen;
Aric Stewartfc508932009-10-12 14:24:18 -05001104 char *auth_data = NULL;
1105 UINT auth_data_len = 0;
Rob Shearman847cc512007-05-21 14:28:02 +01001106
Aric Stewartfc508932009-10-12 14:24:18 -05001107 TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
Rob Shearman847cc512007-05-21 14:28:02 +01001108
Aric Stewartfc508932009-10-12 14:24:18 -05001109 if (!domain_and_username)
1110 {
1111 if (host && szRealm)
1112 auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data);
1113 if (auth_data_len == 0)
1114 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001115 heap_free(szRealm);
Aric Stewartfc508932009-10-12 14:24:18 -05001116 return FALSE;
1117 }
1118 }
1119 else
1120 {
1121 userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
1122 passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
Rob Shearman7631bdf2008-03-10 16:40:23 +00001123
Aric Stewartfc508932009-10-12 14:24:18 -05001124 /* length includes a nul terminator, which will be re-used for the ':' */
Jacek Caban354a74e2011-04-21 13:39:03 +02001125 auth_data = heap_alloc(userlen + 1 + passlen);
Aric Stewartfc508932009-10-12 14:24:18 -05001126 if (!auth_data)
1127 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001128 heap_free(szRealm);
Aric Stewartfc508932009-10-12 14:24:18 -05001129 return FALSE;
1130 }
Rob Shearman7631bdf2008-03-10 16:40:23 +00001131
Aric Stewartfc508932009-10-12 14:24:18 -05001132 WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
1133 auth_data[userlen] = ':';
1134 WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
1135 auth_data_len = userlen + 1 + passlen;
1136 if (host && szRealm)
1137 cache_basic_authorization(host, szRealm, auth_data, auth_data_len);
1138 }
Rob Shearman847cc512007-05-21 14:28:02 +01001139
1140 pAuthInfo->auth_data = auth_data;
Aric Stewartfc508932009-10-12 14:24:18 -05001141 pAuthInfo->auth_data_len = auth_data_len;
Rob Shearman847cc512007-05-21 14:28:02 +01001142 pAuthInfo->finished = TRUE;
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001143 heap_free(szRealm);
Rob Shearman847cc512007-05-21 14:28:02 +01001144 return TRUE;
Rob Shearman4b507682007-05-21 14:26:26 +01001145 }
1146 else
1147 {
1148 LPCWSTR pszAuthData;
1149 SecBufferDesc out_desc, in_desc;
1150 SecBuffer out, in;
1151 unsigned char *buffer;
1152 ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
1153 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
1154
1155 in.BufferType = SECBUFFER_TOKEN;
1156 in.cbBuffer = 0;
1157 in.pvBuffer = NULL;
1158
1159 in_desc.ulVersion = 0;
1160 in_desc.cBuffers = 1;
1161 in_desc.pBuffers = &in;
1162
1163 pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
1164 if (*pszAuthData == ' ')
1165 {
1166 pszAuthData++;
1167 in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
Jacek Caban354a74e2011-04-21 13:39:03 +02001168 in.pvBuffer = heap_alloc(in.cbBuffer);
Rob Shearman4b507682007-05-21 14:26:26 +01001169 HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
1170 }
1171
Jacek Caban354a74e2011-04-21 13:39:03 +02001172 buffer = heap_alloc(pAuthInfo->max_token);
Rob Shearman4b507682007-05-21 14:26:26 +01001173
1174 out.BufferType = SECBUFFER_TOKEN;
Rob Shearman0be05ab2008-03-10 16:41:44 +00001175 out.cbBuffer = pAuthInfo->max_token;
Rob Shearman4b507682007-05-21 14:26:26 +01001176 out.pvBuffer = buffer;
1177
1178 out_desc.ulVersion = 0;
1179 out_desc.cBuffers = 1;
1180 out_desc.pBuffers = &out;
1181
Rob Shearman7b948712007-05-26 08:49:12 +01001182 sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
Rob Shearman5edcf3a2008-01-24 19:30:11 +00001183 first ? NULL : &pAuthInfo->ctx,
Juan Lang20980062011-03-01 11:18:22 -08001184 first ? request->session->serverName : NULL,
Rob Shearman4b507682007-05-21 14:26:26 +01001185 context_req, 0, SECURITY_NETWORK_DREP,
1186 in.pvBuffer ? &in_desc : NULL,
1187 0, &pAuthInfo->ctx, &out_desc,
1188 &pAuthInfo->attr, &pAuthInfo->exp);
1189 if (sec_status == SEC_E_OK)
1190 {
1191 pAuthInfo->finished = TRUE;
1192 pAuthInfo->auth_data = out.pvBuffer;
1193 pAuthInfo->auth_data_len = out.cbBuffer;
1194 TRACE("sending last auth packet\n");
1195 }
1196 else if (sec_status == SEC_I_CONTINUE_NEEDED)
1197 {
1198 pAuthInfo->auth_data = out.pvBuffer;
1199 pAuthInfo->auth_data_len = out.cbBuffer;
1200 TRACE("sending next auth packet\n");
1201 }
1202 else
1203 {
1204 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001205 heap_free(out.pvBuffer);
Hans Leidekker50fef742009-09-02 11:44:43 +02001206 destroy_authinfo(pAuthInfo);
1207 *ppAuthInfo = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001208 return FALSE;
1209 }
1210 }
1211
1212 return TRUE;
1213}
1214
Robert Shearmandee87512004-07-19 20:09:20 +00001215/***********************************************************************
Mike McCormackb288f712004-06-14 17:57:26 +00001216 * HTTP_HttpAddRequestHeadersW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001217 */
Juan Langb49b2432011-03-01 10:59:39 -08001218static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *request,
Mike McCormacka4e902c2004-03-30 04:36:09 +00001219 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001220{
Mike McCormacka4e902c2004-03-30 04:36:09 +00001221 LPWSTR lpszStart;
1222 LPWSTR lpszEnd;
1223 LPWSTR buffer;
Jacek Cabane9749652009-11-30 20:01:00 +01001224 DWORD len, res = ERROR_HTTP_INVALID_HEADER;
David Hammerton852c7ae2003-06-20 23:26:56 +00001225
Francois Gougetabfa73b2008-02-19 00:18:02 +01001226 TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
Mike McCormack08c6c692004-08-10 23:41:35 +00001227
Alexandre Julliard7c1925a02005-09-13 15:00:32 +00001228 if( dwHeaderLength == ~0U )
Mike McCormack08c6c692004-08-10 23:41:35 +00001229 len = strlenW(lpszHeader);
1230 else
1231 len = dwHeaderLength;
Jacek Caban354a74e2011-04-21 13:39:03 +02001232 buffer = heap_alloc(sizeof(WCHAR)*(len+1));
Peter Berg Larsene732fc02005-03-28 14:17:51 +00001233 lstrcpynW( buffer, lpszHeader, len + 1);
Mike McCormack08c6c692004-08-10 23:41:35 +00001234
Ulrich Czekallac2757242000-06-11 20:04:44 +00001235 lpszStart = buffer;
1236
1237 do
1238 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00001239 LPWSTR * pFieldAndValue;
1240
Ulrich Czekallac2757242000-06-11 20:04:44 +00001241 lpszEnd = lpszStart;
1242
1243 while (*lpszEnd != '\0')
1244 {
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001245 if (*lpszEnd == '\r' || *lpszEnd == '\n')
Ulrich Czekallac2757242000-06-11 20:04:44 +00001246 break;
1247 lpszEnd++;
1248 }
1249
Robert Shearman4cd38b42004-07-13 23:34:28 +00001250 if (*lpszStart == '\0')
Ulrich Czekallac2757242000-06-11 20:04:44 +00001251 break;
1252
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001253 if (*lpszEnd == '\r' || *lpszEnd == '\n')
Robert Shearman4cd38b42004-07-13 23:34:28 +00001254 {
1255 *lpszEnd = '\0';
Mike Kaplinskiy6c767c42009-06-14 18:29:31 -04001256 lpszEnd++; /* Jump over newline */
Robert Shearman4cd38b42004-07-13 23:34:28 +00001257 }
Mike McCormacka4e902c2004-03-30 04:36:09 +00001258 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
Paul TBBle Hampson4d57ee32009-04-25 02:31:06 +10001259 if (*lpszStart == '\0')
1260 {
1261 /* Skip 0-length headers */
1262 lpszStart = lpszEnd;
Jacek Cabane9749652009-11-30 20:01:00 +01001263 res = ERROR_SUCCESS;
Paul TBBle Hampson4d57ee32009-04-25 02:31:06 +10001264 continue;
1265 }
Robert Shearmanb72a6822004-09-23 22:53:50 +00001266 pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
1267 if (pFieldAndValue)
1268 {
Juan Langb49b2432011-03-01 10:59:39 -08001269 res = HTTP_VerifyValidHeader(request, pFieldAndValue[0]);
Jacek Cabane9749652009-11-30 20:01:00 +01001270 if (res == ERROR_SUCCESS)
Juan Langb49b2432011-03-01 10:59:39 -08001271 res = HTTP_ProcessHeader(request, pFieldAndValue[0],
Aric Stewartc8dfc022007-07-26 08:59:00 -05001272 pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
Robert Shearmanb72a6822004-09-23 22:53:50 +00001273 HTTP_FreeTokens(pFieldAndValue);
1274 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00001275
Robert Shearman4cd38b42004-07-13 23:34:28 +00001276 lpszStart = lpszEnd;
Jacek Cabane9749652009-11-30 20:01:00 +01001277 } while (res == ERROR_SUCCESS);
Ulrich Czekallac2757242000-06-11 20:04:44 +00001278
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001279 heap_free(buffer);
Jacek Cabane9749652009-11-30 20:01:00 +01001280 return res;
Mike McCormackb288f712004-06-14 17:57:26 +00001281}
1282
1283/***********************************************************************
1284 * HttpAddRequestHeadersW (WININET.@)
1285 *
1286 * Adds one or more HTTP header to the request handler
1287 *
Francois Gougetabfa73b2008-02-19 00:18:02 +01001288 * NOTE
1289 * On Windows if dwHeaderLength includes the trailing '\0', then
1290 * HttpAddRequestHeadersW() adds it too. However this results in an
1291 * invalid Http header which is rejected by some servers so we probably
1292 * don't need to match Windows on that point.
1293 *
Mike McCormackb288f712004-06-14 17:57:26 +00001294 * RETURNS
1295 * TRUE on success
1296 * FALSE on failure
1297 *
1298 */
1299BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
1300 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1301{
Juan Langb49b2432011-03-01 10:59:39 -08001302 http_request_t *request;
Jacek Cabane9749652009-11-30 20:01:00 +01001303 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
Mike McCormackb288f712004-06-14 17:57:26 +00001304
Francois Gougetabfa73b2008-02-19 00:18:02 +01001305 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
Mike McCormackb288f712004-06-14 17:57:26 +00001306
1307 if (!lpszHeader)
1308 return TRUE;
1309
Juan Langb49b2432011-03-01 10:59:39 -08001310 request = (http_request_t*) get_handle_object( hHttpRequest );
1311 if (request && request->hdr.htype == WH_HHTTPREQ)
1312 res = HTTP_HttpAddRequestHeadersW( request, lpszHeader, dwHeaderLength, dwModifier );
1313 if( request )
1314 WININET_Release( &request->hdr );
Mike McCormackb288f712004-06-14 17:57:26 +00001315
Jacek Cabane9749652009-11-30 20:01:00 +01001316 if(res != ERROR_SUCCESS)
1317 SetLastError(res);
1318 return res == ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00001319}
1320
Chris Morgana8b32162002-09-27 22:05:23 +00001321/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00001322 * HttpAddRequestHeadersA (WININET.@)
1323 *
1324 * Adds one or more HTTP header to the request handler
1325 *
1326 * RETURNS
1327 * TRUE on success
1328 * FALSE on failure
1329 *
1330 */
1331BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
1332 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1333{
1334 DWORD len;
1335 LPWSTR hdr;
1336 BOOL r;
1337
Francois Gougetabfa73b2008-02-19 00:18:02 +01001338 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001339
1340 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
Jacek Caban354a74e2011-04-21 13:39:03 +02001341 hdr = heap_alloc(len*sizeof(WCHAR));
Mike McCormacka4e902c2004-03-30 04:36:09 +00001342 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
Alexandre Julliard7c1925a02005-09-13 15:00:32 +00001343 if( dwHeaderLength != ~0U )
Mike McCormacka4e902c2004-03-30 04:36:09 +00001344 dwHeaderLength = len;
1345
1346 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
1347
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001348 heap_free( hdr );
Mike McCormacka4e902c2004-03-30 04:36:09 +00001349 return r;
1350}
1351
Hans Leidekker85e9e212011-09-27 11:40:33 +02001352static void free_accept_types( WCHAR **accept_types )
1353{
1354 WCHAR *ptr, **types = accept_types;
1355
1356 if (!types) return;
1357 while ((ptr = *types))
1358 {
1359 heap_free( ptr );
1360 types++;
1361 }
1362 heap_free( accept_types );
1363}
1364
1365static WCHAR **convert_accept_types( const char **accept_types )
1366{
1367 unsigned int count;
1368 const char **types = accept_types;
1369 WCHAR **typesW;
1370 BOOL invalid_pointer = FALSE;
1371
1372 if (!types) return NULL;
1373 count = 0;
1374 while (*types)
1375 {
1376 __TRY
1377 {
1378 /* find out how many there are */
1379 if (*types && **types)
1380 {
1381 TRACE("accept type: %s\n", debugstr_a(*types));
1382 count++;
1383 }
1384 }
1385 __EXCEPT_PAGE_FAULT
1386 {
1387 WARN("invalid accept type pointer\n");
1388 invalid_pointer = TRUE;
1389 }
1390 __ENDTRY;
1391 types++;
1392 }
1393 if (invalid_pointer) return NULL;
1394 if (!(typesW = heap_alloc( sizeof(WCHAR *) * (count + 1) ))) return NULL;
1395 count = 0;
1396 types = accept_types;
1397 while (*types)
1398 {
1399 if (*types && **types) typesW[count++] = heap_strdupAtoW( *types );
1400 types++;
1401 }
1402 typesW[count] = NULL;
1403 return typesW;
1404}
1405
Mike McCormacka4e902c2004-03-30 04:36:09 +00001406/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00001407 * HttpOpenRequestA (WININET.@)
Alberto Massarid476a5a2002-11-12 02:13:04 +00001408 *
1409 * Open a HTTP request handle
1410 *
1411 * RETURNS
1412 * HINTERNET a HTTP request handle on success
1413 * NULL on failure
1414 *
1415 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00001416HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
1417 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1418 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
Francois Gougetd4337f22007-08-30 16:21:33 +02001419 DWORD dwFlags, DWORD_PTR dwContext)
Alberto Massarid476a5a2002-11-12 02:13:04 +00001420{
Mike McCormacka4e902c2004-03-30 04:36:09 +00001421 LPWSTR szVerb = NULL, szObjectName = NULL;
1422 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
David Hammerton852c7ae2003-06-20 23:26:56 +00001423 HINTERNET rc = FALSE;
Hans Leidekker493b6912008-05-07 13:19:37 +02001424
Francois Gougetd4337f22007-08-30 16:21:33 +02001425 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
Mike McCormacka4e902c2004-03-30 04:36:09 +00001426 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1427 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
David Hammerton852c7ae2003-06-20 23:26:56 +00001428 dwFlags, dwContext);
Alberto Massaribc8bd722002-12-06 23:20:31 +00001429
David Hammerton852c7ae2003-06-20 23:26:56 +00001430 if (lpszVerb)
1431 {
Jacek Caban97936252009-07-17 01:17:13 +02001432 szVerb = heap_strdupAtoW(lpszVerb);
Mike McCormack43629c92003-08-15 03:47:30 +00001433 if ( !szVerb )
David Hammerton852c7ae2003-06-20 23:26:56 +00001434 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001435 }
1436
1437 if (lpszObjectName)
1438 {
Jacek Caban97936252009-07-17 01:17:13 +02001439 szObjectName = heap_strdupAtoW(lpszObjectName);
Mike McCormack43629c92003-08-15 03:47:30 +00001440 if ( !szObjectName )
David Hammerton852c7ae2003-06-20 23:26:56 +00001441 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001442 }
1443
1444 if (lpszVersion)
1445 {
Jacek Caban97936252009-07-17 01:17:13 +02001446 szVersion = heap_strdupAtoW(lpszVersion);
Mike McCormack43629c92003-08-15 03:47:30 +00001447 if ( !szVersion )
David Hammerton852c7ae2003-06-20 23:26:56 +00001448 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001449 }
1450
1451 if (lpszReferrer)
1452 {
Jacek Caban97936252009-07-17 01:17:13 +02001453 szReferrer = heap_strdupAtoW(lpszReferrer);
Mike McCormack43629c92003-08-15 03:47:30 +00001454 if ( !szReferrer )
David Hammerton852c7ae2003-06-20 23:26:56 +00001455 goto end;
David Hammerton852c7ae2003-06-20 23:26:56 +00001456 }
1457
Hans Leidekker85e9e212011-09-27 11:40:33 +02001458 szAcceptTypes = convert_accept_types( lpszAcceptTypes );
1459 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer,
1460 (const WCHAR **)szAcceptTypes, dwFlags, dwContext);
David Hammerton852c7ae2003-06-20 23:26:56 +00001461
1462end:
Hans Leidekker85e9e212011-09-27 11:40:33 +02001463 free_accept_types(szAcceptTypes);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001464 heap_free(szReferrer);
1465 heap_free(szVersion);
1466 heap_free(szObjectName);
1467 heap_free(szVerb);
David Hammerton852c7ae2003-06-20 23:26:56 +00001468 return rc;
Alberto Massarid476a5a2002-11-12 02:13:04 +00001469}
Ulrich Czekallac2757242000-06-11 20:04:44 +00001470
1471/***********************************************************************
Rob Shearmana9ebc702007-01-12 19:17:20 -06001472 * HTTP_EncodeBase64
Mike McCormacka1c16d22003-07-22 03:17:52 +00001473 */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001474static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001475{
1476 UINT n = 0, x;
Andrew Talbot46fc9c22007-02-24 21:55:12 +00001477 static const CHAR HTTP_Base64Enc[] =
Mike McCormacka1c16d22003-07-22 03:17:52 +00001478 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1479
Rob Shearmana9ebc702007-01-12 19:17:20 -06001480 while( len > 0 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001481 {
1482 /* first 6 bits, all from bin[0] */
1483 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1484 x = (bin[0] & 3) << 4;
1485
1486 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001487 if( len == 1 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001488 {
1489 base64[n++] = HTTP_Base64Enc[x];
1490 base64[n++] = '=';
1491 base64[n++] = '=';
1492 break;
1493 }
1494 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1495 x = ( bin[1] & 0x0f ) << 2;
1496
1497 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
Rob Shearmana9ebc702007-01-12 19:17:20 -06001498 if( len == 2 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001499 {
1500 base64[n++] = HTTP_Base64Enc[x];
1501 base64[n++] = '=';
1502 break;
1503 }
1504 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1505
1506 /* last 6 bits, all from bin [2] */
1507 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1508 bin += 3;
Rob Shearmana9ebc702007-01-12 19:17:20 -06001509 len -= 3;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001510 }
1511 base64[n] = 0;
1512 return n;
1513}
1514
Rob Shearman4b507682007-05-21 14:26:26 +01001515#define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1516 ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1517 ((x) >= '0' && (x) <= '9') ? (x) - '0' + 52 : \
1518 ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1519static const signed char HTTP_Base64Dec[256] =
1520{
1521 CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1522 CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1523 CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1524 CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1525 CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1526 CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1527 CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1528 CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1529 CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1530 CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1531 CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1532 CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1533 CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1534 CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1535 CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1536 CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1537 CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1538 CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1539 CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1540 CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1541 CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1542 CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1543 CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1544 CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1545 CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1546 CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1547};
1548#undef CH
1549
1550/***********************************************************************
1551 * HTTP_DecodeBase64
1552 */
1553static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
1554{
1555 unsigned int n = 0;
1556
1557 while(*base64)
1558 {
1559 signed char in[4];
1560
Rob Shearmanf8f9dbb2008-02-15 10:06:32 +00001561 if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
Rob Shearman4b507682007-05-21 14:26:26 +01001562 ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
Rob Shearmanf8f9dbb2008-02-15 10:06:32 +00001563 base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
Rob Shearman4b507682007-05-21 14:26:26 +01001564 ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1565 {
1566 WARN("invalid base64: %s\n", debugstr_w(base64));
1567 return 0;
1568 }
1569 if (bin)
1570 bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1571 n++;
1572
1573 if ((base64[2] == '=') && (base64[3] == '='))
1574 break;
1575 if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) ||
1576 ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1577 {
1578 WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1579 return 0;
1580 }
1581 if (bin)
1582 bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1583 n++;
1584
1585 if (base64[3] == '=')
1586 break;
1587 if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) ||
1588 ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1589 {
1590 WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1591 return 0;
1592 }
1593 if (bin)
1594 bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1595 n++;
1596
1597 base64 += 4;
1598 }
1599
1600 return n;
1601}
1602
Mike McCormacka1c16d22003-07-22 03:17:52 +00001603/***********************************************************************
Hans Leidekker1c5bc9a2008-05-09 15:18:51 +02001604 * HTTP_InsertAuthorization
Rob Shearman4b507682007-05-21 14:26:26 +01001605 *
1606 * Insert or delete the authorization field in the request header.
1607 */
Juan Langb49b2432011-03-01 10:59:39 -08001608static BOOL HTTP_InsertAuthorization( http_request_t *request, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
Rob Shearman4b507682007-05-21 14:26:26 +01001609{
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001610 if (pAuthInfo)
Rob Shearman4b507682007-05-21 14:26:26 +01001611 {
1612 static const WCHAR wszSpace[] = {' ',0};
Rob Shearman01826e02007-11-27 14:19:50 +00001613 static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
Rob Shearman4b507682007-05-21 14:26:26 +01001614 unsigned int len;
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001615 WCHAR *authorization = NULL;
Rob Shearman4b507682007-05-21 14:26:26 +01001616
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001617 if (pAuthInfo->auth_data_len)
Rob Shearman01826e02007-11-27 14:19:50 +00001618 {
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001619 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1620 len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
Jacek Caban354a74e2011-04-21 13:39:03 +02001621 authorization = heap_alloc((len+1)*sizeof(WCHAR));
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001622 if (!authorization)
1623 return FALSE;
1624
1625 strcpyW(authorization, pAuthInfo->scheme);
1626 strcatW(authorization, wszSpace);
1627 HTTP_EncodeBase64(pAuthInfo->auth_data,
1628 pAuthInfo->auth_data_len,
1629 authorization+strlenW(authorization));
1630
1631 /* clear the data as it isn't valid now that it has been sent to the
1632 * server, unless it's Basic authentication which doesn't do
1633 * connection tracking */
1634 if (strcmpiW(pAuthInfo->scheme, wszBasic))
1635 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001636 heap_free(pAuthInfo->auth_data);
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001637 pAuthInfo->auth_data = NULL;
1638 pAuthInfo->auth_data_len = 0;
1639 }
Rob Shearman01826e02007-11-27 14:19:50 +00001640 }
Rob Shearmanebaa4d92008-03-12 13:27:46 +00001641
1642 TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1643
Juan Langb49b2432011-03-01 10:59:39 -08001644 HTTP_ProcessHeader(request, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001645 heap_free(authorization);
Rob Shearman4b507682007-05-21 14:26:26 +01001646 }
Rob Shearman4b507682007-05-21 14:26:26 +01001647 return TRUE;
1648}
1649
Jacek Caban34abacd2009-07-13 01:41:50 +02001650static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001651{
André Hentscheld8f036e2011-08-22 21:31:14 +02001652 static const WCHAR slash[] = { '/',0 };
1653 static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 };
1654 static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','u',0 };
1655 http_session_t *session = req->session;
Hans Leidekker612f3c12008-03-31 20:26:16 +02001656 WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001657 DWORD size;
1658
1659 size = sizeof(new_location);
Jacek Caban9823c232009-12-14 02:27:29 +01001660 if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS)
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001661 {
André Hentscheld8f036e2011-08-22 21:31:14 +02001662 URL_COMPONENTSW UrlComponents;
1663
Jacek Caban354a74e2011-04-21 13:39:03 +02001664 if (!(url = heap_alloc(size + sizeof(WCHAR)))) return NULL;
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001665 strcpyW( url, new_location );
André Hentscheld8f036e2011-08-22 21:31:14 +02001666
1667 ZeroMemory(&UrlComponents,sizeof(URL_COMPONENTSW));
1668 if(InternetCrackUrlW(url, 0, 0, &UrlComponents)) goto done;
1669 heap_free(url);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001670 }
André Hentscheld8f036e2011-08-22 21:31:14 +02001671
1672 size = 16; /* "https://" + sizeof(port#) + ":/\0" */
1673 size += strlenW( session->hostName ) + strlenW( req->path );
1674
1675 if (!(url = heap_alloc(size * sizeof(WCHAR)))) return NULL;
1676
1677 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1678 sprintfW( url, formatSSL, session->hostName, session->hostPort );
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001679 else
André Hentscheld8f036e2011-08-22 21:31:14 +02001680 sprintfW( url, format, session->hostName, session->hostPort );
1681 if (req->path[0] != '/') strcatW( url, slash );
1682 strcatW( url, req->path );
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001683
André Hentscheld8f036e2011-08-22 21:31:14 +02001684done:
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001685 TRACE("url=%s\n", debugstr_w(url));
1686 return url;
1687}
1688
Rob Shearman4b507682007-05-21 14:26:26 +01001689/***********************************************************************
Mike McCormacka1c16d22003-07-22 03:17:52 +00001690 * HTTP_DealWithProxy
1691 */
Juan Langb49b2432011-03-01 10:59:39 -08001692static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *session, http_request_t *request)
Mike McCormacka1c16d22003-07-22 03:17:52 +00001693{
André Hentschel0fda1352011-08-22 21:30:55 +02001694 WCHAR buf[INTERNET_MAX_HOST_NAME_LENGTH];
1695 WCHAR protoProxy[INTERNET_MAX_URL_LENGTH];
1696 DWORD protoProxyLen = INTERNET_MAX_URL_LENGTH;
1697 WCHAR proxy[INTERNET_MAX_URL_LENGTH];
Hans Leidekker781f3f72006-10-13 15:43:54 +02001698 static WCHAR szNul[] = { 0 };
Mike McCormacka4e902c2004-03-30 04:36:09 +00001699 URL_COMPONENTSW UrlComponents;
Juan Langde6a0a82010-03-13 09:36:46 -08001700 static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001701 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1702 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
Mike McCormacka1c16d22003-07-22 03:17:52 +00001703
1704 memset( &UrlComponents, 0, sizeof UrlComponents );
1705 UrlComponents.dwStructSize = sizeof UrlComponents;
1706 UrlComponents.lpszHostName = buf;
André Hentschel0fda1352011-08-22 21:30:55 +02001707 UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001708
Juan Lang72431562011-03-01 11:00:49 -08001709 if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen))
Juan Langde6a0a82010-03-13 09:36:46 -08001710 return FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00001711 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
Juan Langde6a0a82010-03-13 09:36:46 -08001712 protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1713 sprintfW(proxy, szFormat, protoProxy);
Uwe Bonnes599c4522003-12-15 19:47:31 +00001714 else
Juan Langde6a0a82010-03-13 09:36:46 -08001715 strcpyW(proxy, protoProxy);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001716 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001717 return FALSE;
1718 if( UrlComponents.dwHostNameLength == 0 )
1719 return FALSE;
1720
Juan Lang20980062011-03-01 11:18:22 -08001721 if( !request->path )
1722 request->path = szNul;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001723
1724 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1725 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1726
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001727 heap_free(session->serverName);
Juan Lang8e050392011-03-01 11:02:14 -08001728 session->serverName = heap_strdupW(UrlComponents.lpszHostName);
1729 session->serverPort = UrlComponents.nPort;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001730
Juan Lang8e050392011-03-01 11:02:14 -08001731 TRACE("proxy server=%s port=%d\n", debugstr_w(session->serverName), session->serverPort);
Mike McCormacka1c16d22003-07-22 03:17:52 +00001732 return TRUE;
1733}
1734
Jacek Caban8a1df202011-05-10 09:26:43 +00001735static DWORD HTTP_ResolveName(http_request_t *request, server_t *server)
Rob Shearman72575a02006-12-07 00:52:50 +00001736{
Jacek Caban8a1df202011-05-10 09:26:43 +00001737 socklen_t addr_len;
Juan Lang058e9182009-07-09 11:36:00 -07001738 const void *addr;
Rob Shearman72575a02006-12-07 00:52:50 +00001739
Jacek Caban8a1df202011-05-10 09:26:43 +00001740 if(server->addr_len)
1741 return ERROR_SUCCESS;
1742
Juan Langb49b2432011-03-01 10:59:39 -08001743 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001744 INTERNET_STATUS_RESOLVING_NAME,
Jacek Caban8a1df202011-05-10 09:26:43 +00001745 server->name,
1746 (strlenW(server->name)+1) * sizeof(WCHAR));
Rob Shearman72575a02006-12-07 00:52:50 +00001747
Jacek Caban8a1df202011-05-10 09:26:43 +00001748 addr_len = sizeof(server->addr);
1749 if (!GetAddress(server->name, server->port, (struct sockaddr *)&server->addr, &addr_len))
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001750 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Rob Shearman72575a02006-12-07 00:52:50 +00001751
Jacek Caban8a1df202011-05-10 09:26:43 +00001752 switch(server->addr.ss_family) {
Juan Lang058e9182009-07-09 11:36:00 -07001753 case AF_INET:
Jacek Caban8a1df202011-05-10 09:26:43 +00001754 addr = &((struct sockaddr_in *)&server->addr)->sin_addr;
Juan Lang058e9182009-07-09 11:36:00 -07001755 break;
Juan Lang481c9b82009-07-09 11:42:25 -07001756 case AF_INET6:
Jacek Caban8a1df202011-05-10 09:26:43 +00001757 addr = &((struct sockaddr_in6 *)&server->addr)->sin6_addr;
Juan Lang481c9b82009-07-09 11:42:25 -07001758 break;
Juan Lang058e9182009-07-09 11:36:00 -07001759 default:
Jacek Caban8a1df202011-05-10 09:26:43 +00001760 WARN("unsupported family %d\n", server->addr.ss_family);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001761 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Juan Lang058e9182009-07-09 11:36:00 -07001762 }
Jacek Caban8a1df202011-05-10 09:26:43 +00001763
1764 server->addr_len = addr_len;
1765 inet_ntop(server->addr.ss_family, addr, server->addr_str, sizeof(server->addr_str));
Juan Langb49b2432011-03-01 10:59:39 -08001766 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001767 INTERNET_STATUS_NAME_RESOLVED,
Jacek Caban8a1df202011-05-10 09:26:43 +00001768 server->addr_str, strlen(server->addr_str)+1);
Hans Leidekker2f994502008-05-31 21:46:07 +02001769
Jacek Caban8a1df202011-05-10 09:26:43 +00001770 TRACE("resolved %s to %s\n", debugstr_w(server->name), server->addr_str);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001771 return ERROR_SUCCESS;
Rob Shearman72575a02006-12-07 00:52:50 +00001772}
1773
Piotr Caban75481bd2010-07-24 17:56:41 +02001774static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1775{
Juan Langb9c348a2011-03-02 08:28:39 -08001776 static const WCHAR http[] = { 'h','t','t','p',':','/','/',0 };
1777 static const WCHAR https[] = { 'h','t','t','p','s',':','/','/',0 };
1778 static const WCHAR slash[] = { '/',0 };
Piotr Caban75481bd2010-07-24 17:56:41 +02001779 LPHTTPHEADERW host_header;
Juan Langb9c348a2011-03-02 08:28:39 -08001780 LPCWSTR scheme;
Piotr Caban75481bd2010-07-24 17:56:41 +02001781
1782 host_header = HTTP_GetHeader(req, hostW);
1783 if(!host_header)
1784 return FALSE;
1785
Juan Langb9c348a2011-03-02 08:28:39 -08001786 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1787 scheme = https;
1788 else
1789 scheme = http;
1790 strcpyW(buf, scheme);
1791 strcatW(buf, host_header->lpszValue);
1792 if (req->path[0] != '/')
1793 strcatW(buf, slash);
1794 strcatW(buf, req->path);
Piotr Caban75481bd2010-07-24 17:56:41 +02001795 return TRUE;
1796}
1797
Jacek Caban5a535d62008-02-26 20:20:41 +01001798
1799/***********************************************************************
1800 * HTTPREQ_Destroy (internal)
1801 *
1802 * Deallocate request handle
1803 *
1804 */
Jacek Caban44d633a2009-07-07 21:46:09 +02001805static void HTTPREQ_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01001806{
Juan Langb49b2432011-03-01 10:59:39 -08001807 http_request_t *request = (http_request_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01001808 DWORD i;
1809
1810 TRACE("\n");
1811
Juan Langb49b2432011-03-01 10:59:39 -08001812 if(request->hCacheFile) {
Piotr Caban75481bd2010-07-24 17:56:41 +02001813 WCHAR url[INTERNET_MAX_URL_LENGTH];
Piotr Caban75481bd2010-07-24 17:56:41 +02001814
Juan Langb49b2432011-03-01 10:59:39 -08001815 CloseHandle(request->hCacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001816
Juan Langb49b2432011-03-01 10:59:39 -08001817 if(HTTP_GetRequestURL(request, url)) {
Juan Lang011b26b2011-03-03 15:33:40 -08001818 DWORD headersLen;
1819
1820 headersLen = request->rawHeaders ? strlenW(request->rawHeaders) : 0;
Juan Lang28e92292011-03-04 11:43:54 -08001821 CommitUrlCacheEntryW(url, request->cacheFile, request->expires,
Juan Lang011b26b2011-03-03 15:33:40 -08001822 request->last_modified, NORMAL_CACHE_ENTRY,
1823 request->rawHeaders, headersLen, NULL, 0);
Piotr Caban75481bd2010-07-24 17:56:41 +02001824 }
1825 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001826 heap_free(request->cacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001827
Francois Gouget17929b92011-11-16 16:29:44 +01001828 request->read_section.DebugInfo->Spare[0] = 0;
Juan Langb49b2432011-03-01 10:59:39 -08001829 DeleteCriticalSection( &request->read_section );
Juan Lang20980062011-03-01 11:18:22 -08001830 WININET_Release(&request->session->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01001831
Juan Lang20980062011-03-01 11:18:22 -08001832 destroy_authinfo(request->authInfo);
1833 destroy_authinfo(request->proxyAuthInfo);
Hans Leidekkerd5dca632008-10-17 13:46:25 +02001834
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001835 heap_free(request->path);
1836 heap_free(request->verb);
1837 heap_free(request->rawHeaders);
1838 heap_free(request->version);
1839 heap_free(request->statusText);
Jacek Caban5a535d62008-02-26 20:20:41 +01001840
Juan Langb49b2432011-03-01 10:59:39 -08001841 for (i = 0; i < request->nCustHeaders; i++)
Jacek Caban5a535d62008-02-26 20:20:41 +01001842 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001843 heap_free(request->custHeaders[i].lpszField);
1844 heap_free(request->custHeaders[i].lpszValue);
Jacek Caban5a535d62008-02-26 20:20:41 +01001845 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02001846 destroy_data_stream(request->data_stream);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001847 heap_free(request->custHeaders);
Jacek Caban5a535d62008-02-26 20:20:41 +01001848}
1849
Jacek Caban8a1df202011-05-10 09:26:43 +00001850static void http_release_netconn(http_request_t *req, BOOL reuse)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001851{
Jacek Caban8a1df202011-05-10 09:26:43 +00001852 TRACE("%p %p\n",req, req->netconn);
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001853
Jacek Caban8a1df202011-05-10 09:26:43 +00001854 if(!req->netconn)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001855 return;
1856
Jacek Caban8a1df202011-05-10 09:26:43 +00001857 if(reuse && req->netconn->keep_alive) {
1858 BOOL run_collector;
1859
1860 EnterCriticalSection(&connection_pool_cs);
1861
1862 list_add_head(&req->netconn->server->conn_pool, &req->netconn->pool_entry);
1863 req->netconn->keep_until = GetTickCount64() + COLLECT_TIME;
1864 req->netconn = NULL;
1865
1866 run_collector = !collector_running;
1867 collector_running = TRUE;
1868
1869 LeaveCriticalSection(&connection_pool_cs);
1870
1871 if(run_collector) {
1872 HANDLE thread = NULL;
1873 HMODULE module;
1874
1875 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)WININET_hModule, &module);
1876 if(module)
1877 thread = CreateThread(NULL, 0, collect_connections_proc, NULL, 0, NULL);
1878 if(!thread) {
1879 EnterCriticalSection(&connection_pool_cs);
1880 collector_running = FALSE;
1881 LeaveCriticalSection(&connection_pool_cs);
1882
1883 if(module)
1884 FreeLibrary(module);
1885 }
Pierre Schweitzer85e2b4d2011-12-30 21:55:42 +01001886 else
1887 CloseHandle(thread);
Jacek Caban8a1df202011-05-10 09:26:43 +00001888 }
1889 return;
1890 }
1891
1892 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001893 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1894
Jacek Caban8a1df202011-05-10 09:26:43 +00001895 free_netconn(req->netconn);
1896 req->netconn = NULL;
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001897
Jacek Caban8a1df202011-05-10 09:26:43 +00001898 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001899 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1900}
1901
Jacek Caban8a1df202011-05-10 09:26:43 +00001902static void drain_content(http_request_t *req)
1903{
1904 BOOL try_reuse;
1905
1906 if (!req->netconn) return;
1907
1908 if (req->contentLength == -1)
1909 try_reuse = FALSE;
1910 else if(!strcmpW(req->verb, szHEAD))
1911 try_reuse = TRUE;
1912 else
1913 try_reuse = req->data_stream->vtbl->drain_content(req->data_stream, req);
1914
1915 http_release_netconn(req, try_reuse);
1916}
1917
Juan Langb49b2432011-03-01 10:59:39 -08001918static BOOL HTTP_KeepAlive(http_request_t *request)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001919{
1920 WCHAR szVersion[10];
1921 WCHAR szConnectionResponse[20];
1922 DWORD dwBufferSize = sizeof(szVersion);
1923 BOOL keepalive = FALSE;
1924
1925 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1926 * the connection is keep-alive by default */
Juan Langb49b2432011-03-01 10:59:39 -08001927 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS
Jacek Caban9823c232009-12-14 02:27:29 +01001928 && !strcmpiW(szVersion, g_szHttp1_1))
Juan Lang6ae6ea92009-08-10 15:20:45 -07001929 {
1930 keepalive = TRUE;
1931 }
1932
1933 dwBufferSize = sizeof(szConnectionResponse);
Juan Langb49b2432011-03-01 10:59:39 -08001934 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
1935 || HTTP_HttpQueryInfoW(request, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001936 {
1937 keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1938 }
1939
1940 return keepalive;
1941}
1942
Jacek Caban8a1df202011-05-10 09:26:43 +00001943static void HTTPREQ_CloseConnection(object_header_t *hdr)
1944{
1945 http_request_t *req = (http_request_t*)hdr;
1946
1947 drain_content(req);
1948}
1949
Jacek Caban44d633a2009-07-07 21:46:09 +02001950static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01001951{
Jacek Caban34abacd2009-07-13 01:41:50 +02001952 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e010d82008-03-12 02:23:48 +01001953
Jacek Cabane2933c22008-03-12 02:23:20 +01001954 switch(option) {
Juan Lang6ae6ea92009-08-10 15:20:45 -07001955 case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1956 {
Juan Lang20980062011-03-01 11:18:22 -08001957 http_session_t *session = req->session;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001958 INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1959
1960 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1961
1962 if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1963 return ERROR_INSUFFICIENT_BUFFER;
1964 *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1965 /* FIXME: can't get a SOCKET from our connection since we don't use
1966 * winsock
1967 */
1968 info->Socket = 0;
1969 /* FIXME: get source port from req->netConnection */
1970 info->SourcePort = 0;
Juan Lang8e050392011-03-01 11:02:14 -08001971 info->DestPort = session->hostPort;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001972 info->Flags = 0;
1973 if (HTTP_KeepAlive(req))
1974 info->Flags |= IDSI_FLAG_KEEP_ALIVE;
Juan Lang8e050392011-03-01 11:02:14 -08001975 if (session->appInfo->proxy && session->appInfo->proxy[0] != 0)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001976 info->Flags |= IDSI_FLAG_PROXY;
Jacek Caban8a1df202011-05-10 09:26:43 +00001977 if (req->netconn->useSSL)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001978 info->Flags |= IDSI_FLAG_SECURE;
1979
1980 return ERROR_SUCCESS;
1981 }
1982
Aric Stewartc6ae9452009-06-23 15:29:00 +09001983 case INTERNET_OPTION_SECURITY_FLAGS:
1984 {
Juan Lang948173b2010-09-30 13:33:47 -07001985 DWORD flags;
Aric Stewartc6ae9452009-06-23 15:29:00 +09001986
1987 if (*size < sizeof(ULONG))
1988 return ERROR_INSUFFICIENT_BUFFER;
1989
1990 *size = sizeof(DWORD);
Juan Lang948173b2010-09-30 13:33:47 -07001991 flags = 0;
Juan Lang80545ef2010-09-30 17:11:56 -07001992 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
Juan Lang948173b2010-09-30 13:33:47 -07001993 flags |= SECURITY_FLAG_SECURE;
Jacek Caban8a1df202011-05-10 09:26:43 +00001994 flags |= req->security_flags;
1995 if(req->netconn) {
1996 int bits = NETCON_GetCipherStrength(req->netconn);
1997 if (bits >= 128)
1998 flags |= SECURITY_FLAG_STRENGTH_STRONG;
1999 else if (bits >= 56)
2000 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
2001 else
2002 flags |= SECURITY_FLAG_STRENGTH_WEAK;
2003 }
Juan Lang948173b2010-09-30 13:33:47 -07002004 *(DWORD *)buffer = flags;
Aric Stewartc6ae9452009-06-23 15:29:00 +09002005 return ERROR_SUCCESS;
2006 }
2007
Jacek Cabane2933c22008-03-12 02:23:20 +01002008 case INTERNET_OPTION_HANDLE_TYPE:
2009 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2010
2011 if (*size < sizeof(ULONG))
2012 return ERROR_INSUFFICIENT_BUFFER;
2013
2014 *size = sizeof(DWORD);
2015 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
2016 return ERROR_SUCCESS;
Jacek Caban0e010d82008-03-12 02:23:48 +01002017
2018 case INTERNET_OPTION_URL: {
2019 WCHAR url[INTERNET_MAX_URL_LENGTH];
2020 HTTPHEADERW *host;
2021 DWORD len;
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002022 WCHAR *pch;
Jacek Caban0e010d82008-03-12 02:23:48 +01002023
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002024 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
Jacek Caban0e010d82008-03-12 02:23:48 +01002025
2026 TRACE("INTERNET_OPTION_URL\n");
2027
2028 host = HTTP_GetHeader(req, hostW);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002029 strcpyW(url, httpW);
2030 strcatW(url, host->lpszValue);
2031 if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
2032 *pch = 0;
Juan Lang20980062011-03-01 11:18:22 -08002033 strcatW(url, req->path);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002034
Jacek Caban0e010d82008-03-12 02:23:48 +01002035 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
2036
2037 if(unicode) {
2038 len = (strlenW(url)+1) * sizeof(WCHAR);
2039 if(*size < len)
2040 return ERROR_INSUFFICIENT_BUFFER;
2041
2042 *size = len;
2043 strcpyW(buffer, url);
2044 return ERROR_SUCCESS;
2045 }else {
2046 len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
2047 if(len > *size)
2048 return ERROR_INSUFFICIENT_BUFFER;
2049
2050 *size = len;
2051 return ERROR_SUCCESS;
2052 }
2053 }
Jacek Cabance6a2282008-03-12 02:24:06 +01002054
Hans Leidekkerc2932852009-06-16 15:13:52 +02002055 case INTERNET_OPTION_CACHE_TIMESTAMPS: {
2056 INTERNET_CACHE_ENTRY_INFOW *info;
2057 INTERNET_CACHE_TIMESTAMPS *ts = buffer;
2058 WCHAR url[INTERNET_MAX_URL_LENGTH];
2059 DWORD nbytes, error;
2060 BOOL ret;
2061
2062 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
2063
2064 if (*size < sizeof(*ts))
2065 {
2066 *size = sizeof(*ts);
2067 return ERROR_INSUFFICIENT_BUFFER;
2068 }
2069 nbytes = 0;
2070 HTTP_GetRequestURL(req, url);
2071 ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
2072 error = GetLastError();
2073 if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
2074 {
Jacek Caban354a74e2011-04-21 13:39:03 +02002075 if (!(info = heap_alloc(nbytes)))
Hans Leidekkerc2932852009-06-16 15:13:52 +02002076 return ERROR_OUTOFMEMORY;
2077
2078 GetUrlCacheEntryInfoW(url, info, &nbytes);
2079
2080 ts->ftExpires = info->ExpireTime;
2081 ts->ftLastModified = info->LastModifiedTime;
2082
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002083 heap_free(info);
Hans Leidekkerc2932852009-06-16 15:13:52 +02002084 *size = sizeof(*ts);
2085 return ERROR_SUCCESS;
2086 }
2087 return error;
2088 }
2089
Jacek Cabance6a2282008-03-12 02:24:06 +01002090 case INTERNET_OPTION_DATAFILE_NAME: {
2091 DWORD req_size;
2092
2093 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
2094
Juan Lang20980062011-03-01 11:18:22 -08002095 if(!req->cacheFile) {
Jacek Cabance6a2282008-03-12 02:24:06 +01002096 *size = 0;
2097 return ERROR_INTERNET_ITEM_NOT_FOUND;
2098 }
2099
2100 if(unicode) {
Juan Lang20980062011-03-01 11:18:22 -08002101 req_size = (lstrlenW(req->cacheFile)+1) * sizeof(WCHAR);
Jacek Cabance6a2282008-03-12 02:24:06 +01002102 if(*size < req_size)
2103 return ERROR_INSUFFICIENT_BUFFER;
2104
2105 *size = req_size;
Juan Lang20980062011-03-01 11:18:22 -08002106 memcpy(buffer, req->cacheFile, *size);
Jacek Cabance6a2282008-03-12 02:24:06 +01002107 return ERROR_SUCCESS;
2108 }else {
Juan Lang20980062011-03-01 11:18:22 -08002109 req_size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile, -1, NULL, 0, NULL, NULL);
Jacek Cabance6a2282008-03-12 02:24:06 +01002110 if (req_size > *size)
2111 return ERROR_INSUFFICIENT_BUFFER;
2112
Juan Lang20980062011-03-01 11:18:22 -08002113 *size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile,
Jacek Cabance6a2282008-03-12 02:24:06 +01002114 -1, buffer, *size, NULL, NULL);
2115 return ERROR_SUCCESS;
2116 }
2117 }
Jacek Caban7e63f952008-03-12 02:24:23 +01002118
2119 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
2120 PCCERT_CONTEXT context;
2121
Juan Lang56ebc042010-09-30 13:09:04 -07002122 if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
2123 *size = sizeof(INTERNET_CERTIFICATE_INFOA);
Jacek Caban7e63f952008-03-12 02:24:23 +01002124 return ERROR_INSUFFICIENT_BUFFER;
2125 }
2126
Jacek Caban8a1df202011-05-10 09:26:43 +00002127 context = (PCCERT_CONTEXT)NETCON_GetCert(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002128 if(context) {
Juan Lang56ebc042010-09-30 13:09:04 -07002129 INTERNET_CERTIFICATE_INFOA *info = (INTERNET_CERTIFICATE_INFOA*)buffer;
Jacek Caban7e63f952008-03-12 02:24:23 +01002130 DWORD len;
2131
2132 memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
2133 info->ftExpiry = context->pCertInfo->NotAfter;
2134 info->ftStart = context->pCertInfo->NotBefore;
Juan Lang56ebc042010-09-30 13:09:04 -07002135 len = CertNameToStrA(context->dwCertEncodingType,
2136 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
2137 info->lpszSubjectInfo = LocalAlloc(0, len);
2138 if(info->lpszSubjectInfo)
2139 CertNameToStrA(context->dwCertEncodingType,
2140 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2141 info->lpszSubjectInfo, len);
2142 len = CertNameToStrA(context->dwCertEncodingType,
2143 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
2144 info->lpszIssuerInfo = LocalAlloc(0, len);
2145 if(info->lpszIssuerInfo)
2146 CertNameToStrA(context->dwCertEncodingType,
2147 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2148 info->lpszIssuerInfo, len);
Jacek Caban8a1df202011-05-10 09:26:43 +00002149 info->dwKeySize = NETCON_GetCipherStrength(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002150 CertFreeCertificateContext(context);
2151 return ERROR_SUCCESS;
2152 }
2153 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01002154 case INTERNET_OPTION_CONNECT_TIMEOUT:
2155 if (*size < sizeof(DWORD))
2156 return ERROR_INSUFFICIENT_BUFFER;
2157
2158 *size = sizeof(DWORD);
2159 *(DWORD *)buffer = req->connect_timeout;
2160 return ERROR_SUCCESS;
Jacek Cabane2933c22008-03-12 02:23:20 +01002161 }
2162
Hans Leidekker80dd3672010-05-25 12:19:32 +02002163 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01002164}
2165
Jacek Caban44d633a2009-07-07 21:46:09 +02002166static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Jacek Caban0e33eee2008-02-26 20:22:02 +01002167{
Jacek Caban34abacd2009-07-13 01:41:50 +02002168 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002169
2170 switch(option) {
Juan Lang77c4ade2010-09-28 16:46:41 -07002171 case INTERNET_OPTION_SECURITY_FLAGS:
2172 {
2173 DWORD flags;
2174
2175 if (!buffer || size != sizeof(DWORD))
2176 return ERROR_INVALID_PARAMETER;
2177 flags = *(DWORD *)buffer;
2178 TRACE("%08x\n", flags);
Jacek Caban8a1df202011-05-10 09:26:43 +00002179 req->security_flags = flags;
2180 if(req->netconn)
2181 req->netconn->security_flags = flags;
Juan Lang77c4ade2010-09-28 16:46:41 -07002182 return ERROR_SUCCESS;
2183 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01002184 case INTERNET_OPTION_CONNECT_TIMEOUT:
2185 if (size != sizeof(DWORD))
2186 return ERROR_INVALID_PARAMETER;
2187
2188 req->connect_timeout = *(DWORD *)buffer;
2189 return ERROR_SUCCESS;
2190
Jacek Caban0e33eee2008-02-26 20:22:02 +01002191 case INTERNET_OPTION_SEND_TIMEOUT:
2192 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2193 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
2194
2195 if (size != sizeof(DWORD))
2196 return ERROR_INVALID_PARAMETER;
2197
Jacek Caban8a1df202011-05-10 09:26:43 +00002198 if(!req->netconn) {
Jacek Caban4c1c5fe2011-05-04 11:47:32 +00002199 FIXME("unsupported without active connection\n");
2200 return ERROR_SUCCESS;
2201 }
2202
Jacek Caban8a1df202011-05-10 09:26:43 +00002203 return NETCON_set_timeout(req->netconn, option == INTERNET_OPTION_SEND_TIMEOUT,
Jacek Caban0e33eee2008-02-26 20:22:02 +01002204 *(DWORD*)buffer);
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002205
2206 case INTERNET_OPTION_USERNAME:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002207 heap_free(req->session->userName);
Juan Lang20980062011-03-01 11:18:22 -08002208 if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002209 return ERROR_SUCCESS;
2210
2211 case INTERNET_OPTION_PASSWORD:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002212 heap_free(req->session->password);
Juan Lang20980062011-03-01 11:18:22 -08002213 if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002214 return ERROR_SUCCESS;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002215 case INTERNET_OPTION_HTTP_DECODING:
2216 if(size != sizeof(BOOL))
2217 return ERROR_INVALID_PARAMETER;
2218 req->decoding = *(BOOL*)buffer;
2219 return ERROR_SUCCESS;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002220 }
2221
2222 return ERROR_INTERNET_INVALID_OPTION;
2223}
2224
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002225/* read some more data into the read buffer (the read section must be held) */
Jacek Caban1d96e202009-11-30 19:59:56 +01002226static DWORD read_more_data( http_request_t *req, int maxlen )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002227{
Jacek Caban358e7b72009-11-30 19:59:40 +01002228 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002229 int len;
2230
Jacek Caban11ca05f2009-05-29 23:35:13 +02002231 if (req->read_pos)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002232 {
2233 /* move existing data to the start of the buffer */
Jacek Caban11ca05f2009-05-29 23:35:13 +02002234 if(req->read_size)
2235 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002236 req->read_pos = 0;
2237 }
2238
2239 if (maxlen == -1) maxlen = sizeof(req->read_buf);
Jacek Caban11ca05f2009-05-29 23:35:13 +02002240
Jacek Caban8a1df202011-05-10 09:26:43 +00002241 res = NETCON_recv( req->netconn, req->read_buf + req->read_size,
Jacek Caban358e7b72009-11-30 19:59:40 +01002242 maxlen - req->read_size, 0, &len );
Jacek Caban1d96e202009-11-30 19:59:56 +01002243 if(res == ERROR_SUCCESS)
2244 req->read_size += len;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002245
Jacek Caban1d96e202009-11-30 19:59:56 +01002246 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002247}
2248
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002249/* remove some amount of data from the read buffer (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002250static void remove_data( http_request_t *req, int count )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002251{
2252 if (!(req->read_size -= count)) req->read_pos = 0;
2253 else req->read_pos += count;
2254}
2255
Jacek Caban34abacd2009-07-13 01:41:50 +02002256static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002257{
2258 int count, bytes_read, pos = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002259 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002260
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002261 EnterCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002262 for (;;)
2263 {
Jacek Caban26bbf072009-05-29 23:34:37 +02002264 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002265
2266 if (eol)
2267 {
2268 count = eol - (req->read_buf + req->read_pos);
2269 bytes_read = count + 1;
2270 }
2271 else count = bytes_read = req->read_size;
2272
2273 count = min( count, *len - pos );
2274 memcpy( buffer + pos, req->read_buf + req->read_pos, count );
2275 pos += count;
2276 remove_data( req, bytes_read );
2277 if (eol) break;
2278
Jacek Caban1d96e202009-11-30 19:59:56 +01002279 if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002280 {
2281 *len = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00002282 TRACE( "returning empty string %u\n", res);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002283 LeaveCriticalSection( &req->read_section );
Jacek Caban1d96e202009-11-30 19:59:56 +01002284 INTERNET_SetLastError(res);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002285 return FALSE;
2286 }
2287 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002288 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002289
2290 if (pos < *len)
2291 {
2292 if (pos && buffer[pos - 1] == '\r') pos--;
2293 *len = pos + 1;
2294 }
2295 buffer[*len - 1] = 0;
2296 TRACE( "returning %s\n", debugstr_a(buffer));
2297 return TRUE;
2298}
2299
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002300/* check if we have reached the end of the data to read (the read section must be held) */
2301static BOOL end_of_read_data( http_request_t *req )
2302{
2303 return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req);
2304}
2305
2306/* fetch some more data into the read buffer (the read section must be held) */
Jacek Caban193da882011-05-23 16:10:09 +02002307static DWORD refill_read_buffer(http_request_t *req, read_mode_t read_mode, DWORD *read_bytes)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002308{
2309 DWORD res, read=0;
2310
2311 if(req->read_size == sizeof(req->read_buf))
2312 return ERROR_SUCCESS;
2313
2314 if(req->read_pos) {
2315 if(req->read_size)
2316 memmove(req->read_buf, req->read_buf+req->read_pos, req->read_size);
2317 req->read_pos = 0;
2318 }
2319
2320 res = req->data_stream->vtbl->read(req->data_stream, req, req->read_buf+req->read_size,
2321 sizeof(req->read_buf)-req->read_size, &read, read_mode);
2322 req->read_size += read;
2323
2324 TRACE("read %u bytes, read_size %u\n", read, req->read_size);
Jacek Caban193da882011-05-23 16:10:09 +02002325 if(read_bytes)
2326 *read_bytes = read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002327 return res;
2328}
2329
2330/* return the size of data available to be read immediately (the read section must be held) */
2331static DWORD get_avail_data( http_request_t *req )
2332{
2333 return req->read_size + req->data_stream->vtbl->get_avail_data(req->data_stream, req);
2334}
2335
2336static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req)
2337{
Jacek Caban8a1df202011-05-10 09:26:43 +00002338 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002339 DWORD avail = 0;
2340
Jacek Caban8a1df202011-05-10 09:26:43 +00002341 if(req->netconn)
2342 NETCON_query_data_available(req->netconn, &avail);
2343 return netconn_stream->content_length == ~0u
2344 ? avail
2345 : min(avail, netconn_stream->content_length-netconn_stream->content_read);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002346}
2347
2348static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req)
2349{
2350 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Caban8a1df202011-05-10 09:26:43 +00002351 return netconn_stream->content_read == netconn_stream->content_length || !req->netconn;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002352}
2353
2354static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2355 DWORD *read, read_mode_t read_mode)
2356{
2357 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002358 int len = 0;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002359
2360 size = min(size, netconn_stream->content_length-netconn_stream->content_read);
2361
2362 if(read_mode == READMODE_NOBLOCK)
2363 size = min(size, netconn_get_avail_data(stream, req));
2364
Jacek Caban8a1df202011-05-10 09:26:43 +00002365 if(size && req->netconn) {
2366 if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS)
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002367 len = 0;
Jacek Cabancfdc5392011-06-10 14:47:27 +02002368 if(!len)
2369 netconn_stream->content_length = netconn_stream->content_read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002370 }
2371
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002372 netconn_stream->content_read += *read = len;
2373 TRACE("read %u bytes\n", len);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002374 return ERROR_SUCCESS;
2375}
2376
Jacek Caban8a1df202011-05-10 09:26:43 +00002377static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req)
2378{
2379 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2380 BYTE buf[1024];
2381 DWORD avail;
2382 int len;
2383
2384 if(netconn_end_of_data(stream, req))
2385 return TRUE;
2386
2387 do {
2388 avail = netconn_get_avail_data(stream, req);
2389 if(!avail)
2390 return FALSE;
2391
2392 if(NETCON_recv(req->netconn, buf, min(avail, sizeof(buf)), 0, &len) != ERROR_SUCCESS)
2393 return FALSE;
2394
2395 netconn_stream->content_read += len;
2396 }while(netconn_stream->content_read < netconn_stream->content_length);
2397
2398 return TRUE;
2399}
2400
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002401static void netconn_destroy(data_stream_t *stream)
2402{
2403}
2404
2405static const data_stream_vtbl_t netconn_stream_vtbl = {
2406 netconn_get_avail_data,
2407 netconn_end_of_data,
2408 netconn_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002409 netconn_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002410 netconn_destroy
2411};
2412
2413/* read some more data into the read buffer (the read section must be held) */
2414static DWORD read_more_chunked_data(chunked_stream_t *stream, http_request_t *req, int maxlen)
2415{
2416 DWORD res;
2417 int len;
2418
2419 if (stream->buf_pos)
2420 {
2421 /* move existing data to the start of the buffer */
2422 if(stream->buf_size)
2423 memmove(stream->buf, stream->buf + stream->buf_pos, stream->buf_size);
2424 stream->buf_pos = 0;
2425 }
2426
2427 if (maxlen == -1) maxlen = sizeof(stream->buf);
2428
Jacek Caban8a1df202011-05-10 09:26:43 +00002429 res = NETCON_recv( req->netconn, stream->buf + stream->buf_size,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002430 maxlen - stream->buf_size, 0, &len );
2431 if(res == ERROR_SUCCESS)
2432 stream->buf_size += len;
2433
2434 return res;
2435}
2436
2437/* remove some amount of data from the read buffer (the read section must be held) */
2438static void remove_chunked_data(chunked_stream_t *stream, int count)
2439{
2440 if (!(stream->buf_size -= count)) stream->buf_pos = 0;
2441 else stream->buf_pos += count;
2442}
2443
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002444/* discard data contents until we reach end of line (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002445static DWORD discard_chunked_eol(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002446{
Jacek Caban1d96e202009-11-30 19:59:56 +01002447 DWORD res;
2448
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002449 do
2450 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002451 BYTE *eol = memchr(stream->buf + stream->buf_pos, '\n', stream->buf_size);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002452 if (eol)
2453 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002454 remove_chunked_data(stream, (eol + 1) - (stream->buf + stream->buf_pos));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002455 break;
2456 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002457 stream->buf_pos = stream->buf_size = 0; /* discard everything */
2458 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2459 } while (stream->buf_size);
Jacek Caban1d96e202009-11-30 19:59:56 +01002460 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002461}
2462
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002463/* read the size of the next chunk (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002464static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002465{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002466 /* TODOO */
Jacek Caban1d96e202009-11-30 19:59:56 +01002467 DWORD chunk_size = 0, res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002468
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002469 if(stream->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
2470 return res;
2471
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002472 for (;;)
2473 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002474 while (stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002475 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002476 char ch = stream->buf[stream->buf_pos];
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002477 if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
2478 else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
2479 else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
2480 else if (ch == ';' || ch == '\r' || ch == '\n')
2481 {
2482 TRACE( "reading %u byte chunk\n", chunk_size );
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002483 stream->chunk_size = chunk_size;
2484 req->contentLength += chunk_size;
2485 return discard_chunked_eol(stream, req);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002486 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002487 remove_chunked_data(stream, 1);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002488 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002489 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2490 if (!stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002491 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002492 stream->chunk_size = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002493 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002494 }
2495 }
2496}
2497
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002498static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002499{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002500 /* Allow reading only from read buffer */
2501 return 0;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002502}
2503
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002504static BOOL chunked_end_of_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002505{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002506 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2507 return !chunked_stream->chunk_size;
2508}
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002509
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002510static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2511 DWORD *read, read_mode_t read_mode)
2512{
2513 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2514 DWORD read_bytes = 0, ret_read = 0, res = ERROR_SUCCESS;
2515
2516 if(chunked_stream->chunk_size == ~0u) {
2517 res = start_next_chunk(chunked_stream, req);
2518 if(res != ERROR_SUCCESS)
2519 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002520 }
2521
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002522 while(size && chunked_stream->chunk_size) {
2523 if(chunked_stream->buf_size) {
2524 read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002525
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002526 /* this could block */
2527 if(read_mode == READMODE_NOBLOCK && read_bytes == chunked_stream->chunk_size)
2528 break;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002529
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002530 memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
2531 remove_chunked_data(chunked_stream, read_bytes);
2532 }else {
2533 read_bytes = min(size, chunked_stream->chunk_size);
Jacek Cabana76db212009-06-07 21:19:06 +02002534
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002535 if(read_mode == READMODE_NOBLOCK) {
2536 DWORD avail;
Jacek Cabana76db212009-06-07 21:19:06 +02002537
Jacek Caban8a1df202011-05-10 09:26:43 +00002538 if(!NETCON_query_data_available(req->netconn, &avail) || !avail)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002539 break;
2540 if(read_bytes > avail)
2541 read_bytes = avail;
2542
2543 /* this could block */
2544 if(read_bytes == chunked_stream->chunk_size)
2545 break;
2546 }
2547
Jacek Caban8a1df202011-05-10 09:26:43 +00002548 res = NETCON_recv(req->netconn, (char *)buf+ret_read, read_bytes, 0, (int*)&read_bytes);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002549 if(res != ERROR_SUCCESS)
Jacek Cabana76db212009-06-07 21:19:06 +02002550 break;
2551 }
2552
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002553 chunked_stream->chunk_size -= read_bytes;
2554 size -= read_bytes;
2555 ret_read += read_bytes;
2556 if(!chunked_stream->chunk_size) {
2557 assert(read_mode != READMODE_NOBLOCK);
2558 res = start_next_chunk(chunked_stream, req);
2559 if(res != ERROR_SUCCESS)
2560 break;
Jacek Cabana76db212009-06-07 21:19:06 +02002561 }
Jacek Cabana76db212009-06-07 21:19:06 +02002562
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002563 if(read_mode == READMODE_ASYNC)
2564 read_mode = READMODE_NOBLOCK;
Jacek Cabana76db212009-06-07 21:19:06 +02002565 }
2566
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002567 TRACE("read %u bytes\n", ret_read);
2568 *read = ret_read;
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002569 return res;
2570}
2571
Jacek Caban8a1df202011-05-10 09:26:43 +00002572static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req)
2573{
2574 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2575
2576 /* FIXME: we can do better */
2577 return !chunked_stream->chunk_size;
2578}
2579
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002580static void chunked_destroy(data_stream_t *stream)
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002581{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002582 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2583 heap_free(chunked_stream);
Jacek Cabana76db212009-06-07 21:19:06 +02002584}
2585
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002586static const data_stream_vtbl_t chunked_stream_vtbl = {
2587 chunked_get_avail_data,
2588 chunked_end_of_data,
2589 chunked_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002590 chunked_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002591 chunked_destroy
2592};
2593
2594/* set the request content length based on the headers */
Jacek Cabana890e3a2011-05-13 13:48:15 +02002595static DWORD set_content_length(http_request_t *request, DWORD status_code)
Jacek Cabana76db212009-06-07 21:19:06 +02002596{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002597 static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
2598 WCHAR encoding[20];
2599 DWORD size;
2600
Jacek Cabana890e3a2011-05-13 13:48:15 +02002601 if(status_code == HTTP_STATUS_NO_CONTENT) {
2602 request->contentLength = request->netconn_stream.content_length = 0;
2603 return ERROR_SUCCESS;
2604 }
2605
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002606 size = sizeof(request->contentLength);
2607 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
2608 &request->contentLength, &size, NULL) != ERROR_SUCCESS)
2609 request->contentLength = ~0u;
2610 request->netconn_stream.content_length = request->contentLength;
2611 request->netconn_stream.content_read = request->read_size;
2612
2613 size = sizeof(encoding);
2614 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS &&
2615 !strcmpiW(encoding, szChunked))
2616 {
2617 chunked_stream_t *chunked_stream;
2618
2619 chunked_stream = heap_alloc(sizeof(*chunked_stream));
2620 if(!chunked_stream)
2621 return ERROR_OUTOFMEMORY;
2622
2623 chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
2624 chunked_stream->buf_size = chunked_stream->buf_pos = 0;
2625 chunked_stream->chunk_size = ~0u;
2626
2627 if(request->read_size) {
2628 memcpy(chunked_stream->buf, request->read_buf+request->read_pos, request->read_size);
2629 chunked_stream->buf_size = request->read_size;
2630 request->read_size = request->read_pos = 0;
2631 }
2632
2633 request->data_stream = &chunked_stream->data_stream;
2634 request->contentLength = ~0u;
2635 request->read_chunked = TRUE;
2636 }
2637
2638 if(request->decoding) {
2639 int encoding_idx;
2640
2641 static const WCHAR gzipW[] = {'g','z','i','p',0};
2642
2643 encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE);
2644 if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW))
2645 return init_gzip_stream(request);
2646 }
2647
2648 return ERROR_SUCCESS;
Jacek Cabana76db212009-06-07 21:19:06 +02002649}
2650
Jacek Cabanc0293df2011-06-10 14:47:04 +02002651static void send_request_complete(http_request_t *req, DWORD_PTR result, DWORD error)
Jacek Caban12931062009-01-13 00:28:25 +01002652{
2653 INTERNET_ASYNC_RESULT iar;
Jacek Cabanc0293df2011-06-10 14:47:04 +02002654
2655 iar.dwResult = result;
2656 iar.dwError = error;
2657
2658 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2659 sizeof(INTERNET_ASYNC_RESULT));
2660}
2661
2662static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2663{
2664 DWORD res, read = 0, avail = 0;
Jacek Caban193da882011-05-23 16:10:09 +02002665 read_mode_t mode;
Jacek Caban12931062009-01-13 00:28:25 +01002666
2667 TRACE("%p\n", req);
2668
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002669 EnterCriticalSection( &req->read_section );
Jacek Caban193da882011-05-23 16:10:09 +02002670
2671 mode = first_notif && req->read_size ? READMODE_NOBLOCK : READMODE_ASYNC;
2672 res = refill_read_buffer(req, mode, &read);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002673 if(res == ERROR_SUCCESS && !first_notif)
2674 avail = get_avail_data(req);
Jacek Caban193da882011-05-23 16:10:09 +02002675
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002676 LeaveCriticalSection( &req->read_section );
Jacek Caban12931062009-01-13 00:28:25 +01002677
Jacek Caban193da882011-05-23 16:10:09 +02002678 if(res != ERROR_SUCCESS || (mode != READMODE_NOBLOCK && !read)) {
2679 WARN("res %u read %u, closing connection\n", res, read);
2680 http_release_netconn(req, FALSE);
2681 }
2682
Jacek Cabanc0293df2011-06-10 14:47:04 +02002683 if(res == ERROR_SUCCESS)
Jacek Caban8e37ed52011-06-10 14:47:16 +02002684 send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002685 else
2686 send_request_complete(req, 0, res);
Jacek Caban12931062009-01-13 00:28:25 +01002687}
2688
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002689/* read data from the http connection (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002690static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
Jacek Caban3b4ca692008-03-02 19:35:11 +01002691{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002692 DWORD current_read = 0, ret_read = 0;
2693 read_mode_t read_mode;
2694 DWORD res = ERROR_SUCCESS;
2695
2696 read_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? READMODE_ASYNC : READMODE_SYNC;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002697
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002698 EnterCriticalSection( &req->read_section );
Jacek Cabana76db212009-06-07 21:19:06 +02002699
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002700 if(req->read_size) {
2701 ret_read = min(size, req->read_size);
2702 memcpy(buffer, req->read_buf+req->read_pos, ret_read);
2703 req->read_size -= ret_read;
2704 req->read_pos += ret_read;
2705 if(read_mode == READMODE_ASYNC)
2706 read_mode = READMODE_NOBLOCK;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002707 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002708
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002709 if(ret_read < size) {
2710 res = req->data_stream->vtbl->read(req->data_stream, req, (BYTE*)buffer+ret_read, size-ret_read, &current_read, read_mode);
2711 ret_read += current_read;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002712 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002713
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002714 LeaveCriticalSection( &req->read_section );
2715
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002716 *read = ret_read;
2717 TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength );
Jacek Caban3b4ca692008-03-02 19:35:11 +01002718
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002719 if(req->hCacheFile && res == ERROR_SUCCESS && ret_read) {
2720 BOOL res;
2721 DWORD written;
2722
2723 res = WriteFile(req->hCacheFile, buffer, ret_read, &written, NULL);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002724 if(!res)
2725 WARN("WriteFile failed: %u\n", GetLastError());
2726 }
2727
Jacek Caban086eb612011-05-13 13:48:00 +02002728 if(size && !ret_read)
2729 http_release_netconn(req, res == ERROR_SUCCESS);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002730
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002731 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002732}
2733
Hans Leidekker058761f2008-03-26 22:22:04 +01002734
Jacek Caban44d633a2009-07-07 21:46:09 +02002735static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
Hans Leidekker058761f2008-03-26 22:22:04 +01002736{
Jacek Caban34abacd2009-07-13 01:41:50 +02002737 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002738 DWORD res;
2739
2740 EnterCriticalSection( &req->read_section );
2741 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2742 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2743
2744 res = HTTPREQ_Read(req, buffer, size, read, TRUE);
2745 if(res == ERROR_SUCCESS)
2746 res = hdr->dwError;
2747 LeaveCriticalSection( &req->read_section );
2748
2749 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002750}
2751
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002752static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
Jacek Caband597fd12008-03-03 18:07:20 +01002753{
2754 struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
Jacek Caban34abacd2009-07-13 01:41:50 +02002755 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caband597fd12008-03-03 18:07:20 +01002756 DWORD res;
2757
2758 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2759
2760 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2761 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2762
Jacek Cabanc0293df2011-06-10 14:47:04 +02002763 send_request_complete(req, res == ERROR_SUCCESS, res);
Jacek Caband597fd12008-03-03 18:07:20 +01002764}
2765
Jacek Caban44d633a2009-07-07 21:46:09 +02002766static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
Jacek Caband597fd12008-03-03 18:07:20 +01002767 DWORD flags, DWORD_PTR context)
2768{
Jacek Caban34abacd2009-07-13 01:41:50 +02002769 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002770 DWORD res, size, read, error = ERROR_SUCCESS;
Jacek Caband597fd12008-03-03 18:07:20 +01002771
2772 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2773 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2774
2775 if (buffers->dwStructSize != sizeof(*buffers))
2776 return ERROR_INVALID_PARAMETER;
2777
2778 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2779
Piotr Caban898531d2010-07-01 13:10:46 +02002780 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002781 {
2782 WORKREQUEST workRequest;
Jacek Caband597fd12008-03-03 18:07:20 +01002783
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002784 if (TryEnterCriticalSection( &req->read_section ))
2785 {
2786 if (get_avail_data(req))
2787 {
2788 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2789 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002790 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002791 LeaveCriticalSection( &req->read_section );
2792 goto done;
2793 }
2794 LeaveCriticalSection( &req->read_section );
2795 }
2796
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002797 workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2798 workRequest.hdr = WININET_AddRef(&req->hdr);
2799 workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
Jacek Caband597fd12008-03-03 18:07:20 +01002800
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002801 INTERNET_AsyncCall(&workRequest);
Jacek Caband597fd12008-03-03 18:07:20 +01002802
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002803 return ERROR_IO_PENDING;
Jacek Caband597fd12008-03-03 18:07:20 +01002804 }
2805
Piotr Caban21ced8d2010-07-20 00:33:24 +02002806 read = 0;
2807 size = buffers->dwBufferLength;
2808
2809 EnterCriticalSection( &req->read_section );
2810 if(hdr->dwError == ERROR_SUCCESS)
2811 hdr->dwError = INTERNET_HANDLE_IN_USE;
2812 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2813 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2814
2815 while(1) {
2816 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2817 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002818 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002819 break;
2820
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002821 read += buffers->dwBufferLength;
2822 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002823 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002824
Piotr Caban21ced8d2010-07-20 00:33:24 +02002825 LeaveCriticalSection( &req->read_section );
2826
2827 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2828 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2829 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2830 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2831
2832 EnterCriticalSection( &req->read_section );
2833 }
2834
2835 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2836 hdr->dwError = ERROR_SUCCESS;
2837 else
2838 error = hdr->dwError;
2839
2840 LeaveCriticalSection( &req->read_section );
2841 size = buffers->dwBufferLength;
2842 buffers->dwBufferLength = read;
Jacek Caband597fd12008-03-03 18:07:20 +01002843
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002844done:
Jacek Caband597fd12008-03-03 18:07:20 +01002845 if (res == ERROR_SUCCESS) {
Jacek Caband597fd12008-03-03 18:07:20 +01002846 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2847 &size, sizeof(size));
2848 }
2849
Piotr Caban21ced8d2010-07-20 00:33:24 +02002850 return res==ERROR_SUCCESS ? error : res;
Jacek Caband597fd12008-03-03 18:07:20 +01002851}
2852
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002853static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2854{
2855 struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
Jacek Caban34abacd2009-07-13 01:41:50 +02002856 http_request_t *req = (http_request_t*)workRequest->hdr;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002857 DWORD res;
2858
2859 TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2860
2861 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2862 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2863
Jacek Cabanc0293df2011-06-10 14:47:04 +02002864 send_request_complete(req, res == ERROR_SUCCESS, res);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002865}
2866
Jacek Caban44d633a2009-07-07 21:46:09 +02002867static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002868 DWORD flags, DWORD_PTR context)
2869{
2870
Jacek Caban34abacd2009-07-13 01:41:50 +02002871 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002872 DWORD res, size, read, error = ERROR_SUCCESS;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002873
2874 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2875 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2876
2877 if (buffers->dwStructSize != sizeof(*buffers))
2878 return ERROR_INVALID_PARAMETER;
2879
2880 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2881
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002882 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002883 {
2884 WORKREQUEST workRequest;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002885
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002886 if (TryEnterCriticalSection( &req->read_section ))
2887 {
2888 if (get_avail_data(req))
2889 {
2890 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2891 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002892 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002893 LeaveCriticalSection( &req->read_section );
2894 goto done;
2895 }
2896 LeaveCriticalSection( &req->read_section );
2897 }
2898
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002899 workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2900 workRequest.hdr = WININET_AddRef(&req->hdr);
2901 workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002902
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002903 INTERNET_AsyncCall(&workRequest);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002904
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002905 return ERROR_IO_PENDING;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002906 }
2907
Piotr Caban21ced8d2010-07-20 00:33:24 +02002908 read = 0;
2909 size = buffers->dwBufferLength;
2910
2911 EnterCriticalSection( &req->read_section );
2912 if(hdr->dwError == ERROR_SUCCESS)
2913 hdr->dwError = INTERNET_HANDLE_IN_USE;
2914 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2915 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2916
2917 while(1) {
2918 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2919 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002920 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002921 break;
2922
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002923 read += buffers->dwBufferLength;
2924 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002925 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002926
Piotr Caban21ced8d2010-07-20 00:33:24 +02002927 LeaveCriticalSection( &req->read_section );
2928
2929 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2930 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2931 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2932 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2933
2934 EnterCriticalSection( &req->read_section );
2935 }
2936
2937 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2938 hdr->dwError = ERROR_SUCCESS;
2939 else
2940 error = hdr->dwError;
2941
2942 LeaveCriticalSection( &req->read_section );
2943 size = buffers->dwBufferLength;
2944 buffers->dwBufferLength = read;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002945
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002946done:
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002947 if (res == ERROR_SUCCESS) {
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002948 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2949 &size, sizeof(size));
2950 }
2951
Piotr Caban21ced8d2010-07-20 00:33:24 +02002952 return res==ERROR_SUCCESS ? error : res;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002953}
2954
Jacek Caban1ee3ad42009-11-30 00:13:39 +01002955static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002956{
Jacek Cabanb77868c2009-11-30 00:13:21 +01002957 DWORD res;
Juan Langb49b2432011-03-01 10:59:39 -08002958 http_request_t *request = (http_request_t*)hdr;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002959
Juan Langb49b2432011-03-01 10:59:39 -08002960 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Hans Leidekker85eb4382009-04-08 15:22:05 +02002961
Hans Leidekker0fabf542009-04-08 15:21:28 +02002962 *written = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00002963 res = NETCON_send(request->netconn, buffer, size, 0, (LPINT)written);
Jacek Cabanb77868c2009-11-30 00:13:21 +01002964 if (res == ERROR_SUCCESS)
Juan Lang20980062011-03-01 11:18:22 -08002965 request->bytesWritten += *written;
Hans Leidekker0fabf542009-04-08 15:21:28 +02002966
Juan Langb49b2432011-03-01 10:59:39 -08002967 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
Jacek Caban1ee3ad42009-11-30 00:13:39 +01002968 return res;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01002969}
2970
Jacek Caban33141842008-02-29 12:57:57 +01002971static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
2972{
Jacek Caban34abacd2009-07-13 01:41:50 +02002973 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caban33141842008-02-29 12:57:57 +01002974
Jacek Cabane13781a2009-01-22 13:48:23 +01002975 HTTP_ReceiveRequestData(req, FALSE);
Jacek Caban33141842008-02-29 12:57:57 +01002976}
2977
Jacek Caban44d633a2009-07-07 21:46:09 +02002978static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
Jacek Caban33141842008-02-29 12:57:57 +01002979{
Jacek Caban34abacd2009-07-13 01:41:50 +02002980 http_request_t *req = (http_request_t*)hdr;
Jacek Caban33141842008-02-29 12:57:57 +01002981
2982 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
2983
Juan Lang20980062011-03-01 11:18:22 -08002984 if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban33141842008-02-29 12:57:57 +01002985 {
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002986 WORKREQUEST workRequest;
Jacek Caban33141842008-02-29 12:57:57 +01002987
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002988 /* never wait, if we can't enter the section we queue an async request right away */
2989 if (TryEnterCriticalSection( &req->read_section ))
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002990 {
Jacek Caban193da882011-05-23 16:10:09 +02002991 refill_read_buffer(req, READMODE_NOBLOCK, NULL);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002992 if ((*available = get_avail_data( req ))) goto done;
2993 if (end_of_read_data( req )) goto done;
2994 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002995 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002996
2997 workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
2998 workRequest.hdr = WININET_AddRef( &req->hdr );
2999
3000 INTERNET_AsyncCall(&workRequest);
3001
3002 return ERROR_IO_PENDING;
Jacek Caban33141842008-02-29 12:57:57 +01003003 }
3004
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003005 EnterCriticalSection( &req->read_section );
3006
3007 if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
3008 {
Jacek Caban193da882011-05-23 16:10:09 +02003009 refill_read_buffer( req, READMODE_ASYNC, NULL );
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003010 *available = get_avail_data( req );
3011 }
3012
3013done:
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003014 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02003015
3016 TRACE( "returning %u\n", *available );
Jacek Caban33141842008-02-29 12:57:57 +01003017 return ERROR_SUCCESS;
3018}
3019
Jacek Caban44d633a2009-07-07 21:46:09 +02003020static const object_vtbl_t HTTPREQVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01003021 HTTPREQ_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003022 HTTPREQ_CloseConnection,
Jacek Cabane2933c22008-03-12 02:23:20 +01003023 HTTPREQ_QueryOption,
Jacek Caban0e33eee2008-02-26 20:22:02 +01003024 HTTPREQ_SetOption,
Jacek Caban3b4ca692008-03-02 19:35:11 +01003025 HTTPREQ_ReadFile,
Jacek Caband597fd12008-03-03 18:07:20 +01003026 HTTPREQ_ReadFileExA,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01003027 HTTPREQ_ReadFileExW,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003028 HTTPREQ_WriteFile,
Jacek Caban33141842008-02-29 12:57:57 +01003029 HTTPREQ_QueryDataAvailable,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003030 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01003031};
3032
Mike McCormacka1c16d22003-07-22 03:17:52 +00003033/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003034 * HTTP_HttpOpenRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003035 *
3036 * Open a HTTP request handle
3037 *
3038 * RETURNS
3039 * HINTERNET a HTTP request handle on success
3040 * NULL on failure
3041 *
3042 */
Juan Langb49b2432011-03-01 10:59:39 -08003043static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
Jacek Caban85a057e2009-11-30 20:00:44 +01003044 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3045 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3046 DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003047{
Jacek Caban8a1df202011-05-10 09:26:43 +00003048 appinfo_t *hIC = session->appInfo;
Juan Langb49b2432011-03-01 10:59:39 -08003049 http_request_t *request;
Jacek Caban8a1df202011-05-10 09:26:43 +00003050 DWORD len, res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003051
Francois Gouget0edbaf72005-11-10 12:14:56 +00003052 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00003053
Juan Langb49b2432011-03-01 10:59:39 -08003054 request = alloc_object(&session->hdr, &HTTPREQVtbl, sizeof(http_request_t));
3055 if(!request)
Jacek Cabana073c662011-02-02 22:51:13 +01003056 return ERROR_OUTOFMEMORY;
3057
Juan Langb49b2432011-03-01 10:59:39 -08003058 request->hdr.htype = WH_HHTTPREQ;
3059 request->hdr.dwFlags = dwFlags;
3060 request->hdr.dwContext = dwContext;
Juan Lang20980062011-03-01 11:18:22 -08003061 request->contentLength = ~0u;
Jacek Cabana073c662011-02-02 22:51:13 +01003062
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003063 request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl;
3064 request->data_stream = &request->netconn_stream.data_stream;
Hans Leidekker72273a02012-01-13 15:15:04 +01003065 request->connect_timeout = session->connect_timeout;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003066
Juan Langb49b2432011-03-01 10:59:39 -08003067 InitializeCriticalSection( &request->read_section );
Francois Gouget17929b92011-11-16 16:29:44 +01003068 request->read_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.read_section");
Mike McCormack3a1391b2004-07-19 21:49:39 +00003069
Juan Langb49b2432011-03-01 10:59:39 -08003070 WININET_AddRef( &session->hdr );
Juan Lang20980062011-03-01 11:18:22 -08003071 request->session = session;
Juan Langb49b2432011-03-01 10:59:39 -08003072 list_add_head( &session->hdr.children, &request->hdr.entry );
Jacek Cabana9bdc012006-10-29 18:50:25 +01003073
Juan Lang0b8bfd92011-04-07 08:05:36 -07003074 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_CN_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003075 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
Juan Lang0b8bfd92011-04-07 08:05:36 -07003076 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_DATE_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003077 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003078
Jacek Cabanf9791342008-02-13 13:34:05 +01003079 if (lpszObjectName && *lpszObjectName) {
Aric Stewartff9b9d42002-06-21 23:59:49 +00003080 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003081
3082 len = 0;
3083 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003084 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003085 len = strlenW(lpszObjectName)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003086 request->path = heap_alloc(len*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003087 rc = UrlEscapeW(lpszObjectName, request->path, &len,
Huw D M Davies0aebee92001-01-21 21:09:00 +00003088 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003089 if (rc != S_OK)
Aric Stewartff9b9d42002-06-21 23:59:49 +00003090 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003091 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
Juan Lang20980062011-03-01 11:18:22 -08003092 strcpyW(request->path,lpszObjectName);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003093 }
Jacek Caband1d1da32009-05-29 23:34:25 +02003094 }else {
3095 static const WCHAR slashW[] = {'/',0};
3096
Juan Lang20980062011-03-01 11:18:22 -08003097 request->path = heap_strdupW(slashW);
Huw D M Davies0aebee92001-01-21 21:09:00 +00003098 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003099
Jacek Cabanf9791342008-02-13 13:34:05 +01003100 if (lpszReferrer && *lpszReferrer)
Juan Langb49b2432011-03-01 10:59:39 -08003101 HTTP_ProcessHeader(request, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003102
Hans Leidekker2024f682007-02-12 15:19:17 +01003103 if (lpszAcceptTypes)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003104 {
3105 int i;
Hans Leidekker2024f682007-02-12 15:19:17 +01003106 for (i = 0; lpszAcceptTypes[i]; i++)
3107 {
3108 if (!*lpszAcceptTypes[i]) continue;
Juan Langb49b2432011-03-01 10:59:39 -08003109 HTTP_ProcessHeader(request, HTTP_ACCEPT, lpszAcceptTypes[i],
Hans Leidekker2024f682007-02-12 15:19:17 +01003110 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
3111 HTTP_ADDHDR_FLAG_REQ |
3112 (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
3113 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003114 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003115
Juan Lang20980062011-03-01 11:18:22 -08003116 request->verb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
3117 request->version = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
Hans Leidekkerd0033db2008-02-17 20:41:42 +01003118
Juan Lang8e050392011-03-01 11:02:14 -08003119 if (session->hostPort != INTERNET_INVALID_PORT_NUMBER &&
3120 session->hostPort != INTERNET_DEFAULT_HTTP_PORT &&
3121 session->hostPort != INTERNET_DEFAULT_HTTPS_PORT)
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003122 {
Jacek Caban59f2e832011-05-02 11:26:10 +02003123 WCHAR *host_name;
3124
3125 static const WCHAR host_formatW[] = {'%','s',':','%','u',0};
3126
3127 host_name = heap_alloc((strlenW(session->hostName) + 7 /* length of ":65535" + 1 */) * sizeof(WCHAR));
3128 if (!host_name) {
3129 res = ERROR_OUTOFMEMORY;
3130 goto lend;
3131 }
3132
3133 sprintfW(host_name, host_formatW, session->hostName, session->hostPort);
3134 HTTP_ProcessHeader(request, hostW, host_name, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
3135 heap_free(host_name);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003136 }
3137 else
Juan Lang8e050392011-03-01 11:02:14 -08003138 HTTP_ProcessHeader(request, hostW, session->hostName,
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003139 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Robert Shearman37f2cc82004-09-13 19:33:17 +00003140
Juan Lang8e050392011-03-01 11:02:14 -08003141 if (session->serverPort == INTERNET_INVALID_PORT_NUMBER)
3142 session->serverPort = (dwFlags & INTERNET_FLAG_SECURE ?
Mike McCormack403e58f2005-10-19 19:07:08 +00003143 INTERNET_DEFAULT_HTTPS_PORT :
3144 INTERNET_DEFAULT_HTTP_PORT);
Hans Leidekkere4c59c22008-03-30 19:17:31 +01003145
Juan Lang8e050392011-03-01 11:02:14 -08003146 if (session->hostPort == INTERNET_INVALID_PORT_NUMBER)
3147 session->hostPort = (dwFlags & INTERNET_FLAG_SECURE ?
Hans Leidekkere4c59c22008-03-30 19:17:31 +01003148 INTERNET_DEFAULT_HTTPS_PORT :
3149 INTERNET_DEFAULT_HTTP_PORT);
Mike McCormack403e58f2005-10-19 19:07:08 +00003150
Jacek Caban8a1df202011-05-10 09:26:43 +00003151 if (hIC->proxy && hIC->proxy[0])
Juan Langb49b2432011-03-01 10:59:39 -08003152 HTTP_DealWithProxy( hIC, session, request );
Ulrich Czekallac2757242000-06-11 20:04:44 +00003153
Juan Langb49b2432011-03-01 10:59:39 -08003154 INTERNET_SendCallback(&session->hdr, dwContext,
3155 INTERNET_STATUS_HANDLE_CREATED, &request->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01003156 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00003157
Mike McCormack3a1391b2004-07-19 21:49:39 +00003158lend:
Juan Langb49b2432011-03-01 10:59:39 -08003159 TRACE("<-- %u (%p)\n", res, request);
Mike McCormack3a1391b2004-07-19 21:49:39 +00003160
Jacek Cabana073c662011-02-02 22:51:13 +01003161 if(res != ERROR_SUCCESS) {
Juan Langb49b2432011-03-01 10:59:39 -08003162 WININET_Release( &request->hdr );
Jacek Cabana073c662011-02-02 22:51:13 +01003163 *ret = NULL;
3164 return res;
3165 }
3166
Juan Langb49b2432011-03-01 10:59:39 -08003167 *ret = request->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01003168 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003169}
3170
Jacek Caban47c71fc2009-11-30 20:00:28 +01003171/***********************************************************************
3172 * HttpOpenRequestW (WININET.@)
3173 *
3174 * Open a HTTP request handle
3175 *
3176 * RETURNS
3177 * HINTERNET a HTTP request handle on success
3178 * NULL on failure
3179 *
3180 */
3181HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
3182 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3183 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3184 DWORD dwFlags, DWORD_PTR dwContext)
3185{
Juan Langb49b2432011-03-01 10:59:39 -08003186 http_session_t *session;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003187 HINTERNET handle = NULL;
Jacek Caban85a057e2009-11-30 20:00:44 +01003188 DWORD res;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003189
3190 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
3191 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
3192 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
3193 dwFlags, dwContext);
3194 if(lpszAcceptTypes!=NULL)
3195 {
3196 int i;
3197 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
3198 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
3199 }
3200
Juan Langb49b2432011-03-01 10:59:39 -08003201 session = (http_session_t*) get_handle_object( hHttpSession );
3202 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban47c71fc2009-11-30 20:00:28 +01003203 {
Jacek Caban85a057e2009-11-30 20:00:44 +01003204 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3205 goto lend;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003206 }
3207
3208 /*
3209 * My tests seem to show that the windows version does not
3210 * become asynchronous until after this point. And anyhow
3211 * if this call was asynchronous then how would you get the
3212 * necessary HINTERNET pointer returned by this function.
3213 *
3214 */
Juan Langb49b2432011-03-01 10:59:39 -08003215 res = HTTP_HttpOpenRequestW(session, lpszVerb, lpszObjectName,
Jacek Caban85a057e2009-11-30 20:00:44 +01003216 lpszVersion, lpszReferrer, lpszAcceptTypes,
3217 dwFlags, dwContext, &handle);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003218lend:
Juan Langb49b2432011-03-01 10:59:39 -08003219 if( session )
3220 WININET_Release( &session->hdr );
Jacek Caban47c71fc2009-11-30 20:00:28 +01003221 TRACE("returning %p\n", handle);
Jacek Caban85a057e2009-11-30 20:00:44 +01003222 if(res != ERROR_SUCCESS)
3223 SetLastError(res);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003224 return handle;
3225}
3226
Mike McCormack7f5e2732006-03-30 18:02:54 +09003227static const LPCWSTR header_lookup[] = {
3228 szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
3229 szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
3230 szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
3231 szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
3232 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
3233 szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
3234 szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
3235 szAllow, /* HTTP_QUERY_ALLOW = 7 */
3236 szPublic, /* HTTP_QUERY_PUBLIC = 8 */
3237 szDate, /* HTTP_QUERY_DATE = 9 */
3238 szExpires, /* HTTP_QUERY_EXPIRES = 10 */
3239 szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
3240 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
3241 szURI, /* HTTP_QUERY_URI = 13 */
3242 szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
3243 NULL, /* HTTP_QUERY_COST = 15 */
3244 NULL, /* HTTP_QUERY_LINK = 16 */
3245 szPragma, /* HTTP_QUERY_PRAGMA = 17 */
3246 NULL, /* HTTP_QUERY_VERSION = 18 */
3247 szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
3248 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
3249 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
3250 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
3251 szConnection, /* HTTP_QUERY_CONNECTION = 23 */
3252 szAccept, /* HTTP_QUERY_ACCEPT = 24 */
3253 szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
3254 szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
3255 szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
3256 szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
3257 szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
3258 NULL, /* HTTP_QUERY_FORWARDED = 30 */
3259 NULL, /* HTTP_QUERY_FROM = 31 */
3260 szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
3261 szLocation, /* HTTP_QUERY_LOCATION = 33 */
3262 NULL, /* HTTP_QUERY_ORIG_URI = 34 */
3263 szReferer, /* HTTP_QUERY_REFERER = 35 */
3264 szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
3265 szServer, /* HTTP_QUERY_SERVER = 37 */
3266 NULL, /* HTTP_TITLE = 38 */
3267 szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
3268 szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
3269 szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
3270 szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
3271 szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
3272 szCookie, /* HTTP_QUERY_COOKIE = 44 */
3273 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
3274 NULL, /* HTTP_QUERY_REFRESH = 46 */
3275 NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
3276 szAge, /* HTTP_QUERY_AGE = 48 */
3277 szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
3278 szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
3279 szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
3280 szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
3281 szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
3282 szETag, /* HTTP_QUERY_ETAG = 54 */
Jacek Caban83170892009-05-29 23:34:14 +02003283 hostW, /* HTTP_QUERY_HOST = 55 */
Mike McCormack7f5e2732006-03-30 18:02:54 +09003284 szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
3285 szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
3286 szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
3287 szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
3288 szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
3289 szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
3290 szRange, /* HTTP_QUERY_RANGE = 62 */
3291 szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
3292 szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
3293 szVary, /* HTTP_QUERY_VARY = 65 */
3294 szVia, /* HTTP_QUERY_VIA = 66 */
3295 szWarning, /* HTTP_QUERY_WARNING = 67 */
3296 szExpect, /* HTTP_QUERY_EXPECT = 68 */
3297 szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
3298 szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
Aric Stewart1e946d32005-12-13 17:07:41 +01003299};
3300
Mike McCormack7f5e2732006-03-30 18:02:54 +09003301#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
3302
Alexandre Julliard48243e32004-07-15 18:57:32 +00003303/***********************************************************************
Mike McCormackb288f712004-06-14 17:57:26 +00003304 * HTTP_HttpQueryInfoW (internal)
3305 */
Juan Langb49b2432011-03-01 10:59:39 -08003306static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003307 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Mike McCormackb288f712004-06-14 17:57:26 +00003308{
3309 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01003310 BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
Mike McCormackae300882006-03-30 18:01:48 +09003311 INT requested_index = lpdwIndex ? *lpdwIndex : 0;
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003312 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
Mike McCormackae300882006-03-30 18:01:48 +09003313 INT index = -1;
Mike McCormackb288f712004-06-14 17:57:26 +00003314
3315 /* Find requested header structure */
Mike McCormackae300882006-03-30 18:01:48 +09003316 switch (level)
Mike McCormackb288f712004-06-14 17:57:26 +00003317 {
Mike McCormackae300882006-03-30 18:01:48 +09003318 case HTTP_QUERY_CUSTOM:
Jacek Caban9823c232009-12-14 02:27:29 +01003319 if (!lpBuffer) return ERROR_INVALID_PARAMETER;
Juan Langb49b2432011-03-01 10:59:39 -08003320 index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only);
Mike McCormackae300882006-03-30 18:01:48 +09003321 break;
Mike McCormackae300882006-03-30 18:01:48 +09003322 case HTTP_QUERY_RAW_HEADERS_CRLF:
Robert Shearmandee87512004-07-19 20:09:20 +00003323 {
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003324 LPWSTR headers;
Lei Zhangbc9e2142008-08-27 16:54:17 -07003325 DWORD len = 0;
Jacek Caban9823c232009-12-14 02:27:29 +01003326 DWORD res = ERROR_INVALID_PARAMETER;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003327
3328 if (request_only)
Juan Lang20980062011-03-01 11:18:22 -08003329 headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003330 else
Juan Lang20980062011-03-01 11:18:22 -08003331 headers = request->rawHeaders;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003332
Lei Zhangbc9e2142008-08-27 16:54:17 -07003333 if (headers)
3334 len = strlenW(headers) * sizeof(WCHAR);
3335
Dan Kegel1e7f8912008-07-30 06:49:04 -07003336 if (len + sizeof(WCHAR) > *lpdwBufferLength)
Robert Shearmandee87512004-07-19 20:09:20 +00003337 {
Dan Kegel1e7f8912008-07-30 06:49:04 -07003338 len += sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003339 res = ERROR_INSUFFICIENT_BUFFER;
Hans Leidekker694a0922008-05-18 21:09:50 +02003340 }
3341 else if (lpBuffer)
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003342 {
Lei Zhangbc9e2142008-08-27 16:54:17 -07003343 if (headers)
3344 memcpy(lpBuffer, headers, len + sizeof(WCHAR));
3345 else
3346 {
Lei Zhangf7e56d12008-08-27 17:03:13 -07003347 len = strlenW(szCrLf) * sizeof(WCHAR);
3348 memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
Lei Zhangbc9e2142008-08-27 16:54:17 -07003349 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003350 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
Jacek Caban9823c232009-12-14 02:27:29 +01003351 res = ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003352 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003353 *lpdwBufferLength = len;
Robert Shearman4385d302004-07-21 21:17:03 +00003354
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003355 if (request_only) heap_free(headers);
Jacek Caban9823c232009-12-14 02:27:29 +01003356 return res;
Robert Shearmandee87512004-07-19 20:09:20 +00003357 }
Mike McCormackae300882006-03-30 18:01:48 +09003358 case HTTP_QUERY_RAW_HEADERS:
Robert Shearmandee87512004-07-19 20:09:20 +00003359 {
Juan Lang20980062011-03-01 11:18:22 -08003360 LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf);
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003361 DWORD i, size = 0;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003362 LPWSTR pszString = lpBuffer;
Robert Shearmandee87512004-07-19 20:09:20 +00003363
3364 for (i = 0; ppszRawHeaderLines[i]; i++)
3365 size += strlenW(ppszRawHeaderLines[i]) + 1;
3366
3367 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
3368 {
3369 HTTP_FreeTokens(ppszRawHeaderLines);
3370 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003371 return ERROR_INSUFFICIENT_BUFFER;
Robert Shearmandee87512004-07-19 20:09:20 +00003372 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003373 if (pszString)
Robert Shearmandee87512004-07-19 20:09:20 +00003374 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003375 for (i = 0; ppszRawHeaderLines[i]; i++)
3376 {
3377 DWORD len = strlenW(ppszRawHeaderLines[i]);
3378 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
3379 pszString += len+1;
3380 }
3381 *pszString = '\0';
3382 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
Robert Shearmandee87512004-07-19 20:09:20 +00003383 }
Robert Shearman4385d302004-07-21 21:17:03 +00003384 *lpdwBufferLength = size * sizeof(WCHAR);
Robert Shearmandee87512004-07-19 20:09:20 +00003385 HTTP_FreeTokens(ppszRawHeaderLines);
3386
Jacek Caban9823c232009-12-14 02:27:29 +01003387 return ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003388 }
Mike McCormackae300882006-03-30 18:01:48 +09003389 case HTTP_QUERY_STATUS_TEXT:
Juan Lang20980062011-03-01 11:18:22 -08003390 if (request->statusText)
Aric Stewart1e946d32005-12-13 17:07:41 +01003391 {
Juan Lang20980062011-03-01 11:18:22 -08003392 DWORD len = strlenW(request->statusText);
Aric Stewart1e946d32005-12-13 17:07:41 +01003393 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3394 {
3395 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003396 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003397 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003398 if (lpBuffer)
3399 {
Juan Lang20980062011-03-01 11:18:22 -08003400 memcpy(lpBuffer, request->statusText, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003401 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3402 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003403 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003404 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003405 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003406 break;
Mike McCormackae300882006-03-30 18:01:48 +09003407 case HTTP_QUERY_VERSION:
Juan Lang20980062011-03-01 11:18:22 -08003408 if (request->version)
Aric Stewart1e946d32005-12-13 17:07:41 +01003409 {
Juan Lang20980062011-03-01 11:18:22 -08003410 DWORD len = strlenW(request->version);
Aric Stewart1e946d32005-12-13 17:07:41 +01003411 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3412 {
3413 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003414 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003415 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003416 if (lpBuffer)
3417 {
Juan Lang20980062011-03-01 11:18:22 -08003418 memcpy(lpBuffer, request->version, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003419 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3420 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003421 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003422 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003423 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003424 break;
Jacek Caban11ca05f2009-05-29 23:35:13 +02003425 case HTTP_QUERY_CONTENT_ENCODING:
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003426 index = HTTP_GetCustomHeaderIndex(request, header_lookup[request->read_gzip ? HTTP_QUERY_CONTENT_TYPE : level],
Jacek Caban11ca05f2009-05-29 23:35:13 +02003427 requested_index,request_only);
3428 break;
Mike McCormackae300882006-03-30 18:01:48 +09003429 default:
Mike McCormack7f5e2732006-03-30 18:02:54 +09003430 assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
3431
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003432 if (level < LAST_TABLE_HEADER && header_lookup[level])
Juan Langb49b2432011-03-01 10:59:39 -08003433 index = HTTP_GetCustomHeaderIndex(request, header_lookup[level],
Mike McCormack7f5e2732006-03-30 18:02:54 +09003434 requested_index,request_only);
Mike McCormackb288f712004-06-14 17:57:26 +00003435 }
3436
Mike McCormackae300882006-03-30 18:01:48 +09003437 if (index >= 0)
Juan Lang20980062011-03-01 11:18:22 -08003438 lphttpHdr = &request->custHeaders[index];
Mike McCormackae300882006-03-30 18:01:48 +09003439
Austin English0e4adae2008-01-04 13:37:14 -06003440 /* Ensure header satisfies requested attributes */
Mike McCormackae300882006-03-30 18:01:48 +09003441 if (!lphttpHdr ||
3442 ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
3443 (~lphttpHdr->wFlags & HDR_ISREQUEST)))
Alexandre Julliard48243e32004-07-15 18:57:32 +00003444 {
Jacek Caban9823c232009-12-14 02:27:29 +01003445 return ERROR_HTTP_HEADER_NOT_FOUND;
Alexandre Julliard48243e32004-07-15 18:57:32 +00003446 }
Mike McCormackb288f712004-06-14 17:57:26 +00003447
Hans Leidekkerd1076ae2008-12-01 15:35:05 +01003448 if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
Mike McCormackae300882006-03-30 18:01:48 +09003449
Austin English0e4adae2008-01-04 13:37:14 -06003450 /* coalesce value to requested type */
Hans Leidekker128b8a52008-10-06 15:48:28 +02003451 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003452 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003453 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
3454 TRACE(" returning number: %d\n", *(int *)lpBuffer);
Jacek Caban9823c232009-12-14 02:27:29 +01003455 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003456 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003457 {
3458 time_t tmpTime;
3459 struct tm tmpTM;
3460 SYSTEMTIME *STHook;
3461
3462 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
3463
3464 tmpTM = *gmtime(&tmpTime);
Hans Leidekker128b8a52008-10-06 15:48:28 +02003465 STHook = (SYSTEMTIME *)lpBuffer;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003466 STHook->wDay = tmpTM.tm_mday;
3467 STHook->wHour = tmpTM.tm_hour;
3468 STHook->wMilliseconds = 0;
3469 STHook->wMinute = tmpTM.tm_min;
3470 STHook->wDayOfWeek = tmpTM.tm_wday;
3471 STHook->wMonth = tmpTM.tm_mon + 1;
3472 STHook->wSecond = tmpTM.tm_sec;
3473 STHook->wYear = tmpTM.tm_year;
Jacek Caban9823c232009-12-14 02:27:29 +01003474
Hans Leidekker128b8a52008-10-06 15:48:28 +02003475 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
3476 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
3477 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
Mike McCormackb288f712004-06-14 17:57:26 +00003478 }
Aric Stewart7bca41a2005-12-08 12:44:45 +01003479 else if (lphttpHdr->lpszValue)
Mike McCormackb288f712004-06-14 17:57:26 +00003480 {
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003481 DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003482
3483 if (len > *lpdwBufferLength)
3484 {
3485 *lpdwBufferLength = len;
Jacek Caban9823c232009-12-14 02:27:29 +01003486 return ERROR_INSUFFICIENT_BUFFER;
Mike McCormackb288f712004-06-14 17:57:26 +00003487 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003488 if (lpBuffer)
3489 {
3490 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
Jacek Caban9823c232009-12-14 02:27:29 +01003491 TRACE("! returning string: %s\n", debugstr_w(lpBuffer));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003492 }
Mike McCormackb288f712004-06-14 17:57:26 +00003493 *lpdwBufferLength = len - sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003494 }
Jacek Caban9823c232009-12-14 02:27:29 +01003495 return ERROR_SUCCESS;
Mike McCormackb288f712004-06-14 17:57:26 +00003496}
3497
3498/***********************************************************************
Mike McCormack1baf39f2004-03-30 20:37:49 +00003499 * HttpQueryInfoW (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003500 *
3501 * Queries for information about an HTTP request
3502 *
3503 * RETURNS
3504 * TRUE on success
3505 * FALSE on failure
3506 *
3507 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003508BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003509 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003510{
Juan Langb49b2432011-03-01 10:59:39 -08003511 http_request_t *request;
Jacek Caban9823c232009-12-14 02:27:29 +01003512 DWORD res;
Vincent Béron9a624912002-05-31 23:06:46 +00003513
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003514 if (TRACE_ON(wininet)) {
3515#define FE(x) { x, #x }
3516 static const wininet_flag_info query_flags[] = {
3517 FE(HTTP_QUERY_MIME_VERSION),
3518 FE(HTTP_QUERY_CONTENT_TYPE),
3519 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
3520 FE(HTTP_QUERY_CONTENT_ID),
3521 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
3522 FE(HTTP_QUERY_CONTENT_LENGTH),
3523 FE(HTTP_QUERY_CONTENT_LANGUAGE),
3524 FE(HTTP_QUERY_ALLOW),
3525 FE(HTTP_QUERY_PUBLIC),
3526 FE(HTTP_QUERY_DATE),
3527 FE(HTTP_QUERY_EXPIRES),
3528 FE(HTTP_QUERY_LAST_MODIFIED),
3529 FE(HTTP_QUERY_MESSAGE_ID),
3530 FE(HTTP_QUERY_URI),
3531 FE(HTTP_QUERY_DERIVED_FROM),
3532 FE(HTTP_QUERY_COST),
3533 FE(HTTP_QUERY_LINK),
3534 FE(HTTP_QUERY_PRAGMA),
3535 FE(HTTP_QUERY_VERSION),
3536 FE(HTTP_QUERY_STATUS_CODE),
3537 FE(HTTP_QUERY_STATUS_TEXT),
3538 FE(HTTP_QUERY_RAW_HEADERS),
3539 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
3540 FE(HTTP_QUERY_CONNECTION),
3541 FE(HTTP_QUERY_ACCEPT),
3542 FE(HTTP_QUERY_ACCEPT_CHARSET),
3543 FE(HTTP_QUERY_ACCEPT_ENCODING),
3544 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
3545 FE(HTTP_QUERY_AUTHORIZATION),
3546 FE(HTTP_QUERY_CONTENT_ENCODING),
3547 FE(HTTP_QUERY_FORWARDED),
3548 FE(HTTP_QUERY_FROM),
3549 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
3550 FE(HTTP_QUERY_LOCATION),
3551 FE(HTTP_QUERY_ORIG_URI),
3552 FE(HTTP_QUERY_REFERER),
3553 FE(HTTP_QUERY_RETRY_AFTER),
3554 FE(HTTP_QUERY_SERVER),
3555 FE(HTTP_QUERY_TITLE),
3556 FE(HTTP_QUERY_USER_AGENT),
3557 FE(HTTP_QUERY_WWW_AUTHENTICATE),
3558 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
3559 FE(HTTP_QUERY_ACCEPT_RANGES),
Aric Stewart1e946d32005-12-13 17:07:41 +01003560 FE(HTTP_QUERY_SET_COOKIE),
3561 FE(HTTP_QUERY_COOKIE),
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003562 FE(HTTP_QUERY_REQUEST_METHOD),
3563 FE(HTTP_QUERY_REFRESH),
3564 FE(HTTP_QUERY_CONTENT_DISPOSITION),
3565 FE(HTTP_QUERY_AGE),
3566 FE(HTTP_QUERY_CACHE_CONTROL),
3567 FE(HTTP_QUERY_CONTENT_BASE),
3568 FE(HTTP_QUERY_CONTENT_LOCATION),
3569 FE(HTTP_QUERY_CONTENT_MD5),
3570 FE(HTTP_QUERY_CONTENT_RANGE),
3571 FE(HTTP_QUERY_ETAG),
3572 FE(HTTP_QUERY_HOST),
3573 FE(HTTP_QUERY_IF_MATCH),
3574 FE(HTTP_QUERY_IF_NONE_MATCH),
3575 FE(HTTP_QUERY_IF_RANGE),
3576 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
3577 FE(HTTP_QUERY_MAX_FORWARDS),
3578 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
3579 FE(HTTP_QUERY_RANGE),
3580 FE(HTTP_QUERY_TRANSFER_ENCODING),
3581 FE(HTTP_QUERY_UPGRADE),
3582 FE(HTTP_QUERY_VARY),
3583 FE(HTTP_QUERY_VIA),
3584 FE(HTTP_QUERY_WARNING),
3585 FE(HTTP_QUERY_CUSTOM)
3586 };
3587 static const wininet_flag_info modifier_flags[] = {
3588 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
3589 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
3590 FE(HTTP_QUERY_FLAG_NUMBER),
3591 FE(HTTP_QUERY_FLAG_COALESCE)
3592 };
3593#undef FE
3594 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
3595 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003596 DWORD i;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003597
Juan Lang66b4ad22009-12-04 14:39:37 -08003598 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003599 TRACE(" Attribute:");
3600 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
3601 if (query_flags[i].val == info) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003602 TRACE(" %s", query_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003603 break;
3604 }
3605 }
3606 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003607 TRACE(" Unknown (%08x)", info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003608 }
3609
Diego Pettenò869a66a2005-01-07 17:09:39 +00003610 TRACE(" Modifier:");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003611 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
3612 if (modifier_flags[i].val & info_mod) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003613 TRACE(" %s", modifier_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003614 info_mod &= ~ modifier_flags[i].val;
3615 }
3616 }
3617
3618 if (info_mod) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003619 TRACE(" Unknown (%08x)", info_mod);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003620 }
Diego Pettenò869a66a2005-01-07 17:09:39 +00003621 TRACE("\n");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003622 }
3623
Juan Langb49b2432011-03-01 10:59:39 -08003624 request = (http_request_t*) get_handle_object( hHttpRequest );
3625 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003626 {
Jacek Caban9823c232009-12-14 02:27:29 +01003627 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3628 goto lend;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003629 }
3630
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003631 if (lpBuffer == NULL)
3632 *lpdwBufferLength = 0;
Juan Langb49b2432011-03-01 10:59:39 -08003633 res = HTTP_HttpQueryInfoW( request, dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003634 lpBuffer, lpdwBufferLength, lpdwIndex);
Ulrich Czekallac2757242000-06-11 20:04:44 +00003635
Mike McCormack3a1391b2004-07-19 21:49:39 +00003636lend:
Juan Langb49b2432011-03-01 10:59:39 -08003637 if( request )
3638 WININET_Release( &request->hdr );
Mike McCormack3a1391b2004-07-19 21:49:39 +00003639
Jacek Caban9823c232009-12-14 02:27:29 +01003640 TRACE("%u <--\n", res);
3641 if(res != ERROR_SUCCESS)
3642 SetLastError(res);
3643 return res == ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003644}
3645
Alberto Massarid476a5a2002-11-12 02:13:04 +00003646/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003647 * HttpQueryInfoA (WININET.@)
Alberto Massarid476a5a2002-11-12 02:13:04 +00003648 *
3649 * Queries for information about an HTTP request
3650 *
3651 * RETURNS
3652 * TRUE on success
3653 * FALSE on failure
3654 *
3655 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003656BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Alberto Massarid476a5a2002-11-12 02:13:04 +00003657 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3658{
3659 BOOL result;
Mike McCormack1baf39f2004-03-30 20:37:49 +00003660 DWORD len;
3661 WCHAR* bufferW;
3662
Alberto Massarid476a5a2002-11-12 02:13:04 +00003663 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3664 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3665 {
Mike McCormack1baf39f2004-03-30 20:37:49 +00003666 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3667 lpdwBufferLength, lpdwIndex );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003668 }
Mike McCormack1baf39f2004-03-30 20:37:49 +00003669
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003670 if (lpBuffer)
3671 {
Rob Shearman719cd822008-02-18 19:37:35 +00003672 DWORD alloclen;
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003673 len = (*lpdwBufferLength)*sizeof(WCHAR);
Rob Shearman719cd822008-02-18 19:37:35 +00003674 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3675 {
3676 alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3677 if (alloclen < len)
3678 alloclen = len;
3679 }
3680 else
3681 alloclen = len;
Jacek Caban354a74e2011-04-21 13:39:03 +02003682 bufferW = heap_alloc(alloclen);
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003683 /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3684 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
Rob Shearman719cd822008-02-18 19:37:35 +00003685 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003686 } else
3687 {
3688 bufferW = NULL;
3689 len = 0;
3690 }
3691
Mike McCormack1baf39f2004-03-30 20:37:49 +00003692 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3693 &len, lpdwIndex );
3694 if( result )
Alberto Massarid476a5a2002-11-12 02:13:04 +00003695 {
Robert Shearman4385d302004-07-21 21:17:03 +00003696 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
Mike McCormack1baf39f2004-03-30 20:37:49 +00003697 lpBuffer, *lpdwBufferLength, NULL, NULL );
Robert Shearman4385d302004-07-21 21:17:03 +00003698 *lpdwBufferLength = len - 1;
3699
3700 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
Alberto Massarid476a5a2002-11-12 02:13:04 +00003701 }
Robert Shearman907ac442004-07-20 01:21:08 +00003702 else
3703 /* since the strings being returned from HttpQueryInfoW should be
3704 * only ASCII characters, it is reasonable to assume that all of
3705 * the Unicode characters can be reduced to a single byte */
3706 *lpdwBufferLength = len / sizeof(WCHAR);
Robert Shearman4385d302004-07-21 21:17:03 +00003707
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003708 heap_free( bufferW );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003709 return result;
3710}
Huw D M Daviesf9b6d7b2000-10-28 00:30:23 +00003711
3712/***********************************************************************
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003713 * HTTP_GetRedirectURL (internal)
3714 */
Juan Langb49b2432011-03-01 10:59:39 -08003715static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003716{
3717 static WCHAR szHttp[] = {'h','t','t','p',0};
3718 static WCHAR szHttps[] = {'h','t','t','p','s',0};
Juan Lang20980062011-03-01 11:18:22 -08003719 http_session_t *session = request->session;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003720 URL_COMPONENTSW urlComponents;
3721 DWORD url_length = 0;
3722 LPWSTR orig_url;
3723 LPWSTR combined_url;
3724
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003725 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Juan Langb49b2432011-03-01 10:59:39 -08003726 urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003727 urlComponents.dwSchemeLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003728 urlComponents.lpszHostName = session->hostName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003729 urlComponents.dwHostNameLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003730 urlComponents.nPort = session->hostPort;
3731 urlComponents.lpszUserName = session->userName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003732 urlComponents.dwUserNameLength = 0;
3733 urlComponents.lpszPassword = NULL;
3734 urlComponents.dwPasswordLength = 0;
Juan Lang20980062011-03-01 11:18:22 -08003735 urlComponents.lpszUrlPath = request->path;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003736 urlComponents.dwUrlPathLength = 0;
3737 urlComponents.lpszExtraInfo = NULL;
3738 urlComponents.dwExtraInfoLength = 0;
3739
3740 if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
3741 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3742 return NULL;
3743
Jacek Caban354a74e2011-04-21 13:39:03 +02003744 orig_url = heap_alloc(url_length);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003745
3746 /* convert from bytes to characters */
3747 url_length = url_length / sizeof(WCHAR) - 1;
3748 if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
3749 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003750 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003751 return NULL;
3752 }
3753
3754 url_length = 0;
3755 if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
3756 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3757 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003758 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003759 return NULL;
3760 }
Jacek Caban354a74e2011-04-21 13:39:03 +02003761 combined_url = heap_alloc(url_length * sizeof(WCHAR));
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003762
3763 if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
3764 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003765 heap_free(orig_url);
3766 heap_free(combined_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003767 return NULL;
3768 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003769 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003770 return combined_url;
3771}
3772
3773
3774/***********************************************************************
Alberto Massaribc8bd722002-12-06 23:20:31 +00003775 * HTTP_HandleRedirect (internal)
3776 */
Juan Langb49b2432011-03-01 10:59:39 -08003777static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003778{
Juan Lang20980062011-03-01 11:18:22 -08003779 http_session_t *session = request->session;
Juan Lang8e050392011-03-01 11:02:14 -08003780 appinfo_t *hIC = session->appInfo;
Juan Lang72431562011-03-01 11:00:49 -08003781 BOOL using_proxy = hIC->proxy && hIC->proxy[0];
André Hentschel0fda1352011-08-22 21:30:55 +02003782 WCHAR path[INTERNET_MAX_PATH_LENGTH];
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003783 int index;
Mike McCormack7cc70c02004-02-07 01:03:41 +00003784
Alberto Massaribc8bd722002-12-06 23:20:31 +00003785 if(lpszUrl[0]=='/')
3786 {
3787 /* if it's an absolute path, keep the same session info */
Hans Leidekker612f3c12008-03-31 20:26:16 +02003788 lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003789 }
3790 else
3791 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00003792 URL_COMPONENTSW urlComponents;
André Hentschel0fda1352011-08-22 21:30:55 +02003793 WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
3794 WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
3795 WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
Hans Leidekker781f3f72006-10-13 15:43:54 +02003796 static WCHAR szHttp[] = {'h','t','t','p',0};
3797 static WCHAR szHttps[] = {'h','t','t','p','s',0};
Robert Shearman05900252006-03-09 15:11:59 +00003798
Aric Stewart1fc760d2005-11-28 17:31:02 +01003799 userName[0] = 0;
3800 hostName[0] = 0;
3801 protocol[0] = 0;
3802
Mike McCormacka4e902c2004-03-30 04:36:09 +00003803 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003804 urlComponents.lpszScheme = protocol;
André Hentschel0fda1352011-08-22 21:30:55 +02003805 urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003806 urlComponents.lpszHostName = hostName;
André Hentschel0fda1352011-08-22 21:30:55 +02003807 urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003808 urlComponents.lpszUserName = userName;
André Hentschel0fda1352011-08-22 21:30:55 +02003809 urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003810 urlComponents.lpszPassword = NULL;
3811 urlComponents.dwPasswordLength = 0;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003812 urlComponents.lpszUrlPath = path;
André Hentschel0fda1352011-08-22 21:30:55 +02003813 urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003814 urlComponents.lpszExtraInfo = NULL;
3815 urlComponents.dwExtraInfoLength = 0;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003816 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003817 return INTERNET_GetLastError();
Robert Shearmanefac01b2005-11-29 11:25:31 +01003818
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003819 if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
Juan Langb49b2432011-03-01 10:59:39 -08003820 (request->hdr.dwFlags & INTERNET_FLAG_SECURE))
Robert Shearmanefac01b2005-11-29 11:25:31 +01003821 {
3822 TRACE("redirect from secure page to non-secure page\n");
3823 /* FIXME: warn about from secure redirect to non-secure page */
Juan Langb49b2432011-03-01 10:59:39 -08003824 request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
Robert Shearmanefac01b2005-11-29 11:25:31 +01003825 }
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003826 if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) &&
Juan Langb49b2432011-03-01 10:59:39 -08003827 !(request->hdr.dwFlags & INTERNET_FLAG_SECURE))
Robert Shearmanefac01b2005-11-29 11:25:31 +01003828 {
3829 TRACE("redirect from non-secure page to secure page\n");
3830 /* FIXME: notify about redirect to secure page */
Juan Langb49b2432011-03-01 10:59:39 -08003831 request->hdr.dwFlags |= INTERNET_FLAG_SECURE;
Robert Shearmanefac01b2005-11-29 11:25:31 +01003832 }
3833
Alberto Massaribc8bd722002-12-06 23:20:31 +00003834 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
Aric Stewart1fc760d2005-11-28 17:31:02 +01003835 {
3836 if (lstrlenW(protocol)>4) /*https*/
3837 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3838 else /*http*/
3839 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3840 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003841
Mike McCormacka1c16d22003-07-22 03:17:52 +00003842#if 0
3843 /*
3844 * This upsets redirects to binary files on sourceforge.net
3845 * and gives an html page instead of the target file
3846 * Examination of the HTTP request sent by native wininet.dll
3847 * reveals that it doesn't send a referrer in that case.
3848 * Maybe there's a flag that enables this, or maybe a referrer
3849 * shouldn't be added in case of a redirect.
3850 */
3851
3852 /* consider the current host as the referrer */
Juan Langb49b2432011-03-01 10:59:39 -08003853 if (session->lpszServerName && *session->lpszServerName)
3854 HTTP_ProcessHeader(request, HTTP_REFERER, session->lpszServerName,
Mike McCormacka1c16d22003-07-22 03:17:52 +00003855 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
3856 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
3857#endif
Alberto Massaribc8bd722002-12-06 23:20:31 +00003858
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003859 heap_free(session->hostName);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003860 if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
Hans Leidekker8210e1b2008-03-31 20:25:57 +02003861 urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
Aric Stewart1fc760d2005-11-28 17:31:02 +01003862 {
3863 int len;
André Hentschel1a39e292011-03-27 15:27:46 +02003864 static const WCHAR fmt[] = {'%','s',':','%','u',0};
Aric Stewart1fc760d2005-11-28 17:31:02 +01003865 len = lstrlenW(hostName);
Robert Shearman8a8ce9c2005-11-29 11:35:19 +01003866 len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
Jacek Caban354a74e2011-04-21 13:39:03 +02003867 session->hostName = heap_alloc(len*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08003868 sprintfW(session->hostName, fmt, hostName, urlComponents.nPort);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003869 }
3870 else
Juan Lang8e050392011-03-01 11:02:14 -08003871 session->hostName = heap_strdupW(hostName);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003872
Juan Lang8e050392011-03-01 11:02:14 -08003873 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 +01003874
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003875 heap_free(session->userName);
Juan Lang8e050392011-03-01 11:02:14 -08003876 session->userName = NULL;
Robert Shearmanef209362006-03-10 12:28:52 +00003877 if (userName[0])
Juan Lang8e050392011-03-01 11:02:14 -08003878 session->userName = heap_strdupW(userName);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003879
Jacek Caban8a1df202011-05-10 09:26:43 +00003880 reset_data_stream(request);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003881
Jacek Caban8a1df202011-05-10 09:26:43 +00003882 if(!using_proxy) {
3883 if(strcmpiW(session->serverName, hostName)) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003884 heap_free(session->serverName);
Juan Lang8e050392011-03-01 11:02:14 -08003885 session->serverName = heap_strdupW(hostName);
Hans Leidekkerbdf311f2008-06-29 16:03:39 +02003886 }
Jacek Caban8a1df202011-05-10 09:26:43 +00003887 session->serverPort = urlComponents.nPort;
Hans Leidekker8210e1b2008-03-31 20:25:57 +02003888 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003889 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003890 heap_free(request->path);
Juan Lang20980062011-03-01 11:18:22 -08003891 request->path=NULL;
Jacek Cabanf9791342008-02-13 13:34:05 +01003892 if (*path)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003893 {
3894 DWORD needed = 0;
3895 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003896
3897 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003898 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003899 needed = strlenW(path)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003900 request->path = heap_alloc(needed*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003901 rc = UrlEscapeW(path, request->path, &needed,
Alberto Massaribc8bd722002-12-06 23:20:31 +00003902 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003903 if (rc != S_OK)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003904 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003905 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
Juan Lang20980062011-03-01 11:18:22 -08003906 strcpyW(request->path,path);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003907 }
3908 }
3909
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003910 /* Remove custom content-type/length headers on redirects. */
Juan Langb49b2432011-03-01 10:59:39 -08003911 index = HTTP_GetCustomHeaderIndex(request, szContent_Type, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003912 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003913 HTTP_DeleteCustomHeader(request, index);
3914 index = HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003915 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003916 HTTP_DeleteCustomHeader(request, index);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003917
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003918 return ERROR_SUCCESS;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003919}
3920
3921/***********************************************************************
Mike McCormacka4969062004-07-04 00:24:47 +00003922 * HTTP_build_req (internal)
3923 *
3924 * concatenate all the strings in the request together
3925 */
3926static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
3927{
3928 LPCWSTR *t;
3929 LPWSTR str;
3930
3931 for( t = list; *t ; t++ )
3932 len += strlenW( *t );
3933 len++;
3934
Jacek Caban354a74e2011-04-21 13:39:03 +02003935 str = heap_alloc(len*sizeof(WCHAR));
Mike McCormacka4969062004-07-04 00:24:47 +00003936 *str = 0;
3937
3938 for( t = list; *t ; t++ )
3939 strcatW( str, *t );
3940
3941 return str;
3942}
3943
Juan Langb49b2432011-03-01 10:59:39 -08003944static DWORD HTTP_SecureProxyConnect(http_request_t *request)
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003945{
3946 LPWSTR lpszPath;
3947 LPWSTR requestString;
3948 INT len;
3949 INT cnt;
3950 INT responseLen;
3951 char *ascii_req;
Jacek Cabanb77868c2009-11-30 00:13:21 +01003952 DWORD res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003953 static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
André Hentschel1a39e292011-03-27 15:27:46 +02003954 static const WCHAR szFormat[] = {'%','s',':','%','u',0};
Juan Lang20980062011-03-01 11:18:22 -08003955 http_session_t *session = request->session;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003956
3957 TRACE("\n");
3958
Jacek Caban354a74e2011-04-21 13:39:03 +02003959 lpszPath = heap_alloc((lstrlenW( session->hostName ) + 13)*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08003960 sprintfW( lpszPath, szFormat, session->hostName, session->hostPort );
Juan Langb49b2432011-03-01 10:59:39 -08003961 requestString = HTTP_BuildHeaderRequestString( request, szConnect, lpszPath, g_szHttp1_1 );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003962 heap_free( lpszPath );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003963
3964 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3965 NULL, 0, NULL, NULL );
3966 len--; /* the nul terminator isn't needed */
Jacek Caban354a74e2011-04-21 13:39:03 +02003967 ascii_req = heap_alloc(len);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003968 WideCharToMultiByte( CP_ACP, 0, requestString, -1, ascii_req, len, NULL, NULL );
3969 heap_free( requestString );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003970
3971 TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
3972
Jacek Caban8a1df202011-05-10 09:26:43 +00003973 res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003974 heap_free( ascii_req );
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003975 if (res != ERROR_SUCCESS)
3976 return res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003977
Juan Langb49b2432011-03-01 10:59:39 -08003978 responseLen = HTTP_GetResponseHeaders( request, TRUE );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003979 if (!responseLen)
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003980 return ERROR_HTTP_INVALID_HEADER;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003981
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003982 return ERROR_SUCCESS;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01003983}
3984
Juan Langb49b2432011-03-01 10:59:39 -08003985static void HTTP_InsertCookies(http_request_t *request)
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003986{
Jacek Cabandce91812011-05-19 16:11:30 +02003987 DWORD cookie_size, size, cnt = 0;
3988 HTTPHEADERW *host;
3989 WCHAR *cookies;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003990
Jacek Cabandce91812011-05-19 16:11:30 +02003991 static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' ',0};
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003992
Jacek Cabandce91812011-05-19 16:11:30 +02003993 host = HTTP_GetHeader(request, hostW);
3994 if(!host)
3995 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003996
Jacek Cabandce91812011-05-19 16:11:30 +02003997 if(!get_cookie(host->lpszValue, request->path, NULL, &cookie_size))
3998 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02003999
Jacek Cabandce91812011-05-19 16:11:30 +02004000 size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf);
4001 if(!(cookies = heap_alloc(size)))
4002 return;
4003
4004 cnt += sprintfW(cookies, cookieW);
4005 get_cookie(host->lpszValue, request->path, cookies+cnt, &cookie_size);
4006 strcatW(cookies, szCrLf);
4007
4008 HTTP_HttpAddRequestHeadersW(request, cookies, strlenW(cookies), HTTP_ADDREQ_FLAG_REPLACE);
4009
4010 heap_free(cookies);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004011}
4012
Juan Langaeca2f92011-10-21 22:55:14 -07004013static WORD HTTP_ParseWkday(LPCWSTR day)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004014{
Francois Gouget4bacb3f2011-03-11 18:22:23 +01004015 static const WCHAR days[7][4] = {{ 's','u','n',0 },
4016 { 'm','o','n',0 },
4017 { 't','u','e',0 },
4018 { 'w','e','d',0 },
4019 { 't','h','u',0 },
4020 { 'f','r','i',0 },
4021 { 's','a','t',0 }};
4022 int i;
4023 for (i = 0; i < sizeof(days)/sizeof(*days); i++)
4024 if (!strcmpiW(day, days[i]))
4025 return i;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004026
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004027 /* Invalid */
4028 return 7;
4029}
4030
4031static WORD HTTP_ParseMonth(LPCWSTR month)
4032{
4033 static const WCHAR jan[] = { 'j','a','n',0 };
4034 static const WCHAR feb[] = { 'f','e','b',0 };
4035 static const WCHAR mar[] = { 'm','a','r',0 };
4036 static const WCHAR apr[] = { 'a','p','r',0 };
4037 static const WCHAR may[] = { 'm','a','y',0 };
4038 static const WCHAR jun[] = { 'j','u','n',0 };
4039 static const WCHAR jul[] = { 'j','u','l',0 };
4040 static const WCHAR aug[] = { 'a','u','g',0 };
4041 static const WCHAR sep[] = { 's','e','p',0 };
4042 static const WCHAR oct[] = { 'o','c','t',0 };
4043 static const WCHAR nov[] = { 'n','o','v',0 };
4044 static const WCHAR dec[] = { 'd','e','c',0 };
4045
4046 if (!strcmpiW(month, jan)) return 1;
4047 if (!strcmpiW(month, feb)) return 2;
4048 if (!strcmpiW(month, mar)) return 3;
4049 if (!strcmpiW(month, apr)) return 4;
4050 if (!strcmpiW(month, may)) return 5;
4051 if (!strcmpiW(month, jun)) return 6;
4052 if (!strcmpiW(month, jul)) return 7;
4053 if (!strcmpiW(month, aug)) return 8;
4054 if (!strcmpiW(month, sep)) return 9;
4055 if (!strcmpiW(month, oct)) return 10;
4056 if (!strcmpiW(month, nov)) return 11;
4057 if (!strcmpiW(month, dec)) return 12;
4058 /* Invalid */
4059 return 0;
4060}
4061
Juan Lang28e92292011-03-04 11:43:54 -08004062/* Parses the string pointed to by *str, assumed to be a 24-hour time HH:MM:SS,
4063 * optionally preceded by whitespace.
4064 * Upon success, returns TRUE, sets the wHour, wMinute, and wSecond fields of
4065 * st, and sets *str to the first character after the time format.
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004066 */
Juan Lang28e92292011-03-04 11:43:54 -08004067static BOOL HTTP_ParseTime(SYSTEMTIME *st, LPCWSTR *str)
4068{
4069 LPCWSTR ptr = *str;
4070 WCHAR *nextPtr;
4071 unsigned long num;
4072
4073 while (isspaceW(*ptr))
4074 ptr++;
4075
4076 num = strtoulW(ptr, &nextPtr, 10);
4077 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4078 {
4079 ERR("unexpected time format %s\n", debugstr_w(ptr));
4080 return FALSE;
4081 }
4082 if (num > 23)
4083 {
4084 ERR("unexpected hour in time format %s\n", debugstr_w(ptr));
4085 return FALSE;
4086 }
4087 ptr = nextPtr + 1;
4088 st->wHour = (WORD)num;
4089 num = strtoulW(ptr, &nextPtr, 10);
4090 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4091 {
4092 ERR("unexpected time format %s\n", debugstr_w(ptr));
4093 return FALSE;
4094 }
4095 if (num > 59)
4096 {
4097 ERR("unexpected minute in time format %s\n", debugstr_w(ptr));
4098 return FALSE;
4099 }
4100 ptr = nextPtr + 1;
4101 st->wMinute = (WORD)num;
4102 num = strtoulW(ptr, &nextPtr, 10);
4103 if (!nextPtr || nextPtr <= ptr)
4104 {
4105 ERR("unexpected time format %s\n", debugstr_w(ptr));
4106 return FALSE;
4107 }
4108 if (num > 59)
4109 {
4110 ERR("unexpected second in time format %s\n", debugstr_w(ptr));
4111 return FALSE;
4112 }
4113 ptr = nextPtr + 1;
4114 *str = ptr;
4115 st->wSecond = (WORD)num;
4116 return TRUE;
4117}
4118
4119static BOOL HTTP_ParseDateAsAsctime(LPCWSTR value, FILETIME *ft)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004120{
4121 static const WCHAR gmt[]= { 'G','M','T',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004122 WCHAR day[4], *dayPtr, month[4], *monthPtr, *nextPtr;
4123 LPCWSTR ptr;
4124 SYSTEMTIME st = { 0 };
4125 unsigned long num;
4126
4127 for (ptr = value, dayPtr = day; *ptr && !isspaceW(*ptr) &&
4128 dayPtr - day < sizeof(day) / sizeof(day[0]) - 1; ptr++, dayPtr++)
4129 *dayPtr = *ptr;
4130 *dayPtr = 0;
Juan Langaeca2f92011-10-21 22:55:14 -07004131 st.wDayOfWeek = HTTP_ParseWkday(day);
Juan Lang28e92292011-03-04 11:43:54 -08004132 if (st.wDayOfWeek >= 7)
4133 {
4134 ERR("unexpected weekday %s\n", debugstr_w(day));
4135 return FALSE;
4136 }
4137
4138 while (isspaceW(*ptr))
4139 ptr++;
4140
4141 for (monthPtr = month; !isspace(*ptr) &&
4142 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4143 monthPtr++, ptr++)
4144 *monthPtr = *ptr;
4145 *monthPtr = 0;
4146 st.wMonth = HTTP_ParseMonth(month);
4147 if (!st.wMonth || st.wMonth > 12)
4148 {
4149 ERR("unexpected month %s\n", debugstr_w(month));
4150 return FALSE;
4151 }
4152
4153 while (isspaceW(*ptr))
4154 ptr++;
4155
4156 num = strtoulW(ptr, &nextPtr, 10);
4157 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4158 {
4159 ERR("unexpected day %s\n", debugstr_w(ptr));
4160 return FALSE;
4161 }
4162 ptr = nextPtr;
4163 st.wDay = (WORD)num;
4164
4165 while (isspaceW(*ptr))
4166 ptr++;
4167
4168 if (!HTTP_ParseTime(&st, &ptr))
4169 return FALSE;
4170
4171 while (isspaceW(*ptr))
4172 ptr++;
4173
4174 num = strtoulW(ptr, &nextPtr, 10);
4175 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4176 {
4177 ERR("unexpected year %s\n", debugstr_w(ptr));
4178 return FALSE;
4179 }
4180 ptr = nextPtr;
4181 st.wYear = (WORD)num;
4182
4183 while (isspaceW(*ptr))
4184 ptr++;
4185
4186 /* asctime() doesn't report a timezone, but some web servers do, so accept
4187 * with or without GMT.
4188 */
4189 if (*ptr && strcmpW(ptr, gmt))
4190 {
4191 ERR("unexpected timezone %s\n", debugstr_w(ptr));
4192 return FALSE;
4193 }
4194 return SystemTimeToFileTime(&st, ft);
4195}
4196
4197static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft)
4198{
4199 static const WCHAR gmt[]= { 'G','M','T',0 };
4200 WCHAR *nextPtr, day[4], month[4], *monthPtr;
4201 LPCWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004202 unsigned long num;
Juan Langb9673bc2011-03-07 13:13:11 -08004203 SYSTEMTIME st = { 0 };
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004204
4205 ptr = strchrW(value, ',');
4206 if (!ptr)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004207 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004208 if (ptr - value != 3)
4209 {
Juan Langaeca2f92011-10-21 22:55:14 -07004210 WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004211 return FALSE;
4212 }
4213 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4214 day[3] = 0;
Juan Langaeca2f92011-10-21 22:55:14 -07004215 st.wDayOfWeek = HTTP_ParseWkday(day);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004216 if (st.wDayOfWeek > 6)
4217 {
Juan Langaeca2f92011-10-21 22:55:14 -07004218 WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004219 return FALSE;
4220 }
4221 ptr++;
4222
4223 while (isspaceW(*ptr))
4224 ptr++;
4225
4226 num = strtoulW(ptr, &nextPtr, 10);
4227 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4228 {
Juan Langaeca2f92011-10-21 22:55:14 -07004229 WARN("unexpected day %s\n", debugstr_w(value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004230 return FALSE;
4231 }
4232 ptr = nextPtr;
4233 st.wDay = (WORD)num;
4234
4235 while (isspaceW(*ptr))
4236 ptr++;
4237
4238 for (monthPtr = month; !isspace(*ptr) &&
4239 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4240 monthPtr++, ptr++)
4241 *monthPtr = *ptr;
4242 *monthPtr = 0;
4243 st.wMonth = HTTP_ParseMonth(month);
4244 if (!st.wMonth || st.wMonth > 12)
4245 {
Juan Langaeca2f92011-10-21 22:55:14 -07004246 WARN("unexpected month %s\n", debugstr_w(month));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004247 return FALSE;
4248 }
4249
4250 while (isspaceW(*ptr))
4251 ptr++;
4252
4253 num = strtoulW(ptr, &nextPtr, 10);
4254 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4255 {
4256 ERR("unexpected year %s\n", debugstr_w(value));
4257 return FALSE;
4258 }
4259 ptr = nextPtr;
4260 st.wYear = (WORD)num;
4261
Juan Lang28e92292011-03-04 11:43:54 -08004262 if (!HTTP_ParseTime(&st, &ptr))
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004263 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004264
4265 while (isspaceW(*ptr))
4266 ptr++;
4267
4268 if (strcmpW(ptr, gmt))
4269 {
4270 ERR("unexpected time zone %s\n", debugstr_w(ptr));
4271 return FALSE;
4272 }
4273 return SystemTimeToFileTime(&st, ft);
4274}
4275
Juan Langaeca2f92011-10-21 22:55:14 -07004276static WORD HTTP_ParseWeekday(LPCWSTR day)
4277{
4278 static const WCHAR days[7][10] = {{ 's','u','n','d','a','y',0 },
4279 { 'm','o','n','d','a','y',0 },
4280 { 't','u','e','s','d','a','y',0 },
4281 { 'w','e','d','n','e','s','d','a','y',0 },
4282 { 't','h','u','r','s','d','a','y',0 },
4283 { 'f','r','i','d','a','y',0 },
4284 { 's','a','t','u','r','d','a','y',0 }};
4285 int i;
4286 for (i = 0; i < sizeof(days)/sizeof(*days); i++)
4287 if (!strcmpiW(day, days[i]))
4288 return i;
4289
4290 /* Invalid */
4291 return 7;
4292}
4293
4294static BOOL HTTP_ParseRfc850Date(LPCWSTR value, FILETIME *ft)
4295{
4296 static const WCHAR gmt[]= { 'G','M','T',0 };
4297 WCHAR *nextPtr, day[10], month[4], *monthPtr;
4298 LPCWSTR ptr;
4299 unsigned long num;
4300 SYSTEMTIME st = { 0 };
4301
4302 ptr = strchrW(value, ',');
4303 if (!ptr)
4304 return FALSE;
4305 if (ptr - value == 3)
4306 {
4307 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4308 day[3] = 0;
4309 st.wDayOfWeek = HTTP_ParseWkday(day);
4310 if (st.wDayOfWeek > 6)
4311 {
4312 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4313 return FALSE;
4314 }
4315 }
Juan Langad3e22d2011-10-24 13:21:10 -07004316 else if (ptr - value < sizeof(day) / sizeof(day[0]))
Juan Langaeca2f92011-10-21 22:55:14 -07004317 {
4318 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4319 day[ptr - value + 1] = 0;
4320 st.wDayOfWeek = HTTP_ParseWeekday(day);
4321 if (st.wDayOfWeek > 6)
4322 {
4323 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4324 return FALSE;
4325 }
4326 }
4327 else
4328 {
4329 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4330 return FALSE;
4331 }
4332 ptr++;
4333
4334 while (isspaceW(*ptr))
4335 ptr++;
4336
4337 num = strtoulW(ptr, &nextPtr, 10);
4338 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4339 {
4340 ERR("unexpected day %s\n", debugstr_w(value));
4341 return FALSE;
4342 }
4343 ptr = nextPtr;
4344 st.wDay = (WORD)num;
4345
4346 if (*ptr != '-')
4347 {
4348 ERR("unexpected month format %s\n", debugstr_w(ptr));
4349 return FALSE;
4350 }
4351 ptr++;
4352
4353 for (monthPtr = month; *ptr != '-' &&
4354 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4355 monthPtr++, ptr++)
4356 *monthPtr = *ptr;
4357 *monthPtr = 0;
4358 st.wMonth = HTTP_ParseMonth(month);
4359 if (!st.wMonth || st.wMonth > 12)
4360 {
4361 ERR("unexpected month %s\n", debugstr_w(month));
4362 return FALSE;
4363 }
4364
4365 if (*ptr != '-')
4366 {
4367 ERR("unexpected year format %s\n", debugstr_w(ptr));
4368 return FALSE;
4369 }
4370 ptr++;
4371
4372 num = strtoulW(ptr, &nextPtr, 10);
4373 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4374 {
4375 ERR("unexpected year %s\n", debugstr_w(value));
4376 return FALSE;
4377 }
4378 ptr = nextPtr;
4379 st.wYear = (WORD)num;
4380
4381 if (!HTTP_ParseTime(&st, &ptr))
4382 return FALSE;
4383
4384 while (isspaceW(*ptr))
4385 ptr++;
4386
4387 if (strcmpW(ptr, gmt))
4388 {
4389 ERR("unexpected time zone %s\n", debugstr_w(ptr));
4390 return FALSE;
4391 }
4392 return SystemTimeToFileTime(&st, ft);
4393}
4394
Juan Lang28e92292011-03-04 11:43:54 -08004395static BOOL HTTP_ParseDate(LPCWSTR value, FILETIME *ft)
4396{
Juan Langd797e5f2011-05-13 06:47:49 -07004397 static const WCHAR zero[] = { '0',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004398 BOOL ret;
4399
Juan Langd797e5f2011-05-13 06:47:49 -07004400 if (!strcmpW(value, zero))
4401 {
4402 ft->dwLowDateTime = ft->dwHighDateTime = 0;
4403 ret = TRUE;
4404 }
4405 else if (strchrW(value, ','))
Juan Langaeca2f92011-10-21 22:55:14 -07004406 {
Juan Lang28e92292011-03-04 11:43:54 -08004407 ret = HTTP_ParseRfc1123Date(value, ft);
Juan Langaeca2f92011-10-21 22:55:14 -07004408 if (!ret)
4409 {
4410 ret = HTTP_ParseRfc850Date(value, ft);
4411 if (!ret)
4412 ERR("unexpected date format %s\n", debugstr_w(value));
4413 }
4414 }
Juan Lang28e92292011-03-04 11:43:54 -08004415 else
4416 {
4417 ret = HTTP_ParseDateAsAsctime(value, ft);
4418 if (!ret)
4419 ERR("unexpected date format %s\n", debugstr_w(value));
4420 }
4421 return ret;
4422}
4423
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004424static void HTTP_ProcessExpires(http_request_t *request)
4425{
Juan Langab16c752011-03-03 10:54:07 -08004426 BOOL expirationFound = FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004427 int headerIndex;
4428
Juan Lang488c2d02011-03-03 10:54:47 -08004429 /* Look for a Cache-Control header with a max-age directive, as it takes
4430 * precedence over the Expires header.
4431 */
4432 headerIndex = HTTP_GetCustomHeaderIndex(request, szCache_Control, 0, FALSE);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004433 if (headerIndex != -1)
4434 {
Juan Lang488c2d02011-03-03 10:54:47 -08004435 LPHTTPHEADERW ccHeader = &request->custHeaders[headerIndex];
4436 LPWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004437
Juan Lang488c2d02011-03-03 10:54:47 -08004438 for (ptr = ccHeader->lpszValue; ptr && *ptr; )
Juan Langab16c752011-03-03 10:54:07 -08004439 {
Juan Lang488c2d02011-03-03 10:54:47 -08004440 LPWSTR comma = strchrW(ptr, ','), end, equal;
4441
4442 if (comma)
4443 end = comma;
4444 else
4445 end = ptr + strlenW(ptr);
4446 for (equal = end - 1; equal > ptr && *equal != '='; equal--)
4447 ;
4448 if (*equal == '=')
4449 {
4450 static const WCHAR max_age[] = {
4451 'm','a','x','-','a','g','e',0 };
4452
4453 if (!strncmpiW(ptr, max_age, equal - ptr - 1))
4454 {
4455 LPWSTR nextPtr;
4456 unsigned long age;
4457
4458 age = strtoulW(equal + 1, &nextPtr, 10);
4459 if (nextPtr > equal + 1)
4460 {
4461 LARGE_INTEGER ft;
4462
4463 NtQuerySystemTime( &ft );
4464 /* Age is in seconds, FILETIME resolution is in
4465 * 100 nanosecond intervals.
4466 */
4467 ft.QuadPart += age * (ULONGLONG)1000000;
4468 request->expires.dwLowDateTime = ft.u.LowPart;
4469 request->expires.dwHighDateTime = ft.u.HighPart;
4470 expirationFound = TRUE;
4471 }
4472 }
4473 }
4474 if (comma)
4475 {
4476 ptr = comma + 1;
4477 while (isspaceW(*ptr))
4478 ptr++;
4479 }
4480 else
4481 ptr = NULL;
4482 }
4483 }
4484 if (!expirationFound)
4485 {
4486 headerIndex = HTTP_GetCustomHeaderIndex(request, szExpires, 0, FALSE);
4487 if (headerIndex != -1)
4488 {
4489 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4490 FILETIME ft;
4491
4492 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4493 {
4494 expirationFound = TRUE;
4495 request->expires = ft;
4496 }
Juan Langab16c752011-03-03 10:54:07 -08004497 }
4498 }
4499 if (!expirationFound)
4500 {
Juan Lang2d323432011-03-03 10:54:07 -08004501 LARGE_INTEGER t;
Juan Langab16c752011-03-03 10:54:07 -08004502
4503 /* With no known age, default to 10 minutes until expiration. */
Juan Lang2d323432011-03-03 10:54:07 -08004504 NtQuerySystemTime( &t );
4505 t.QuadPart += 10 * 60 * (ULONGLONG)10000000;
4506 request->expires.dwLowDateTime = t.u.LowPart;
4507 request->expires.dwHighDateTime = t.u.HighPart;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004508 }
4509}
4510
Juan Lang28e92292011-03-04 11:43:54 -08004511static void HTTP_ProcessLastModified(http_request_t *request)
4512{
4513 int headerIndex;
4514
4515 headerIndex = HTTP_GetCustomHeaderIndex(request, szLast_Modified, 0, FALSE);
4516 if (headerIndex != -1)
4517 {
4518 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4519 FILETIME ft;
4520
4521 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4522 request->last_modified = ft;
4523 }
4524}
4525
Jacek Caban8a1df202011-05-10 09:26:43 +00004526static void http_process_keep_alive(http_request_t *req)
4527{
4528 int index;
4529
4530 index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE);
4531 if(index != -1)
4532 req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive);
4533 else
4534 req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1);
4535}
4536
Juan Lang666353d2011-03-02 10:06:37 -08004537static void HTTP_CacheRequest(http_request_t *request)
4538{
4539 WCHAR url[INTERNET_MAX_URL_LENGTH];
4540 WCHAR cacheFileName[MAX_PATH+1];
4541 BOOL b;
4542
4543 b = HTTP_GetRequestURL(request, url);
4544 if(!b) {
4545 WARN("Could not get URL\n");
4546 return;
4547 }
4548
Juan Lang7685dad2011-03-03 08:55:32 -08004549 b = CreateUrlCacheEntryW(url, request->contentLength, NULL, cacheFileName, 0);
Juan Lang666353d2011-03-02 10:06:37 -08004550 if(b) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004551 heap_free(request->cacheFile);
Juan Lang666353d2011-03-02 10:06:37 -08004552 CloseHandle(request->hCacheFile);
4553
4554 request->cacheFile = heap_strdupW(cacheFileName);
4555 request->hCacheFile = CreateFileW(request->cacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
4556 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
4557 if(request->hCacheFile == INVALID_HANDLE_VALUE) {
4558 WARN("Could not create file: %u\n", GetLastError());
4559 request->hCacheFile = NULL;
4560 }
4561 }else {
4562 WARN("Could not create cache entry: %08x\n", GetLastError());
4563 }
4564}
4565
Jacek Caban8a1df202011-05-10 09:26:43 +00004566static DWORD open_http_connection(http_request_t *request, BOOL *reusing)
4567{
4568 const BOOL is_https = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) != 0;
4569 http_session_t *session = request->session;
4570 netconn_t *netconn = NULL;
4571 server_t *server;
4572 DWORD res;
4573
4574 assert(!request->netconn);
4575 reset_data_stream(request);
4576
4577 server = get_server(session->serverName, session->serverPort);
4578 if(!server)
4579 return ERROR_OUTOFMEMORY;
4580
4581 res = HTTP_ResolveName(request, server);
4582 if(res != ERROR_SUCCESS) {
4583 server_release(server);
4584 return res;
4585 }
4586
4587 EnterCriticalSection(&connection_pool_cs);
4588
4589 while(!list_empty(&server->conn_pool)) {
4590 netconn = LIST_ENTRY(list_head(&server->conn_pool), netconn_t, pool_entry);
4591 list_remove(&netconn->pool_entry);
4592
4593 if(NETCON_is_alive(netconn))
4594 break;
4595
4596 TRACE("connection %p closed during idle\n", netconn);
4597 free_netconn(netconn);
4598 netconn = NULL;
4599 }
4600
4601 LeaveCriticalSection(&connection_pool_cs);
4602
4603 if(netconn) {
4604 TRACE("<-- reusing %p netconn\n", netconn);
4605 request->netconn = netconn;
4606 *reusing = TRUE;
4607 return ERROR_SUCCESS;
4608 }
4609
4610 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4611 INTERNET_STATUS_CONNECTING_TO_SERVER,
4612 server->addr_str,
4613 strlen(server->addr_str)+1);
4614
Hans Leidekker72273a02012-01-13 15:15:04 +01004615 res = create_netconn(is_https, server, request->security_flags, request->connect_timeout, &netconn);
Jacek Caban8a1df202011-05-10 09:26:43 +00004616 server_release(server);
4617 if(res != ERROR_SUCCESS) {
4618 ERR("create_netconn failed: %u\n", res);
4619 return res;
4620 }
4621
4622 request->netconn = netconn;
4623
4624 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4625 INTERNET_STATUS_CONNECTED_TO_SERVER,
4626 server->addr_str, strlen(server->addr_str)+1);
4627
4628 if(is_https) {
4629 /* Note: we differ from Microsoft's WinINet here. they seem to have
4630 * a bug that causes no status callbacks to be sent when starting
4631 * a tunnel to a proxy server using the CONNECT verb. i believe our
4632 * behaviour to be more correct and to not cause any incompatibilities
4633 * because using a secure connection through a proxy server is a rare
4634 * case that would be hard for anyone to depend on */
4635 if(session->appInfo->proxy)
4636 res = HTTP_SecureProxyConnect(request);
4637 if(res == ERROR_SUCCESS)
4638 res = NETCON_secure_connect(request->netconn, session->hostName);
4639 if(res != ERROR_SUCCESS)
4640 {
4641 WARN("Couldn't connect securely to host\n");
4642
4643 if((request->hdr.ErrorMask&INTERNET_ERROR_MASK_COMBINED_SEC_CERT) && (
4644 res == ERROR_INTERNET_SEC_CERT_DATE_INVALID
4645 || res == ERROR_INTERNET_INVALID_CA
4646 || res == ERROR_INTERNET_SEC_CERT_NO_REV
4647 || res == ERROR_INTERNET_SEC_CERT_REV_FAILED
4648 || res == ERROR_INTERNET_SEC_CERT_REVOKED
4649 || res == ERROR_INTERNET_SEC_INVALID_CERT
4650 || res == ERROR_INTERNET_SEC_CERT_CN_INVALID))
4651 res = ERROR_INTERNET_SEC_CERT_ERRORS;
4652 }
4653 }
4654
4655 if(res != ERROR_SUCCESS) {
4656 http_release_netconn(request, FALSE);
4657 return res;
4658 }
4659
4660 *reusing = FALSE;
4661 TRACE("Created connection to %s: %p\n", debugstr_w(server->name), netconn);
4662 return ERROR_SUCCESS;
4663}
4664
Mike McCormacka4969062004-07-04 00:24:47 +00004665/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00004666 * HTTP_HttpSendRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004667 *
4668 * Sends the specified request to the HTTP server
4669 *
4670 * RETURNS
Juan Langb2ed9c52011-03-02 17:09:45 -08004671 * ERROR_SUCCESS on success
4672 * win32 error code on failure
Ulrich Czekallac2757242000-06-11 20:04:44 +00004673 *
4674 */
Juan Langb49b2432011-03-01 10:59:39 -08004675static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004676 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
4677 DWORD dwContentLength, BOOL bEndRequest)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004678{
4679 INT cnt;
Jacek Cabanc952e812009-12-03 14:48:54 +01004680 BOOL redirected = FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00004681 LPWSTR requestString = NULL;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004682 INT responseLen;
Rob Shearman14fb4182007-01-04 18:21:13 +00004683 BOOL loop_next;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004684 static const WCHAR szPost[] = { 'P','O','S','T',0 };
Hans Leidekker64359c22007-10-28 16:32:46 +01004685 static const WCHAR szContentLength[] =
4686 { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
4687 WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004688 DWORD res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00004689
Juan Langb49b2432011-03-01 10:59:39 -08004690 TRACE("--> %p\n", request);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004691
Juan Langb49b2432011-03-01 10:59:39 -08004692 assert(request->hdr.htype == WH_HHTTPREQ);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004693
Jacek Cabanf9791342008-02-13 13:34:05 +01004694 /* if the verb is NULL default to GET */
Juan Lang20980062011-03-01 11:18:22 -08004695 if (!request->verb)
4696 request->verb = heap_strdupW(szGET);
Jacek Cabanf9791342008-02-13 13:34:05 +01004697
Juan Lang20980062011-03-01 11:18:22 -08004698 if (dwContentLength || strcmpW(request->verb, szGET))
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004699 {
4700 sprintfW(contentLengthStr, szContentLength, dwContentLength);
Juan Langb49b2432011-03-01 10:59:39 -08004701 HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
Juan Lang20980062011-03-01 11:18:22 -08004702 request->bytesToWrite = dwContentLength;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004703 }
Juan Lang20980062011-03-01 11:18:22 -08004704 if (request->session->appInfo->agent)
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004705 {
4706 WCHAR *agent_header;
4707 static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
4708 int len;
4709
Juan Lang20980062011-03-01 11:18:22 -08004710 len = strlenW(request->session->appInfo->agent) + strlenW(user_agent);
Jacek Caban354a74e2011-04-21 13:39:03 +02004711 agent_header = heap_alloc(len * sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08004712 sprintfW(agent_header, user_agent, request->session->appInfo->agent);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004713
Juan Langb49b2432011-03-01 10:59:39 -08004714 HTTP_HttpAddRequestHeadersW(request, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004715 heap_free(agent_header);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004716 }
Juan Langb49b2432011-03-01 10:59:39 -08004717 if (request->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE)
Hans Leidekker34ff5552008-06-23 20:58:25 +02004718 {
4719 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 -08004720 HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker34ff5552008-06-23 20:58:25 +02004721 }
Juan Lang20980062011-03-01 11:18:22 -08004722 if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost))
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004723 {
4724 static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
4725 ' ','n','o','-','c','a','c','h','e','\r','\n',0};
Juan Langb49b2432011-03-01 10:59:39 -08004726 HTTP_HttpAddRequestHeadersW(request, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004727 }
David Hammerton6226f3f2003-08-05 18:31:02 +00004728
David Hammerton852c7ae2003-06-20 23:26:56 +00004729 do
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004730 {
Aric Stewartbe918f42005-11-21 15:17:55 +00004731 DWORD len;
Piotr Cabanee684732010-06-29 12:20:51 +02004732 BOOL reusing_connection;
Mike McCormacka4969062004-07-04 00:24:47 +00004733 char *ascii_req;
4734
Rob Shearman14fb4182007-01-04 18:21:13 +00004735 loop_next = FALSE;
Rob Shearman272954b2007-01-04 18:23:17 +00004736
4737 /* like native, just in case the caller forgot to call InternetReadFile
4738 * for all the data */
Jacek Caban8a1df202011-05-10 09:26:43 +00004739 drain_content(request);
Piotr Caban224af0d2010-05-20 02:35:38 +02004740 if(redirected) {
Juan Lang20980062011-03-01 11:18:22 -08004741 request->contentLength = ~0u;
4742 request->bytesToWrite = 0;
Piotr Caban224af0d2010-05-20 02:35:38 +02004743 }
Rob Shearman14fb4182007-01-04 18:21:13 +00004744
Rob Shearman4319ec62006-12-07 00:53:27 +00004745 if (TRACE_ON(wininet))
4746 {
Juan Langb49b2432011-03-01 10:59:39 -08004747 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Juan Lang20980062011-03-01 11:18:22 -08004748 TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(request->path));
Rob Shearman4319ec62006-12-07 00:53:27 +00004749 }
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004750
Juan Langb49b2432011-03-01 10:59:39 -08004751 HTTP_FixURL(request);
4752 if (request->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION)
Hans Leidekker656a0352008-05-31 21:47:24 +02004753 {
Juan Langb49b2432011-03-01 10:59:39 -08004754 HTTP_ProcessHeader(request, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
Hans Leidekker656a0352008-05-31 21:47:24 +02004755 }
Juan Lang20980062011-03-01 11:18:22 -08004756 HTTP_InsertAuthorization(request, request->authInfo, szAuthorization);
4757 HTTP_InsertAuthorization(request, request->proxyAuthInfo, szProxy_Authorization);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004758
Juan Langb49b2432011-03-01 10:59:39 -08004759 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
4760 HTTP_InsertCookies(request);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004761
Mike McCormackf1d7b142004-07-21 19:36:34 +00004762 /* add the headers the caller supplied */
Mike McCormack08c6c692004-08-10 23:41:35 +00004763 if( lpszHeaders && dwHeaderLength )
Mike McCormackf1d7b142004-07-21 19:36:34 +00004764 {
Juan Langb49b2432011-03-01 10:59:39 -08004765 HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength,
Mike McCormack08c6c692004-08-10 23:41:35 +00004766 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
Mike McCormackf1d7b142004-07-21 19:36:34 +00004767 }
4768
Juan Lang20980062011-03-01 11:18:22 -08004769 if (request->session->appInfo->proxy && request->session->appInfo->proxy[0])
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004770 {
Juan Langb49b2432011-03-01 10:59:39 -08004771 WCHAR *url = HTTP_BuildProxyRequestUrl(request);
Juan Lang20980062011-03-01 11:18:22 -08004772 requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004773 heap_free(url);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004774 }
4775 else
Juan Lang20980062011-03-01 11:18:22 -08004776 requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004777
Mike McCormacka4969062004-07-04 00:24:47 +00004778
4779 TRACE("Request header -> %s\n", debugstr_w(requestString) );
Aric Stewartff9b9d42002-06-21 23:59:49 +00004780
Jacek Caban8a1df202011-05-10 09:26:43 +00004781 if ((res = open_http_connection(request, &reusing_connection)) != ERROR_SUCCESS)
4782 break;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004783
Mike McCormacka4969062004-07-04 00:24:47 +00004784 /* send the request as ASCII, tack on the optional data */
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004785 if (!lpOptional || redirected)
Mike McCormacka4969062004-07-04 00:24:47 +00004786 dwOptionalLength = 0;
4787 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4788 NULL, 0, NULL, NULL );
Jacek Caban354a74e2011-04-21 13:39:03 +02004789 ascii_req = heap_alloc(len + dwOptionalLength);
Mike McCormacka4969062004-07-04 00:24:47 +00004790 WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4791 ascii_req, len, NULL, NULL );
4792 if( lpOptional )
Mike McCormackf1d7b142004-07-21 19:36:34 +00004793 memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
4794 len = (len + dwOptionalLength - 1);
4795 ascii_req[len] = 0;
Aric Stewart44cbdf22005-10-19 18:28:35 +00004796 TRACE("full request -> %s\n", debugstr_a(ascii_req) );
Mike McCormackf1d7b142004-07-21 19:36:34 +00004797
Juan Langb49b2432011-03-01 10:59:39 -08004798 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004799 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Mike McCormackf1d7b142004-07-21 19:36:34 +00004800
Jacek Caban8a1df202011-05-10 09:26:43 +00004801 res = NETCON_send(request->netconn, ascii_req, len, 0, &cnt);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004802 heap_free( ascii_req );
Jacek Caban8a1df202011-05-10 09:26:43 +00004803 if(res != ERROR_SUCCESS) {
4804 TRACE("send failed: %u\n", res);
4805 if(!reusing_connection)
4806 break;
4807 http_release_netconn(request, FALSE);
4808 loop_next = TRUE;
4809 continue;
4810 }
David Hammerton852c7ae2003-06-20 23:26:56 +00004811
Juan Lang20980062011-03-01 11:18:22 -08004812 request->bytesWritten = dwOptionalLength;
Hans Leidekker0fabf542009-04-08 15:21:28 +02004813
Juan Langb49b2432011-03-01 10:59:39 -08004814 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004815 INTERNET_STATUS_REQUEST_SENT,
4816 &len, sizeof(DWORD));
David Hammerton852c7ae2003-06-20 23:26:56 +00004817
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004818 if (bEndRequest)
4819 {
Rob Shearmanac1b5272007-01-04 18:21:49 +00004820 DWORD dwBufferSize;
Rob Shearmancb289692007-06-05 19:49:58 +01004821 DWORD dwStatusCode;
Rob Shearmanac1b5272007-01-04 18:21:49 +00004822
Juan Langb49b2432011-03-01 10:59:39 -08004823 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004824 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
4825
Juan Langb49b2432011-03-01 10:59:39 -08004826 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Piotr Cabanee684732010-06-29 12:20:51 +02004827 /* FIXME: We should know that connection is closed before sending
4828 * headers. Otherwise wrong callbacks are executed */
4829 if(!responseLen && reusing_connection) {
4830 TRACE("Connection closed by server, reconnecting\n");
Jacek Caban8a1df202011-05-10 09:26:43 +00004831 http_release_netconn(request, FALSE);
Piotr Cabanee684732010-06-29 12:20:51 +02004832 loop_next = TRUE;
4833 continue;
4834 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004835
Juan Langb49b2432011-03-01 10:59:39 -08004836 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004837 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
4838 sizeof(DWORD));
Rob Shearman4319ec62006-12-07 00:53:27 +00004839
Jacek Caban8a1df202011-05-10 09:26:43 +00004840 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08004841 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004842 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08004843 HTTP_ProcessLastModified(request);
Rob Shearman4319ec62006-12-07 00:53:27 +00004844
Rob Shearmancb289692007-06-05 19:49:58 +01004845 dwBufferSize = sizeof(dwStatusCode);
Juan Langb49b2432011-03-01 10:59:39 -08004846 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
Jacek Caban9823c232009-12-14 02:27:29 +01004847 &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS)
Rob Shearmancb289692007-06-05 19:49:58 +01004848 dwStatusCode = 0;
4849
Jacek Cabana890e3a2011-05-13 13:48:15 +02004850 res = set_content_length(request, dwStatusCode);
4851 if(res != ERROR_SUCCESS)
4852 goto lend;
4853 if(!request->contentLength)
4854 http_release_netconn(request, TRUE);
4855
Juan Langb49b2432011-03-01 10:59:39 -08004856 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
Rob Shearman4319ec62006-12-07 00:53:27 +00004857 {
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004858 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
Rob Shearman9efe0832007-01-12 19:19:18 -06004859 dwBufferSize=sizeof(szNewLocation);
Hans Leidekker94deb852010-08-27 10:50:59 +02004860 if ((dwStatusCode == HTTP_STATUS_REDIRECT ||
4861 dwStatusCode == HTTP_STATUS_MOVED ||
Karsten Elfenbein5b173cb2011-05-08 12:29:06 +02004862 dwStatusCode == HTTP_STATUS_REDIRECT_KEEP_VERB ||
Hans Leidekker94deb852010-08-27 10:50:59 +02004863 dwStatusCode == HTTP_STATUS_REDIRECT_METHOD) &&
Juan Langb49b2432011-03-01 10:59:39 -08004864 HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS)
Rob Shearman4319ec62006-12-07 00:53:27 +00004865 {
Hans Leidekker14d4d192011-06-01 11:50:32 +02004866 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
4867 dwStatusCode != HTTP_STATUS_REDIRECT_KEEP_VERB)
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004868 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004869 heap_free(request->verb);
Juan Lang20980062011-03-01 11:18:22 -08004870 request->verb = heap_strdupW(szGET);
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004871 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004872 drain_content(request);
Juan Langb49b2432011-03-01 10:59:39 -08004873 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
Rob Shearman4319ec62006-12-07 00:53:27 +00004874 {
Juan Langb49b2432011-03-01 10:59:39 -08004875 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004876 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
Juan Langb49b2432011-03-01 10:59:39 -08004877 res = HTTP_HandleRedirect(request, new_url);
Jacek Cabana9ecdc62009-12-03 14:49:56 +01004878 if (res == ERROR_SUCCESS)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004879 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004880 heap_free(requestString);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004881 loop_next = TRUE;
4882 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004883 heap_free( new_url );
Rob Shearman4319ec62006-12-07 00:53:27 +00004884 }
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004885 redirected = TRUE;
Rob Shearman4319ec62006-12-07 00:53:27 +00004886 }
4887 }
Juan Langb49b2432011-03-01 10:59:39 -08004888 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004889 {
Rob Shearman4b507682007-05-21 14:26:26 +01004890 WCHAR szAuthValue[2048];
4891 dwBufferSize=2048;
Rob Shearmancb289692007-06-05 19:49:58 +01004892 if (dwStatusCode == HTTP_STATUS_DENIED)
Rob Shearman4b507682007-05-21 14:26:26 +01004893 {
Juan Langb49b2432011-03-01 10:59:39 -08004894 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Rob Shearman4b507682007-05-21 14:26:26 +01004895 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004896 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004897 {
Juan Langb49b2432011-03-01 10:59:39 -08004898 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004899 &request->authInfo,
4900 request->session->userName,
4901 request->session->password,
Aric Stewartfc508932009-10-12 14:24:18 -05004902 Host->lpszValue))
Rob Shearmancb289692007-06-05 19:49:58 +01004903 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004904 heap_free(requestString);
Rob Shearmancb289692007-06-05 19:49:58 +01004905 loop_next = TRUE;
4906 break;
4907 }
4908 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004909
4910 if(!loop_next) {
4911 TRACE("Cleaning wrong authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004912 destroy_authinfo(request->authInfo);
4913 request->authInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004914 }
Rob Shearmancb289692007-06-05 19:49:58 +01004915 }
4916 if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
4917 {
4918 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004919 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearmancb289692007-06-05 19:49:58 +01004920 {
Juan Langb49b2432011-03-01 10:59:39 -08004921 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004922 &request->proxyAuthInfo,
4923 request->session->appInfo->proxyUsername,
4924 request->session->appInfo->proxyPassword,
Aric Stewartfc508932009-10-12 14:24:18 -05004925 NULL))
Rob Shearman4b507682007-05-21 14:26:26 +01004926 {
4927 loop_next = TRUE;
4928 break;
4929 }
4930 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004931
4932 if(!loop_next) {
4933 TRACE("Cleaning wrong proxy authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004934 destroy_authinfo(request->proxyAuthInfo);
4935 request->proxyAuthInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004936 }
Rob Shearman4b507682007-05-21 14:26:26 +01004937 }
4938 }
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004939 }
4940 else
Jacek Cabanc952e812009-12-03 14:48:54 +01004941 res = ERROR_SUCCESS;
David Hammerton852c7ae2003-06-20 23:26:56 +00004942 }
4943 while (loop_next);
Aric Stewartff9b9d42002-06-21 23:59:49 +00004944
Juan Lang666353d2011-03-02 10:06:37 -08004945 if(res == ERROR_SUCCESS)
4946 HTTP_CacheRequest(request);
Jacek Caband7a49e82008-02-13 13:32:49 +01004947
Ulrich Czekallac2757242000-06-11 20:04:44 +00004948lend:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004949 heap_free(requestString);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004950
Alberto Massaribc8bd722002-12-06 23:20:31 +00004951 /* TODO: send notification for P3P header */
Vincent Béron9a624912002-05-31 23:06:46 +00004952
Juan Lang20980062011-03-01 11:18:22 -08004953 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Hans Leidekker3a711fb2009-04-08 15:22:26 +02004954 {
Jacek Caban8e37ed52011-06-10 14:47:16 +02004955 if (res == ERROR_SUCCESS) {
Andy Claytonda110752011-11-23 08:45:44 -06004956 if(bEndRequest && request->contentLength && request->bytesWritten == request->bytesToWrite)
Jacek Caban8e37ed52011-06-10 14:47:16 +02004957 HTTP_ReceiveRequestData(request, TRUE);
4958 else
4959 send_request_complete(request,
4960 request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0);
4961 }else {
4962 send_request_complete(request, 0, res);
4963 }
Jacek Caban12931062009-01-13 00:28:25 +01004964 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00004965
4966 TRACE("<--\n");
Jacek Cabanc952e812009-12-03 14:48:54 +01004967 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00004968}
4969
Ulrich Czekallac2757242000-06-11 20:04:44 +00004970/***********************************************************************
Jacek Caban34fcbb52009-11-30 20:01:17 +01004971 *
4972 * Helper functions for the HttpSendRequest(Ex) functions
4973 *
4974 */
4975static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
4976{
4977 struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08004978 http_request_t *request = (http_request_t*) workRequest->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004979
Juan Langb49b2432011-03-01 10:59:39 -08004980 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004981
Juan Langb49b2432011-03-01 10:59:39 -08004982 HTTP_HttpSendRequestW(request, req->lpszHeader,
Jacek Caban34fcbb52009-11-30 20:01:17 +01004983 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
4984 req->dwContentLength, req->bEndRequest);
4985
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004986 heap_free(req->lpszHeader);
Jacek Caban34fcbb52009-11-30 20:01:17 +01004987}
4988
4989
Juan Langb49b2432011-03-01 10:59:39 -08004990static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext)
Jacek Caban34fcbb52009-11-30 20:01:17 +01004991{
Jacek Caban34fcbb52009-11-30 20:01:17 +01004992 INT responseLen;
Jacek Cabana890e3a2011-05-13 13:48:15 +02004993 DWORD dwCode, dwCodeLength;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004994 DWORD dwBufferSize;
Jacek Caban741b6612009-12-03 14:49:29 +01004995 DWORD res = ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01004996
Jacek Caban892d3cd2011-12-07 16:40:27 +01004997 if(!request->netconn) {
4998 WARN("Not connected\n");
4999 send_request_complete(request, 0, ERROR_INTERNET_OPERATION_CANCELLED);
5000 return ERROR_INTERNET_OPERATION_CANCELLED;
5001 }
5002
Juan Langb49b2432011-03-01 10:59:39 -08005003 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005004 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
5005
Juan Langb49b2432011-03-01 10:59:39 -08005006 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Jacek Caban741b6612009-12-03 14:49:29 +01005007 if (!responseLen)
5008 res = ERROR_HTTP_HEADER_NOT_FOUND;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005009
Juan Langb49b2432011-03-01 10:59:39 -08005010 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005011 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
5012
5013 /* process cookies here. Is this right? */
Jacek Caban8a1df202011-05-10 09:26:43 +00005014 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08005015 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08005016 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08005017 HTTP_ProcessLastModified(request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005018
Jacek Cabana890e3a2011-05-13 13:48:15 +02005019 dwCodeLength = sizeof(dwCode);
5020 if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
5021 &dwCode,&dwCodeLength,NULL) != ERROR_SUCCESS)
5022 dwCode = 0;
5023
5024 if ((res = set_content_length( request, dwCode )) == ERROR_SUCCESS) {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005025 if(!request->contentLength)
Jacek Caban8a1df202011-05-10 09:26:43 +00005026 http_release_netconn(request, TRUE);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005027 }
Jacek Caban34fcbb52009-11-30 20:01:17 +01005028
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005029 if (res == ERROR_SUCCESS && !(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
Jacek Caban34fcbb52009-11-30 20:01:17 +01005030 {
Jacek Cabana890e3a2011-05-13 13:48:15 +02005031 if (dwCode == HTTP_STATUS_REDIRECT ||
Karsten Elfenbein5b173cb2011-05-08 12:29:06 +02005032 dwCode == HTTP_STATUS_MOVED ||
5033 dwCode == HTTP_STATUS_REDIRECT_METHOD ||
Jacek Cabana890e3a2011-05-13 13:48:15 +02005034 dwCode == HTTP_STATUS_REDIRECT_KEEP_VERB)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005035 {
5036 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
5037 dwBufferSize=sizeof(szNewLocation);
Juan Langb49b2432011-03-01 10:59:39 -08005038 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005039 {
Hans Leidekker14d4d192011-06-01 11:50:32 +02005040 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
5041 dwCode != HTTP_STATUS_REDIRECT_KEEP_VERB)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005042 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005043 heap_free(request->verb);
Juan Lang20980062011-03-01 11:18:22 -08005044 request->verb = heap_strdupW(szGET);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005045 }
Jacek Caban8a1df202011-05-10 09:26:43 +00005046 drain_content(request);
Juan Langb49b2432011-03-01 10:59:39 -08005047 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
Jacek Caban34fcbb52009-11-30 20:01:17 +01005048 {
Juan Langb49b2432011-03-01 10:59:39 -08005049 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005050 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
Juan Langb49b2432011-03-01 10:59:39 -08005051 res = HTTP_HandleRedirect(request, new_url);
Jacek Cabana9ecdc62009-12-03 14:49:56 +01005052 if (res == ERROR_SUCCESS)
Juan Langb49b2432011-03-01 10:59:39 -08005053 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005054 heap_free( new_url );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005055 }
5056 }
5057 }
5058 }
5059
Jacek Cabanc0293df2011-06-10 14:47:04 +02005060 if (res == ERROR_SUCCESS && request->contentLength)
Jacek Caban685daf22011-03-17 01:01:49 +01005061 HTTP_ReceiveRequestData(request, TRUE);
Jacek Cabanc0293df2011-06-10 14:47:04 +02005062 else
Jacek Caban8e37ed52011-06-10 14:47:16 +02005063 send_request_complete(request, res == ERROR_SUCCESS, res);
Jacek Caban685daf22011-03-17 01:01:49 +01005064
Jacek Caban741b6612009-12-03 14:49:29 +01005065 return res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005066}
5067
5068/***********************************************************************
5069 * HttpEndRequestA (WININET.@)
5070 *
5071 * Ends an HTTP request that was started by HttpSendRequestEx
5072 *
5073 * RETURNS
5074 * TRUE if successful
5075 * FALSE on failure
5076 *
5077 */
5078BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
5079 LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
5080{
5081 TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
5082
5083 if (lpBuffersOut)
5084 {
Jacek Cabane1958a62009-12-21 13:58:18 +01005085 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005086 return FALSE;
5087 }
5088
5089 return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
5090}
5091
5092static void AsyncHttpEndRequestProc(WORKREQUEST *work)
5093{
5094 struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08005095 http_request_t *request = (http_request_t*)work->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005096
Juan Langb49b2432011-03-01 10:59:39 -08005097 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005098
Juan Langb49b2432011-03-01 10:59:39 -08005099 HTTP_HttpEndRequestW(request, req->dwFlags, req->dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005100}
5101
5102/***********************************************************************
5103 * HttpEndRequestW (WININET.@)
5104 *
5105 * Ends an HTTP request that was started by HttpSendRequestEx
5106 *
5107 * RETURNS
5108 * TRUE if successful
5109 * FALSE on failure
5110 *
5111 */
5112BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
5113 LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
5114{
Juan Langb49b2432011-03-01 10:59:39 -08005115 http_request_t *request;
Jacek Caban741b6612009-12-03 14:49:29 +01005116 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005117
Jacek Cabanc0293df2011-06-10 14:47:04 +02005118 TRACE("%p %p %x %lx -->\n", hRequest, lpBuffersOut, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005119
5120 if (lpBuffersOut)
5121 {
Jacek Caban741b6612009-12-03 14:49:29 +01005122 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005123 return FALSE;
5124 }
5125
Juan Langb49b2432011-03-01 10:59:39 -08005126 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005127
Juan Langb49b2432011-03-01 10:59:39 -08005128 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005129 {
Jacek Caban741b6612009-12-03 14:49:29 +01005130 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
Juan Langb49b2432011-03-01 10:59:39 -08005131 if (request)
5132 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005133 return FALSE;
5134 }
Juan Langb49b2432011-03-01 10:59:39 -08005135 request->hdr.dwFlags |= dwFlags;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005136
Juan Lang20980062011-03-01 11:18:22 -08005137 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005138 {
5139 WORKREQUEST work;
Juan Langb49b2432011-03-01 10:59:39 -08005140 struct WORKREQ_HTTPENDREQUESTW *work_endrequest;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005141
5142 work.asyncproc = AsyncHttpEndRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005143 work.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005144
Juan Langb49b2432011-03-01 10:59:39 -08005145 work_endrequest = &work.u.HttpEndRequestW;
5146 work_endrequest->dwFlags = dwFlags;
5147 work_endrequest->dwContext = dwContext;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005148
5149 INTERNET_AsyncCall(&work);
Jacek Caban741b6612009-12-03 14:49:29 +01005150 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005151 }
5152 else
Juan Langb49b2432011-03-01 10:59:39 -08005153 res = HTTP_HttpEndRequestW(request, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005154
Juan Langb49b2432011-03-01 10:59:39 -08005155 WININET_Release( &request->hdr );
Jacek Caban741b6612009-12-03 14:49:29 +01005156 TRACE("%u <--\n", res);
5157 if(res != ERROR_SUCCESS)
5158 SetLastError(res);
5159 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005160}
5161
5162/***********************************************************************
5163 * HttpSendRequestExA (WININET.@)
5164 *
5165 * Sends the specified request to the HTTP server and allows chunked
5166 * transfers.
5167 *
5168 * RETURNS
5169 * Success: TRUE
5170 * Failure: FALSE, call GetLastError() for more information.
5171 */
5172BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
5173 LPINTERNET_BUFFERSA lpBuffersIn,
5174 LPINTERNET_BUFFERSA lpBuffersOut,
5175 DWORD dwFlags, DWORD_PTR dwContext)
5176{
5177 INTERNET_BUFFERSW BuffersInW;
5178 BOOL rc = FALSE;
5179 DWORD headerlen;
5180 LPWSTR header = NULL;
5181
5182 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5183 lpBuffersOut, dwFlags, dwContext);
5184
5185 if (lpBuffersIn)
5186 {
5187 BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
5188 if (lpBuffersIn->lpcszHeader)
5189 {
5190 headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
5191 lpBuffersIn->dwHeadersLength,0,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005192 header = heap_alloc(headerlen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005193 if (!(BuffersInW.lpcszHeader = header))
5194 {
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005195 SetLastError(ERROR_OUTOFMEMORY);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005196 return FALSE;
5197 }
5198 BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
5199 lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
5200 header, headerlen);
5201 }
5202 else
5203 BuffersInW.lpcszHeader = NULL;
5204 BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
5205 BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
5206 BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
5207 BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
5208 BuffersInW.Next = NULL;
5209 }
5210
5211 rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
5212
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005213 heap_free(header);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005214 return rc;
5215}
5216
5217/***********************************************************************
5218 * HttpSendRequestExW (WININET.@)
5219 *
5220 * Sends the specified request to the HTTP server and allows chunked
5221 * transfers
5222 *
5223 * RETURNS
5224 * Success: TRUE
5225 * Failure: FALSE, call GetLastError() for more information.
5226 */
5227BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
5228 LPINTERNET_BUFFERSW lpBuffersIn,
5229 LPINTERNET_BUFFERSW lpBuffersOut,
5230 DWORD dwFlags, DWORD_PTR dwContext)
5231{
Juan Langb49b2432011-03-01 10:59:39 -08005232 http_request_t *request;
5233 http_session_t *session;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005234 appinfo_t *hIC;
Jacek Cabanc952e812009-12-03 14:48:54 +01005235 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005236
5237 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5238 lpBuffersOut, dwFlags, dwContext);
5239
Juan Langb49b2432011-03-01 10:59:39 -08005240 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005241
Juan Langb49b2432011-03-01 10:59:39 -08005242 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005243 {
Jacek Cabanc952e812009-12-03 14:48:54 +01005244 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005245 goto lend;
5246 }
5247
Juan Lang20980062011-03-01 11:18:22 -08005248 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005249 assert(session->hdr.htype == WH_HHTTPSESSION);
Juan Lang8e050392011-03-01 11:02:14 -08005250 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005251 assert(hIC->hdr.htype == WH_HINIT);
5252
5253 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5254 {
5255 WORKREQUEST workRequest;
5256 struct WORKREQ_HTTPSENDREQUESTW *req;
5257
5258 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005259 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005260 req = &workRequest.u.HttpSendRequestW;
5261 if (lpBuffersIn)
5262 {
5263 DWORD size = 0;
5264
5265 if (lpBuffersIn->lpcszHeader)
5266 {
5267 if (lpBuffersIn->dwHeadersLength == ~0u)
5268 size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
5269 else
5270 size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
5271
Jacek Caban354a74e2011-04-21 13:39:03 +02005272 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005273 memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
5274 }
5275 else req->lpszHeader = NULL;
5276
5277 req->dwHeaderLength = size / sizeof(WCHAR);
5278 req->lpOptional = lpBuffersIn->lpvBuffer;
5279 req->dwOptionalLength = lpBuffersIn->dwBufferLength;
5280 req->dwContentLength = lpBuffersIn->dwBufferTotal;
5281 }
5282 else
5283 {
5284 req->lpszHeader = NULL;
5285 req->dwHeaderLength = 0;
5286 req->lpOptional = NULL;
5287 req->dwOptionalLength = 0;
5288 req->dwContentLength = 0;
5289 }
5290
5291 req->bEndRequest = FALSE;
5292
5293 INTERNET_AsyncCall(&workRequest);
5294 /*
5295 * This is from windows.
5296 */
Jacek Cabanc952e812009-12-03 14:48:54 +01005297 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005298 }
5299 else
5300 {
5301 if (lpBuffersIn)
Juan Langb49b2432011-03-01 10:59:39 -08005302 res = HTTP_HttpSendRequestW(request, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005303 lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
5304 lpBuffersIn->dwBufferTotal, FALSE);
5305 else
Juan Langb49b2432011-03-01 10:59:39 -08005306 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, FALSE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005307 }
5308
5309lend:
Juan Langb49b2432011-03-01 10:59:39 -08005310 if ( request )
5311 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005312
5313 TRACE("<---\n");
Hans Leidekker68453a52009-12-21 11:13:44 +01005314 SetLastError(res);
Jacek Cabanc952e812009-12-03 14:48:54 +01005315 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005316}
5317
5318/***********************************************************************
5319 * HttpSendRequestW (WININET.@)
5320 *
5321 * Sends the specified request to the HTTP server
5322 *
5323 * RETURNS
5324 * TRUE on success
5325 * FALSE on failure
5326 *
5327 */
5328BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
5329 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5330{
Juan Langb49b2432011-03-01 10:59:39 -08005331 http_request_t *request;
5332 http_session_t *session = NULL;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005333 appinfo_t *hIC = NULL;
5334 DWORD res = ERROR_SUCCESS;
5335
5336 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
5337 debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
5338
Juan Langb49b2432011-03-01 10:59:39 -08005339 request = (http_request_t*) get_handle_object( hHttpRequest );
5340 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005341 {
5342 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5343 goto lend;
5344 }
5345
Juan Lang20980062011-03-01 11:18:22 -08005346 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005347 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005348 {
5349 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5350 goto lend;
5351 }
5352
Juan Lang8e050392011-03-01 11:02:14 -08005353 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005354 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
5355 {
5356 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5357 goto lend;
5358 }
5359
5360 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5361 {
5362 WORKREQUEST workRequest;
5363 struct WORKREQ_HTTPSENDREQUESTW *req;
5364
5365 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005366 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005367 req = &workRequest.u.HttpSendRequestW;
5368 if (lpszHeaders)
5369 {
5370 DWORD size;
5371
5372 if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
5373 else size = dwHeaderLength * sizeof(WCHAR);
5374
Jacek Caban354a74e2011-04-21 13:39:03 +02005375 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005376 memcpy(req->lpszHeader, lpszHeaders, size);
5377 }
5378 else
5379 req->lpszHeader = 0;
5380 req->dwHeaderLength = dwHeaderLength;
5381 req->lpOptional = lpOptional;
5382 req->dwOptionalLength = dwOptionalLength;
5383 req->dwContentLength = dwOptionalLength;
5384 req->bEndRequest = TRUE;
5385
5386 INTERNET_AsyncCall(&workRequest);
5387 /*
5388 * This is from windows.
5389 */
5390 res = ERROR_IO_PENDING;
5391 }
5392 else
5393 {
Juan Langb49b2432011-03-01 10:59:39 -08005394 res = HTTP_HttpSendRequestW(request, lpszHeaders,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005395 dwHeaderLength, lpOptional, dwOptionalLength,
5396 dwOptionalLength, TRUE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005397 }
5398lend:
Juan Langb49b2432011-03-01 10:59:39 -08005399 if( request )
5400 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005401
Hans Leidekker68453a52009-12-21 11:13:44 +01005402 SetLastError(res);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005403 return res == ERROR_SUCCESS;
5404}
5405
5406/***********************************************************************
5407 * HttpSendRequestA (WININET.@)
5408 *
5409 * Sends the specified request to the HTTP server
5410 *
5411 * RETURNS
5412 * TRUE on success
5413 * FALSE on failure
5414 *
5415 */
5416BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
5417 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5418{
5419 BOOL result;
5420 LPWSTR szHeaders=NULL;
5421 DWORD nLen=dwHeaderLength;
5422 if(lpszHeaders!=NULL)
5423 {
5424 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005425 szHeaders = heap_alloc(nLen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005426 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
5427 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005428 result = HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
5429 heap_free(szHeaders);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005430 return result;
5431}
5432
5433/***********************************************************************
Jacek Caban5a535d62008-02-26 20:20:41 +01005434 * HTTPSESSION_Destroy (internal)
5435 *
5436 * Deallocate session handle
5437 *
5438 */
Jacek Caban44d633a2009-07-07 21:46:09 +02005439static void HTTPSESSION_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01005440{
Juan Langb49b2432011-03-01 10:59:39 -08005441 http_session_t *session = (http_session_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01005442
Juan Langb49b2432011-03-01 10:59:39 -08005443 TRACE("%p\n", session);
Jacek Caban5a535d62008-02-26 20:20:41 +01005444
Juan Lang8e050392011-03-01 11:02:14 -08005445 WININET_Release(&session->appInfo->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01005446
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005447 heap_free(session->hostName);
5448 heap_free(session->serverName);
5449 heap_free(session->password);
5450 heap_free(session->userName);
Jacek Caban5a535d62008-02-26 20:20:41 +01005451}
5452
Jacek Caban44d633a2009-07-07 21:46:09 +02005453static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01005454{
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005455 http_session_t *ses = (http_session_t *)hdr;
5456
Jacek Cabane2933c22008-03-12 02:23:20 +01005457 switch(option) {
5458 case INTERNET_OPTION_HANDLE_TYPE:
5459 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
5460
5461 if (*size < sizeof(ULONG))
5462 return ERROR_INSUFFICIENT_BUFFER;
5463
5464 *size = sizeof(DWORD);
5465 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
5466 return ERROR_SUCCESS;
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005467 case INTERNET_OPTION_CONNECT_TIMEOUT:
5468 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
5469
5470 if (*size < sizeof(DWORD))
5471 return ERROR_INSUFFICIENT_BUFFER;
5472
5473 *size = sizeof(DWORD);
5474 *(DWORD *)buffer = ses->connect_timeout;
5475 return ERROR_SUCCESS;
Jacek Cabane2933c22008-03-12 02:23:20 +01005476 }
5477
Hans Leidekker80dd3672010-05-25 12:19:32 +02005478 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01005479}
Jacek Caban5a535d62008-02-26 20:20:41 +01005480
Jacek Caban44d633a2009-07-07 21:46:09 +02005481static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Hans Leidekker8c201242008-09-24 16:54:37 +02005482{
Jacek Cabane9f4a402009-07-13 01:41:18 +02005483 http_session_t *ses = (http_session_t*)hdr;
Hans Leidekker8c201242008-09-24 16:54:37 +02005484
5485 switch(option) {
5486 case INTERNET_OPTION_USERNAME:
5487 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005488 heap_free(ses->userName);
Juan Lang8e050392011-03-01 11:02:14 -08005489 if (!(ses->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005490 return ERROR_SUCCESS;
5491 }
5492 case INTERNET_OPTION_PASSWORD:
5493 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005494 heap_free(ses->password);
Juan Lang8e050392011-03-01 11:02:14 -08005495 if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005496 return ERROR_SUCCESS;
5497 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005498 case INTERNET_OPTION_CONNECT_TIMEOUT:
5499 {
5500 ses->connect_timeout = *(DWORD *)buffer;
5501 return ERROR_SUCCESS;
5502 }
Hans Leidekker8c201242008-09-24 16:54:37 +02005503 default: break;
5504 }
5505
5506 return ERROR_INTERNET_INVALID_OPTION;
5507}
5508
Jacek Caban44d633a2009-07-07 21:46:09 +02005509static const object_vtbl_t HTTPSESSIONVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005510 HTTPSESSION_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01005511 NULL,
Jacek Cabane2933c22008-03-12 02:23:20 +01005512 HTTPSESSION_QueryOption,
Hans Leidekker8c201242008-09-24 16:54:37 +02005513 HTTPSESSION_SetOption,
Jacek Caban8c45eec2008-02-27 18:55:09 +01005514 NULL,
Jacek Caban33141842008-02-29 12:57:57 +01005515 NULL,
Jacek Caban3b4ca692008-03-02 19:35:11 +01005516 NULL,
Jacek Caband597fd12008-03-03 18:07:20 +01005517 NULL,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005518 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01005519};
5520
5521
5522/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005523 * HTTP_Connect (internal)
5524 *
5525 * Create http session handle
5526 *
5527 * RETURNS
5528 * HINTERNET a session handle on success
5529 * NULL on failure
5530 *
5531 */
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005532DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
Juan Lang8e050392011-03-01 11:02:14 -08005533 INTERNET_PORT serverPort, LPCWSTR lpszUserName,
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005534 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
5535 DWORD dwInternalFlags, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005536{
Juan Langb49b2432011-03-01 10:59:39 -08005537 http_session_t *session = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005538
Aric Stewartff9b9d42002-06-21 23:59:49 +00005539 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005540
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005541 if (!lpszServerName || !lpszServerName[0])
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005542 return ERROR_INVALID_PARAMETER;
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005543
Mike McCormack3a1391b2004-07-19 21:49:39 +00005544 assert( hIC->hdr.htype == WH_HINIT );
Ulrich Czekallac2757242000-06-11 20:04:44 +00005545
Juan Langb49b2432011-03-01 10:59:39 -08005546 session = alloc_object(&hIC->hdr, &HTTPSESSIONVtbl, sizeof(http_session_t));
5547 if (!session)
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005548 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005549
Aric Stewartff9b9d42002-06-21 23:59:49 +00005550 /*
5551 * According to my tests. The name is not resolved until a request is sent
5552 */
Ulrich Czekallac2757242000-06-11 20:04:44 +00005553
Juan Langb49b2432011-03-01 10:59:39 -08005554 session->hdr.htype = WH_HHTTPSESSION;
5555 session->hdr.dwFlags = dwFlags;
5556 session->hdr.dwContext = dwContext;
5557 session->hdr.dwInternalFlags |= dwInternalFlags;
Mike McCormack3a1391b2004-07-19 21:49:39 +00005558
Jacek Cabanc2506172006-10-29 18:48:48 +01005559 WININET_AddRef( &hIC->hdr );
Juan Lang8e050392011-03-01 11:02:14 -08005560 session->appInfo = hIC;
Juan Langb49b2432011-03-01 10:59:39 -08005561 list_add_head( &hIC->hdr.children, &session->hdr.entry );
Jacek Cabanc2506172006-10-29 18:48:48 +01005562
Juan Lang72431562011-03-01 11:00:49 -08005563 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) {
5564 if(hIC->proxyBypass)
Dominik Strasser94c02fe2003-04-14 21:32:36 +00005565 FIXME("Proxy bypass is ignored.\n");
5566 }
Juan Lang8e050392011-03-01 11:02:14 -08005567 session->serverName = heap_strdupW(lpszServerName);
5568 session->hostName = heap_strdupW(lpszServerName);
Robert Shearmanef209362006-03-10 12:28:52 +00005569 if (lpszUserName && lpszUserName[0])
Juan Lang8e050392011-03-01 11:02:14 -08005570 session->userName = heap_strdupW(lpszUserName);
Rob Shearman4b507682007-05-21 14:26:26 +01005571 if (lpszPassword && lpszPassword[0])
Juan Lang8e050392011-03-01 11:02:14 -08005572 session->password = heap_strdupW(lpszPassword);
5573 session->serverPort = serverPort;
5574 session->hostPort = serverPort;
Hans Leidekker72273a02012-01-13 15:15:04 +01005575 session->connect_timeout = INFINITE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005576
Kevin Koltzau917df922004-05-13 05:17:25 +00005577 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
Juan Langb49b2432011-03-01 10:59:39 -08005578 if (!(session->hdr.dwInternalFlags & INET_OPENURL))
Ulrich Czekallac2757242000-06-11 20:04:44 +00005579 {
Robert Shearmande2666f2005-11-29 10:44:05 +01005580 INTERNET_SendCallback(&hIC->hdr, dwContext,
Juan Langb49b2432011-03-01 10:59:39 -08005581 INTERNET_STATUS_HANDLE_CREATED, &session->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01005582 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005583 }
5584
Aric Stewartff9b9d42002-06-21 23:59:49 +00005585/*
Francois Gouget93416cd2005-03-23 13:15:18 +00005586 * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
Aric Stewartff9b9d42002-06-21 23:59:49 +00005587 * windows
5588 */
Vincent Béron9a624912002-05-31 23:06:46 +00005589
Juan Langb49b2432011-03-01 10:59:39 -08005590 TRACE("%p --> %p\n", hIC, session);
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005591
Juan Langb49b2432011-03-01 10:59:39 -08005592 *ret = session->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01005593 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005594}
5595
Ulrich Czekallac2757242000-06-11 20:04:44 +00005596/***********************************************************************
Alexandre Julliard48243e32004-07-15 18:57:32 +00005597 * HTTP_clear_response_headers (internal)
5598 *
5599 * clear out any old response headers
5600 */
Juan Langb49b2432011-03-01 10:59:39 -08005601static void HTTP_clear_response_headers( http_request_t *request )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005602{
5603 DWORD i;
5604
Juan Langb49b2432011-03-01 10:59:39 -08005605 for( i=0; i<request->nCustHeaders; i++)
Alexandre Julliard48243e32004-07-15 18:57:32 +00005606 {
Juan Lang20980062011-03-01 11:18:22 -08005607 if( !request->custHeaders[i].lpszField )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005608 continue;
Juan Lang20980062011-03-01 11:18:22 -08005609 if( !request->custHeaders[i].lpszValue )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005610 continue;
Juan Lang20980062011-03-01 11:18:22 -08005611 if ( request->custHeaders[i].wFlags & HDR_ISREQUEST )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005612 continue;
Juan Langb49b2432011-03-01 10:59:39 -08005613 HTTP_DeleteCustomHeader( request, i );
Robert Shearman7707a762005-03-10 11:14:24 +00005614 i--;
Alexandre Julliard48243e32004-07-15 18:57:32 +00005615 }
5616}
5617
5618/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005619 * HTTP_GetResponseHeaders (internal)
5620 *
5621 * Read server response
5622 *
5623 * RETURNS
5624 *
5625 * TRUE on success
5626 * FALSE on error
5627 */
Juan Langb49b2432011-03-01 10:59:39 -08005628static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005629{
5630 INT cbreaks = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005631 WCHAR buffer[MAX_REPLY_LEN];
Ulrich Czekallac2757242000-06-11 20:04:44 +00005632 DWORD buflen = MAX_REPLY_LEN;
5633 BOOL bSuccess = FALSE;
Aric Stewartff9b9d42002-06-21 23:59:49 +00005634 INT rc = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005635 char bufferA[MAX_REPLY_LEN];
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005636 LPWSTR status_code = NULL, status_text = NULL;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005637 DWORD cchMaxRawHeaders = 1024;
Hans Leidekker911d0df2010-02-23 13:03:37 +01005638 LPWSTR lpszRawHeaders = NULL;
Eric van Beurden5caf8092009-06-04 10:52:16 -04005639 LPWSTR temp;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005640 DWORD cchRawHeaders = 0;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005641 BOOL codeHundred = FALSE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005642
Aric Stewartff9b9d42002-06-21 23:59:49 +00005643 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005644
Jacek Caban8a1df202011-05-10 09:26:43 +00005645 if(!request->netconn)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005646 goto lend;
5647
Hans Leidekker2617fb62008-02-17 20:41:56 +01005648 do {
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005649 static const WCHAR szHundred[] = {'1','0','0',0};
Hans Leidekker2617fb62008-02-17 20:41:56 +01005650 /*
Hans Leidekker2617fb62008-02-17 20:41:56 +01005651 * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
5652 */
Hans Leidekker96b639d2009-03-04 12:42:43 +01005653 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005654 if (!read_line(request, bufferA, &buflen))
Hans Leidekker2617fb62008-02-17 20:41:56 +01005655 goto lend;
Piotr Cabanee684732010-06-29 12:20:51 +02005656
5657 /* clear old response headers (eg. from a redirect response) */
5658 if (clear) {
Juan Langb49b2432011-03-01 10:59:39 -08005659 HTTP_clear_response_headers( request );
Piotr Cabanee684732010-06-29 12:20:51 +02005660 clear = FALSE;
5661 }
5662
Hans Leidekker96b639d2009-03-04 12:42:43 +01005663 rc += buflen;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005664 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005665 /* check is this a status code line? */
5666 if (!strncmpW(buffer, g_szHttp1_0, 4))
5667 {
5668 /* split the version from the status code */
5669 status_code = strchrW( buffer, ' ' );
5670 if( !status_code )
5671 goto lend;
5672 *status_code++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005673
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005674 /* split the status code from the status text */
5675 status_text = strchrW( status_code, ' ' );
5676 if( !status_text )
5677 goto lend;
5678 *status_text++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005679
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005680 TRACE("version [%s] status code [%s] status text [%s]\n",
5681 debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
Hans Leidekker2617fb62008-02-17 20:41:56 +01005682
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005683 codeHundred = (!strcmpW(status_code, szHundred));
5684 }
5685 else if (!codeHundred)
5686 {
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005687 WARN("No status line at head of response (%s)\n", debugstr_w(buffer));
5688
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005689 heap_free(request->version);
5690 heap_free(request->statusText);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005691
Juan Lang20980062011-03-01 11:18:22 -08005692 request->version = heap_strdupW(g_szHttp1_0);
5693 request->statusText = heap_strdupW(szOK);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005694
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005695 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005696 request->rawHeaders = heap_strdupW(szDefaultHeader);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005697
5698 bSuccess = TRUE;
Erik Inge Bolsø5af1a492009-09-29 21:50:12 +02005699 goto lend;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005700 }
5701 } while (codeHundred);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005702
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005703 /* Add status code */
Juan Langb49b2432011-03-01 10:59:39 -08005704 HTTP_ProcessHeader(request, szStatus, status_code,
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005705 HTTP_ADDHDR_FLAG_REPLACE);
5706
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005707 heap_free(request->version);
5708 heap_free(request->statusText);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005709
Juan Lang20980062011-03-01 11:18:22 -08005710 request->version = heap_strdupW(buffer);
5711 request->statusText = heap_strdupW(status_text);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005712
5713 /* Restore the spaces */
5714 *(status_code-1) = ' ';
5715 *(status_text-1) = ' ';
5716
Robert Shearmandee87512004-07-19 20:09:20 +00005717 /* regenerate raw headers */
Jacek Caban354a74e2011-04-21 13:39:03 +02005718 lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR));
Hans Leidekker911d0df2010-02-23 13:03:37 +01005719 if (!lpszRawHeaders) goto lend;
5720
Robert Shearmandee87512004-07-19 20:09:20 +00005721 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
Robert Shearmandee87512004-07-19 20:09:20 +00005722 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005723 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden5caf8092009-06-04 10:52:16 -04005724 if (temp == NULL) goto lend;
5725 lpszRawHeaders = temp;
Robert Shearmandee87512004-07-19 20:09:20 +00005726 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5727 cchRawHeaders += (buflen-1);
5728 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5729 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5730 lpszRawHeaders[cchRawHeaders] = '\0';
5731
Ulrich Czekallac2757242000-06-11 20:04:44 +00005732 /* Parse each response line */
5733 do
5734 {
5735 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005736 if (read_line(request, bufferA, &buflen))
Robert Shearmanb72a6822004-09-23 22:53:50 +00005737 {
5738 LPWSTR * pFieldAndValue;
5739
Francois Gougetda8b3dd2005-01-26 21:09:04 +00005740 TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
Hans Leidekker100ee0a2009-03-04 12:44:22 +01005741
5742 if (!bufferA[0]) break;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005743 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Robert Shearmandee87512004-07-19 20:09:20 +00005744
Robert Shearmanb72a6822004-09-23 22:53:50 +00005745 pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
Eric van Beurden59a21782009-06-04 10:52:59 -04005746 if (pFieldAndValue)
5747 {
5748 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
5749 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005750 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden59a21782009-06-04 10:52:59 -04005751 if (temp == NULL) goto lend;
5752 lpszRawHeaders = temp;
5753 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5754 cchRawHeaders += (buflen-1);
5755 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5756 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5757 lpszRawHeaders[cchRawHeaders] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005758
Juan Langb49b2432011-03-01 10:59:39 -08005759 HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1],
Eric van Beurden59a21782009-06-04 10:52:59 -04005760 HTTP_ADDREQ_FLAG_ADD );
Robert Shearmanb72a6822004-09-23 22:53:50 +00005761
Eric van Beurden59a21782009-06-04 10:52:59 -04005762 HTTP_FreeTokens(pFieldAndValue);
5763 }
5764 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005765 else
5766 {
5767 cbreaks++;
5768 if (cbreaks >= 2)
5769 break;
5770 }
5771 }while(1);
5772
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005773 /* make sure the response header is terminated with an empty line. Some apps really
5774 truly care about that empty line being there for some reason. Just add it to the
5775 header. */
5776 if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
5777 {
5778 cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
Jacek Caban55b27222011-04-22 12:35:05 +02005779 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005780 if (temp == NULL) goto lend;
5781 lpszRawHeaders = temp;
5782 }
5783
5784 memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
5785
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005786 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005787 request->rawHeaders = lpszRawHeaders;
Robert Shearmandee87512004-07-19 20:09:20 +00005788 TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005789 bSuccess = TRUE;
5790
5791lend:
5792
Aric Stewartff9b9d42002-06-21 23:59:49 +00005793 TRACE("<--\n");
5794 if (bSuccess)
5795 return rc;
5796 else
Hans Leidekkere3e26222008-07-19 19:52:47 +02005797 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005798 heap_free(lpszRawHeaders);
Robert Shearman0e7c41e2005-11-28 11:55:16 +01005799 return 0;
Hans Leidekkere3e26222008-07-19 19:52:47 +02005800 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005801}
5802
Ulrich Czekallac2757242000-06-11 20:04:44 +00005803/***********************************************************************
5804 * HTTP_InterpretHttpHeader (internal)
5805 *
5806 * Parse server response
5807 *
5808 * RETURNS
5809 *
Robert Shearmanb72a6822004-09-23 22:53:50 +00005810 * Pointer to array of field, value, NULL on success.
5811 * NULL on error.
Ulrich Czekallac2757242000-06-11 20:04:44 +00005812 */
Jacek Caban02708c62005-10-26 10:07:58 +00005813static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005814{
Robert Shearmanb72a6822004-09-23 22:53:50 +00005815 LPWSTR * pTokenPair;
5816 LPWSTR pszColon;
5817 INT len;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005818
Jacek Caban354a74e2011-04-21 13:39:03 +02005819 pTokenPair = heap_alloc_zero(sizeof(*pTokenPair)*3);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005820
Robert Shearmanb72a6822004-09-23 22:53:50 +00005821 pszColon = strchrW(buffer, ':');
5822 /* must have two tokens */
5823 if (!pszColon)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005824 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005825 HTTP_FreeTokens(pTokenPair);
Robert Shearman7707a762005-03-10 11:14:24 +00005826 if (buffer[0])
5827 TRACE("No ':' in line: %s\n", debugstr_w(buffer));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005828 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005829 }
5830
Jacek Caban354a74e2011-04-21 13:39:03 +02005831 pTokenPair[0] = heap_alloc((pszColon - buffer + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005832 if (!pTokenPair[0])
Ulrich Czekallac2757242000-06-11 20:04:44 +00005833 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005834 HTTP_FreeTokens(pTokenPair);
5835 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005836 }
Robert Shearmanb72a6822004-09-23 22:53:50 +00005837 memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
5838 pTokenPair[0][pszColon - buffer] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005839
Robert Shearmanb72a6822004-09-23 22:53:50 +00005840 /* skip colon */
5841 pszColon++;
5842 len = strlenW(pszColon);
Jacek Caban354a74e2011-04-21 13:39:03 +02005843 pTokenPair[1] = heap_alloc((len + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005844 if (!pTokenPair[1])
5845 {
5846 HTTP_FreeTokens(pTokenPair);
5847 return NULL;
5848 }
5849 memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
5850
5851 strip_spaces(pTokenPair[0]);
5852 strip_spaces(pTokenPair[1]);
5853
5854 TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
5855 return pTokenPair;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005856}
5857
Ulrich Czekallac2757242000-06-11 20:04:44 +00005858/***********************************************************************
5859 * HTTP_ProcessHeader (internal)
5860 *
5861 * Stuff header into header tables according to <dwModifier>
5862 *
5863 */
5864
Juan Langa1ab4a72007-11-07 14:45:06 -08005865#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 +00005866
Juan Langb49b2432011-03-01 10:59:39 -08005867static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005868{
Mike McCormacka4e902c2004-03-30 04:36:09 +00005869 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01005870 INT index = -1;
Aric Stewart1e946d32005-12-13 17:07:41 +01005871 BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
Jacek Cabane9749652009-11-30 20:01:00 +01005872 DWORD res = ERROR_HTTP_INVALID_HEADER;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005873
Hans Leidekkercd2c4582006-10-05 13:18:56 +02005874 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005875
Aric Stewart1e946d32005-12-13 17:07:41 +01005876 /* REPLACE wins out over ADD */
5877 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5878 dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
5879
5880 if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
5881 index = -1;
5882 else
Juan Langb49b2432011-03-01 10:59:39 -08005883 index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only);
Aric Stewart1e946d32005-12-13 17:07:41 +01005884
5885 if (index >= 0)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005886 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005887 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
Jacek Cabane9749652009-11-30 20:01:00 +01005888 return ERROR_HTTP_INVALID_HEADER;
Juan Lang20980062011-03-01 11:18:22 -08005889 lphttpHdr = &request->custHeaders[index];
Aric Stewart1e946d32005-12-13 17:07:41 +01005890 }
5891 else if (value)
5892 {
5893 HTTPHEADERW hdr;
5894
5895 hdr.lpszField = (LPWSTR)field;
5896 hdr.lpszValue = (LPWSTR)value;
5897 hdr.wFlags = hdr.wCount = 0;
5898
5899 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5900 hdr.wFlags |= HDR_ISREQUEST;
5901
Juan Langb49b2432011-03-01 10:59:39 -08005902 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewart1e946d32005-12-13 17:07:41 +01005903 }
Rob Shearman7b002a32007-01-12 19:16:49 -06005904 /* no value to delete */
Jacek Cabane9749652009-11-30 20:01:00 +01005905 else return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01005906
5907 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5908 lphttpHdr->wFlags |= HDR_ISREQUEST;
5909 else
5910 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
5911
5912 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5913 {
Juan Langb49b2432011-03-01 10:59:39 -08005914 HTTP_DeleteCustomHeader( request, index );
Aric Stewart1e946d32005-12-13 17:07:41 +01005915
5916 if (value)
Aric Stewartff9b9d42002-06-21 23:59:49 +00005917 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00005918 HTTPHEADERW hdr;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005919
Mike McCormacka4e902c2004-03-30 04:36:09 +00005920 hdr.lpszField = (LPWSTR)field;
5921 hdr.lpszValue = (LPWSTR)value;
Aric Stewartff9b9d42002-06-21 23:59:49 +00005922 hdr.wFlags = hdr.wCount = 0;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005923
5924 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5925 hdr.wFlags |= HDR_ISREQUEST;
5926
Juan Langb49b2432011-03-01 10:59:39 -08005927 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewartff9b9d42002-06-21 23:59:49 +00005928 }
Aric Stewart1e946d32005-12-13 17:07:41 +01005929
Jacek Cabane9749652009-11-30 20:01:00 +01005930 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005931 }
Juan Langa1ab4a72007-11-07 14:45:06 -08005932 else if (dwModifier & COALESCEFLAGS)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005933 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005934 LPWSTR lpsztmp;
5935 WCHAR ch = 0;
5936 INT len = 0;
5937 INT origlen = strlenW(lphttpHdr->lpszValue);
5938 INT valuelen = strlenW(value);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005939
Aric Stewart1e946d32005-12-13 17:07:41 +01005940 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005941 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005942 ch = ',';
5943 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
5944 }
5945 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
5946 {
5947 ch = ';';
5948 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005949 }
5950
Aric Stewart1e946d32005-12-13 17:07:41 +01005951 len = origlen + valuelen + ((ch > 0) ? 2 : 0);
5952
Jacek Caban55b27222011-04-22 12:35:05 +02005953 lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
Aric Stewart1e946d32005-12-13 17:07:41 +01005954 if (lpsztmp)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005955 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005956 lphttpHdr->lpszValue = lpsztmp;
5957 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
5958 if (ch > 0)
5959 {
5960 lphttpHdr->lpszValue[origlen] = ch;
5961 origlen++;
5962 lphttpHdr->lpszValue[origlen] = ' ';
5963 origlen++;
5964 }
5965
5966 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
5967 lphttpHdr->lpszValue[len] = '\0';
Jacek Cabane9749652009-11-30 20:01:00 +01005968 res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005969 }
5970 else
5971 {
Jacek Caban55b27222011-04-22 12:35:05 +02005972 WARN("heap_realloc (%d bytes) failed\n",len+1);
Jacek Cabane9749652009-11-30 20:01:00 +01005973 res = ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005974 }
5975 }
Jacek Cabane9749652009-11-30 20:01:00 +01005976 TRACE("<-- %d\n", res);
5977 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005978}
5979
Ulrich Czekallac2757242000-06-11 20:04:44 +00005980/***********************************************************************
5981 * HTTP_GetCustomHeaderIndex (internal)
5982 *
5983 * Return index of custom header from header array
5984 *
5985 */
Juan Langb49b2432011-03-01 10:59:39 -08005986static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField,
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005987 int requested_index, BOOL request_only)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005988{
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005989 DWORD index;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005990
Juan Lang3cd54552009-12-04 14:37:46 -08005991 TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005992
Juan Langb49b2432011-03-01 10:59:39 -08005993 for (index = 0; index < request->nCustHeaders; index++)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005994 {
Juan Lang20980062011-03-01 11:18:22 -08005995 if (strcmpiW(request->custHeaders[index].lpszField, lpszField))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005996 continue;
5997
Juan Lang20980062011-03-01 11:18:22 -08005998 if (request_only && !(request->custHeaders[index].wFlags & HDR_ISREQUEST))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09005999 continue;
6000
Juan Lang20980062011-03-01 11:18:22 -08006001 if (!request_only && (request->custHeaders[index].wFlags & HDR_ISREQUEST))
Aric Stewart1e946d32005-12-13 17:07:41 +01006002 continue;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006003
Aric Stewart1e946d32005-12-13 17:07:41 +01006004 if (requested_index == 0)
Mike McCormack92ddc1c2006-03-30 18:20:04 +09006005 break;
6006 requested_index --;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006007 }
6008
Juan Langb49b2432011-03-01 10:59:39 -08006009 if (index >= request->nCustHeaders)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006010 index = -1;
6011
Hans Leidekkercd2c4582006-10-05 13:18:56 +02006012 TRACE("Return: %d\n", index);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006013 return index;
6014}
6015
6016
6017/***********************************************************************
6018 * HTTP_InsertCustomHeader (internal)
6019 *
6020 * Insert header into array
6021 *
6022 */
Juan Langb49b2432011-03-01 10:59:39 -08006023static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHdr)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006024{
6025 INT count;
Mike McCormacka4e902c2004-03-30 04:36:09 +00006026 LPHTTPHEADERW lph = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006027
Mike McCormacka4e902c2004-03-30 04:36:09 +00006028 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
Juan Langb49b2432011-03-01 10:59:39 -08006029 count = request->nCustHeaders + 1;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006030 if (count > 1)
Jacek Caban55b27222011-04-22 12:35:05 +02006031 lph = heap_realloc_zero(request->custHeaders, sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006032 else
Jacek Caban354a74e2011-04-21 13:39:03 +02006033 lph = heap_alloc_zero(sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006034
Jacek Cabane9749652009-11-30 20:01:00 +01006035 if (!lph)
6036 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006037
Juan Lang20980062011-03-01 11:18:22 -08006038 request->custHeaders = lph;
6039 request->custHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
6040 request->custHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
6041 request->custHeaders[count-1].wFlags = lpHdr->wFlags;
6042 request->custHeaders[count-1].wCount= lpHdr->wCount;
Juan Langb49b2432011-03-01 10:59:39 -08006043 request->nCustHeaders++;
Jacek Cabane9749652009-11-30 20:01:00 +01006044
6045 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006046}
6047
6048
6049/***********************************************************************
6050 * HTTP_DeleteCustomHeader (internal)
6051 *
6052 * Delete header from array
Mike McCormacka1c16d22003-07-22 03:17:52 +00006053 * If this function is called, the indexs may change.
Ulrich Czekallac2757242000-06-11 20:04:44 +00006054 */
Juan Langb49b2432011-03-01 10:59:39 -08006055static BOOL HTTP_DeleteCustomHeader(http_request_t *request, DWORD index)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006056{
Juan Langb49b2432011-03-01 10:59:39 -08006057 if( request->nCustHeaders <= 0 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00006058 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08006059 if( index >= request->nCustHeaders )
Mike McCormacka1c16d22003-07-22 03:17:52 +00006060 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08006061 request->nCustHeaders--;
Mike McCormacka1c16d22003-07-22 03:17:52 +00006062
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02006063 heap_free(request->custHeaders[index].lpszField);
6064 heap_free(request->custHeaders[index].lpszValue);
Rob Shearman62e0a8c2008-06-20 10:14:38 +01006065
Juan Lang20980062011-03-01 11:18:22 -08006066 memmove( &request->custHeaders[index], &request->custHeaders[index+1],
Juan Langb49b2432011-03-01 10:59:39 -08006067 (request->nCustHeaders - index)* sizeof(HTTPHEADERW) );
Juan Lang20980062011-03-01 11:18:22 -08006068 memset( &request->custHeaders[request->nCustHeaders], 0, sizeof(HTTPHEADERW) );
Mike McCormacka1c16d22003-07-22 03:17:52 +00006069
6070 return TRUE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006071}
Alberto Massarib09eef22002-11-13 04:08:26 +00006072
Aric Stewartc8dfc022007-07-26 08:59:00 -05006073
6074/***********************************************************************
6075 * HTTP_VerifyValidHeader (internal)
6076 *
6077 * Verify the given header is not invalid for the given http request
6078 *
6079 */
Juan Langb49b2432011-03-01 10:59:39 -08006080static BOOL HTTP_VerifyValidHeader(http_request_t *request, LPCWSTR field)
Aric Stewartc8dfc022007-07-26 08:59:00 -05006081{
Aric Stewartc8dfc022007-07-26 08:59:00 -05006082 /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
Juan Lang20980062011-03-01 11:18:22 -08006083 if (!strcmpW(request->version, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
Jacek Cabane9749652009-11-30 20:01:00 +01006084 return ERROR_HTTP_INVALID_HEADER;
Aric Stewartc8dfc022007-07-26 08:59:00 -05006085
Jacek Cabane9749652009-11-30 20:01:00 +01006086 return ERROR_SUCCESS;
Aric Stewartc8dfc022007-07-26 08:59:00 -05006087}
6088
Alberto Massarib09eef22002-11-13 04:08:26 +00006089/***********************************************************************
6090 * IsHostInProxyBypassList (@)
6091 *
6092 * Undocumented
6093 *
6094 */
6095BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
6096{
Hans Leidekkercd2c4582006-10-05 13:18:56 +02006097 FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
Alberto Massarib09eef22002-11-13 04:08:26 +00006098 return FALSE;
6099}
Austin English1c7d3492010-11-25 06:59:25 -08006100
6101/***********************************************************************
6102 * InternetShowSecurityInfoByURLA (@)
6103 */
6104BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window)
6105{
6106 FIXME("stub: %s %p\n", url, window);
6107 return FALSE;
6108}
6109
6110/***********************************************************************
6111 * InternetShowSecurityInfoByURLW (@)
6112 */
6113BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window)
6114{
6115 FIXME("stub: %s %p\n", debugstr_w(url), window);
6116 return FALSE;
6117}
André Hentscheladea3c52011-10-29 15:08:08 +02006118
6119/***********************************************************************
6120 * ShowX509EncodedCertificate (@)
6121 */
6122DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len)
6123{
Juan Lang044f6452011-10-31 12:55:15 -07006124 PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING,
6125 cert, len);
6126 DWORD ret;
6127
6128 if (certContext)
6129 {
6130 CRYPTUI_VIEWCERTIFICATE_STRUCTW view;
6131
6132 memset(&view, 0, sizeof(view));
6133 view.hwndParent = parent;
6134 view.pCertContext = certContext;
6135 if (CryptUIDlgViewCertificateW(&view, NULL))
6136 ret = ERROR_SUCCESS;
6137 else
6138 ret = GetLastError();
6139 CertFreeCertificateContext(certContext);
6140 }
6141 else
6142 ret = GetLastError();
6143 return ret;
André Hentscheladea3c52011-10-29 15:08:08 +02006144}