blob: 28f82a365325ceb89f1423276d51625abb1beda9 [file] [log] [blame]
Vincent Béron9a624912002-05-31 23:06:46 +00001/*
Francois Gougetfac36c52012-05-15 10:15:32 +02002 * Wininet - HTTP Implementation
Ulrich Czekallac2757242000-06-11 20:04:44 +00003 *
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 };
Alexander Morozovef95a792012-05-23 17:49:24 +0400101static const WCHAR szContent_Disposition[] = { 'C','o','n','t','e','n','t','-','D','i','s','p','o','s','i','t','i','o','n',0 };
Jacek Caban83170892009-05-29 23:34:14 +0200102static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
103static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
104static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
105static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
106static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
107static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
108static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
109static 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 };
110static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
111static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
112static const WCHAR szDate[] = { 'D','a','t','e',0 };
113static const WCHAR szFrom[] = { 'F','r','o','m',0 };
114static const WCHAR szETag[] = { 'E','T','a','g',0 };
115static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
116static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
117static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
118static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
119static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
120static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
121static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
122static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
123static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
124static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
125static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
126static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
127static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
128static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
129static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
130static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
131static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
132static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
133static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
134static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
135static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
136static 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 };
137static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
138static const WCHAR szURI[] = { 'U','R','I',0 };
139static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
140static const WCHAR szVary[] = { 'V','a','r','y',0 };
141static const WCHAR szVia[] = { 'V','i','a',0 };
142static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
143static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
144
Jacek Caban83170892009-05-29 23:34:14 +0200145#define HTTP_REFERER szReferer
146#define HTTP_ACCEPT szAccept
147#define HTTP_USERAGENT szUser_Agent
Ulrich Czekallac2757242000-06-11 20:04:44 +0000148
149#define HTTP_ADDHDR_FLAG_ADD 0x20000000
150#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
151#define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
152#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
153#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
154#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
155#define HTTP_ADDHDR_FLAG_REQ 0x02000000
156
Jacek Caban8a1df202011-05-10 09:26:43 +0000157#define COLLECT_TIME 60000
158
Rob Shearman4b507682007-05-21 14:26:26 +0100159#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
160
161struct HttpAuthInfo
162{
163 LPWSTR scheme;
164 CredHandle cred;
165 CtxtHandle ctx;
166 TimeStamp exp;
167 ULONG attr;
Rob Shearman0be05ab2008-03-10 16:41:44 +0000168 ULONG max_token;
Rob Shearman4b507682007-05-21 14:26:26 +0100169 void *auth_data;
170 unsigned int auth_data_len;
171 BOOL finished; /* finished authenticating */
172};
Ulrich Czekallac2757242000-06-11 20:04:44 +0000173
Jacek Caban11ca05f2009-05-29 23:35:13 +0200174
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200175typedef struct _basicAuthorizationData
Aric Stewartfc508932009-10-12 14:24:18 -0500176{
177 struct list entry;
178
Juan Lang2c6ad542011-03-01 10:30:46 -0800179 LPWSTR host;
180 LPWSTR realm;
181 LPSTR authorization;
182 UINT authorizationLen;
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200183} basicAuthorizationData;
184
185typedef struct _authorizationData
186{
187 struct list entry;
188
189 LPWSTR host;
190 LPWSTR scheme;
191 LPWSTR domain;
192 UINT domain_len;
193 LPWSTR user;
194 UINT user_len;
195 LPWSTR password;
196 UINT password_len;
Aric Stewartfc508932009-10-12 14:24:18 -0500197} authorizationData;
198
199static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
Piotr Cabanc398e6f2010-07-17 14:08:44 +0200200static struct list authorizationCache = LIST_INIT(authorizationCache);
Aric Stewartfc508932009-10-12 14:24:18 -0500201
202static CRITICAL_SECTION authcache_cs;
203static CRITICAL_SECTION_DEBUG critsect_debug =
204{
205 0, 0, &authcache_cs,
206 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
207 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
208};
209static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
210
Jacek Caban34abacd2009-07-13 01:41:50 +0200211static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
Jacek Cabane9749652009-11-30 20:01:00 +0100212static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
Jacek Caban02708c62005-10-26 10:07:58 +0000213static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
Jacek Cabane9749652009-11-30 20:01:00 +0100214static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
Jacek Caban34abacd2009-07-13 01:41:50 +0200215static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
216static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
Aric Stewartbe918f42005-11-21 15:17:55 +0000217static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
Jacek Caban9823c232009-12-14 02:27:29 +0100218static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
Jacek Caban34abacd2009-07-13 01:41:50 +0200219static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
Rob Shearman4b507682007-05-21 14:26:26 +0100220static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
Jacek Caban34abacd2009-07-13 01:41:50 +0200221static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
Jacek Cabanc4001172012-07-02 17:15:04 +0200222static BOOL drain_content(http_request_t*,BOOL);
Jacek Caban8a1df202011-05-10 09:26:43 +0000223
224static CRITICAL_SECTION connection_pool_cs;
225static CRITICAL_SECTION_DEBUG connection_pool_debug =
226{
227 0, 0, &connection_pool_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
230};
231static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
232
233static struct list connection_pool = LIST_INIT(connection_pool);
234static BOOL collector_running;
235
236void server_addref(server_t *server)
237{
238 InterlockedIncrement(&server->ref);
239}
240
241void server_release(server_t *server)
242{
243 if(InterlockedDecrement(&server->ref))
244 return;
245
Jacek Caban95c1b742012-05-25 16:35:32 +0200246 list_remove(&server->entry);
247
Jacek Caban6c764fb2012-06-11 10:22:38 +0200248 if(server->cert_chain)
249 CertFreeCertificateChain(server->cert_chain);
Jacek Caban95c1b742012-05-25 16:35:32 +0200250 heap_free(server->name);
251 heap_free(server);
Jacek Caban8a1df202011-05-10 09:26:43 +0000252}
253
Jacek Caban6c764fb2012-06-11 10:22:38 +0200254server_t *get_server(const WCHAR *name, INTERNET_PORT port, BOOL do_create)
Jacek Caban8a1df202011-05-10 09:26:43 +0000255{
256 server_t *iter, *server = NULL;
257
258 EnterCriticalSection(&connection_pool_cs);
259
260 LIST_FOR_EACH_ENTRY(iter, &connection_pool, server_t, entry) {
261 if(iter->port == port && !strcmpW(iter->name, name)) {
262 server = iter;
263 server_addref(server);
264 break;
265 }
266 }
267
Jacek Caban6c764fb2012-06-11 10:22:38 +0200268 if(!server && do_create) {
269 server = heap_alloc_zero(sizeof(*server));
Jacek Caban8a1df202011-05-10 09:26:43 +0000270 if(server) {
Jacek Caban95c1b742012-05-25 16:35:32 +0200271 server->ref = 2; /* list reference and return */
Jacek Caban8a1df202011-05-10 09:26:43 +0000272 server->port = port;
273 list_init(&server->conn_pool);
274 server->name = heap_strdupW(name);
275 if(server->name) {
276 list_add_head(&connection_pool, &server->entry);
277 }else {
278 heap_free(server);
279 server = NULL;
280 }
281 }
282 }
283
284 LeaveCriticalSection(&connection_pool_cs);
285
286 return server;
287}
288
Jacek Cabanf8f22732012-05-25 16:35:48 +0200289BOOL collect_connections(collect_type_t collect_type)
Jacek Caban8a1df202011-05-10 09:26:43 +0000290{
291 netconn_t *netconn, *netconn_safe;
292 server_t *server, *server_safe;
293 BOOL remaining = FALSE;
294 DWORD64 now;
295
296 now = GetTickCount64();
297
298 LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) {
299 LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
Jacek Cabanf8f22732012-05-25 16:35:48 +0200300 if(collect_type > COLLECT_TIMEOUT || netconn->keep_until < now) {
Jacek Caban8a1df202011-05-10 09:26:43 +0000301 TRACE("freeing %p\n", netconn);
302 list_remove(&netconn->pool_entry);
303 free_netconn(netconn);
304 }else {
305 remaining = TRUE;
306 }
307 }
308
Jacek Cabanf8f22732012-05-25 16:35:48 +0200309 if(collect_type == COLLECT_CLEANUP) {
Jacek Caban95c1b742012-05-25 16:35:32 +0200310 list_remove(&server->entry);
311 list_init(&server->entry);
312 server_release(server);
Jacek Caban8a1df202011-05-10 09:26:43 +0000313 }
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
Jacek Cabanf8f22732012-05-25 16:35:48 +0200329 remaining_conns = collect_connections(COLLECT_TIMEOUT);
Jacek Caban8a1df202011-05-10 09:26:43 +0000330 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,
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001184 first ? request->server->name : 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
Francois Gougetfac36c52012-05-15 10:15:32 +02001291 * invalid HTTP header which is rejected by some servers so we probably
Francois Gougetabfa73b2008-02-19 00:18:02 +01001292 * 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;
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001700 server_t *new_server;
Juan Langde6a0a82010-03-13 09:36:46 -08001701 static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01001702 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1703 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
Mike McCormacka1c16d22003-07-22 03:17:52 +00001704
1705 memset( &UrlComponents, 0, sizeof UrlComponents );
1706 UrlComponents.dwStructSize = sizeof UrlComponents;
1707 UrlComponents.lpszHostName = buf;
André Hentschel0fda1352011-08-22 21:30:55 +02001708 UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001709
Juan Lang72431562011-03-01 11:00:49 -08001710 if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen))
Juan Langde6a0a82010-03-13 09:36:46 -08001711 return FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00001712 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
Juan Langde6a0a82010-03-13 09:36:46 -08001713 protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1714 sprintfW(proxy, szFormat, protoProxy);
Uwe Bonnes599c4522003-12-15 19:47:31 +00001715 else
Juan Langde6a0a82010-03-13 09:36:46 -08001716 strcpyW(proxy, protoProxy);
Mike McCormacka4e902c2004-03-30 04:36:09 +00001717 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
Mike McCormacka1c16d22003-07-22 03:17:52 +00001718 return FALSE;
1719 if( UrlComponents.dwHostNameLength == 0 )
1720 return FALSE;
1721
Juan Lang20980062011-03-01 11:18:22 -08001722 if( !request->path )
1723 request->path = szNul;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001724
1725 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1726 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1727
Jacek Caban6c764fb2012-06-11 10:22:38 +02001728 new_server = get_server(UrlComponents.lpszHostName, UrlComponents.nPort, TRUE);
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001729 if(!new_server)
1730 return FALSE;
Mike McCormacka1c16d22003-07-22 03:17:52 +00001731
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001732 server_release(request->server);
1733 request->server = new_server;
1734
1735 TRACE("proxy server=%s port=%d\n", debugstr_w(new_server->name), new_server->port);
Mike McCormacka1c16d22003-07-22 03:17:52 +00001736 return TRUE;
1737}
1738
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001739static DWORD HTTP_ResolveName(http_request_t *request)
Rob Shearman72575a02006-12-07 00:52:50 +00001740{
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001741 server_t *server = request->server;
Jacek Caban8a1df202011-05-10 09:26:43 +00001742 socklen_t addr_len;
Alexandre Julliard3521e1b2012-06-15 17:58:23 +02001743 void *addr;
Rob Shearman72575a02006-12-07 00:52:50 +00001744
Jacek Caban8a1df202011-05-10 09:26:43 +00001745 if(server->addr_len)
1746 return ERROR_SUCCESS;
1747
Juan Langb49b2432011-03-01 10:59:39 -08001748 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001749 INTERNET_STATUS_RESOLVING_NAME,
Jacek Caban8a1df202011-05-10 09:26:43 +00001750 server->name,
1751 (strlenW(server->name)+1) * sizeof(WCHAR));
Rob Shearman72575a02006-12-07 00:52:50 +00001752
Jacek Caban8a1df202011-05-10 09:26:43 +00001753 addr_len = sizeof(server->addr);
1754 if (!GetAddress(server->name, server->port, (struct sockaddr *)&server->addr, &addr_len))
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001755 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Rob Shearman72575a02006-12-07 00:52:50 +00001756
Jacek Caban8a1df202011-05-10 09:26:43 +00001757 switch(server->addr.ss_family) {
Juan Lang058e9182009-07-09 11:36:00 -07001758 case AF_INET:
Jacek Caban8a1df202011-05-10 09:26:43 +00001759 addr = &((struct sockaddr_in *)&server->addr)->sin_addr;
Juan Lang058e9182009-07-09 11:36:00 -07001760 break;
Juan Lang481c9b82009-07-09 11:42:25 -07001761 case AF_INET6:
Jacek Caban8a1df202011-05-10 09:26:43 +00001762 addr = &((struct sockaddr_in6 *)&server->addr)->sin6_addr;
Juan Lang481c9b82009-07-09 11:42:25 -07001763 break;
Juan Lang058e9182009-07-09 11:36:00 -07001764 default:
Jacek Caban8a1df202011-05-10 09:26:43 +00001765 WARN("unsupported family %d\n", server->addr.ss_family);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001766 return ERROR_INTERNET_NAME_NOT_RESOLVED;
Juan Lang058e9182009-07-09 11:36:00 -07001767 }
Jacek Caban8a1df202011-05-10 09:26:43 +00001768
1769 server->addr_len = addr_len;
1770 inet_ntop(server->addr.ss_family, addr, server->addr_str, sizeof(server->addr_str));
Juan Langb49b2432011-03-01 10:59:39 -08001771 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Rob Shearman72575a02006-12-07 00:52:50 +00001772 INTERNET_STATUS_NAME_RESOLVED,
Jacek Caban8a1df202011-05-10 09:26:43 +00001773 server->addr_str, strlen(server->addr_str)+1);
Hans Leidekker2f994502008-05-31 21:46:07 +02001774
Jacek Caban8a1df202011-05-10 09:26:43 +00001775 TRACE("resolved %s to %s\n", debugstr_w(server->name), server->addr_str);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01001776 return ERROR_SUCCESS;
Rob Shearman72575a02006-12-07 00:52:50 +00001777}
1778
Piotr Caban75481bd2010-07-24 17:56:41 +02001779static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1780{
Juan Langb9c348a2011-03-02 08:28:39 -08001781 static const WCHAR http[] = { 'h','t','t','p',':','/','/',0 };
1782 static const WCHAR https[] = { 'h','t','t','p','s',':','/','/',0 };
1783 static const WCHAR slash[] = { '/',0 };
Piotr Caban75481bd2010-07-24 17:56:41 +02001784 LPHTTPHEADERW host_header;
Juan Langb9c348a2011-03-02 08:28:39 -08001785 LPCWSTR scheme;
Piotr Caban75481bd2010-07-24 17:56:41 +02001786
1787 host_header = HTTP_GetHeader(req, hostW);
1788 if(!host_header)
1789 return FALSE;
1790
Juan Langb9c348a2011-03-02 08:28:39 -08001791 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1792 scheme = https;
1793 else
1794 scheme = http;
1795 strcpyW(buf, scheme);
1796 strcatW(buf, host_header->lpszValue);
1797 if (req->path[0] != '/')
1798 strcatW(buf, slash);
1799 strcatW(buf, req->path);
Piotr Caban75481bd2010-07-24 17:56:41 +02001800 return TRUE;
1801}
1802
Jacek Caban5a535d62008-02-26 20:20:41 +01001803
1804/***********************************************************************
1805 * HTTPREQ_Destroy (internal)
1806 *
1807 * Deallocate request handle
1808 *
1809 */
Jacek Caban44d633a2009-07-07 21:46:09 +02001810static void HTTPREQ_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01001811{
Juan Langb49b2432011-03-01 10:59:39 -08001812 http_request_t *request = (http_request_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01001813 DWORD i;
1814
1815 TRACE("\n");
1816
Juan Langb49b2432011-03-01 10:59:39 -08001817 if(request->hCacheFile) {
Piotr Caban75481bd2010-07-24 17:56:41 +02001818 WCHAR url[INTERNET_MAX_URL_LENGTH];
Piotr Caban75481bd2010-07-24 17:56:41 +02001819
Juan Langb49b2432011-03-01 10:59:39 -08001820 CloseHandle(request->hCacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001821
Juan Langb49b2432011-03-01 10:59:39 -08001822 if(HTTP_GetRequestURL(request, url)) {
Juan Lang011b26b2011-03-03 15:33:40 -08001823 DWORD headersLen;
1824
1825 headersLen = request->rawHeaders ? strlenW(request->rawHeaders) : 0;
Juan Lang28e92292011-03-04 11:43:54 -08001826 CommitUrlCacheEntryW(url, request->cacheFile, request->expires,
Juan Lang011b26b2011-03-03 15:33:40 -08001827 request->last_modified, NORMAL_CACHE_ENTRY,
1828 request->rawHeaders, headersLen, NULL, 0);
Piotr Caban75481bd2010-07-24 17:56:41 +02001829 }
1830 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001831 heap_free(request->cacheFile);
Jacek Caban5a535d62008-02-26 20:20:41 +01001832
Francois Gouget17929b92011-11-16 16:29:44 +01001833 request->read_section.DebugInfo->Spare[0] = 0;
Juan Langb49b2432011-03-01 10:59:39 -08001834 DeleteCriticalSection( &request->read_section );
Juan Lang20980062011-03-01 11:18:22 -08001835 WININET_Release(&request->session->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01001836
Juan Lang20980062011-03-01 11:18:22 -08001837 destroy_authinfo(request->authInfo);
1838 destroy_authinfo(request->proxyAuthInfo);
Hans Leidekkerd5dca632008-10-17 13:46:25 +02001839
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02001840 if(request->server)
1841 server_release(request->server);
1842
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001843 heap_free(request->path);
1844 heap_free(request->verb);
1845 heap_free(request->rawHeaders);
1846 heap_free(request->version);
1847 heap_free(request->statusText);
Jacek Caban5a535d62008-02-26 20:20:41 +01001848
Juan Langb49b2432011-03-01 10:59:39 -08001849 for (i = 0; i < request->nCustHeaders; i++)
Jacek Caban5a535d62008-02-26 20:20:41 +01001850 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001851 heap_free(request->custHeaders[i].lpszField);
1852 heap_free(request->custHeaders[i].lpszValue);
Jacek Caban5a535d62008-02-26 20:20:41 +01001853 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02001854 destroy_data_stream(request->data_stream);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02001855 heap_free(request->custHeaders);
Jacek Caban5a535d62008-02-26 20:20:41 +01001856}
1857
Jacek Caban8a1df202011-05-10 09:26:43 +00001858static void http_release_netconn(http_request_t *req, BOOL reuse)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001859{
Jacek Caban8a1df202011-05-10 09:26:43 +00001860 TRACE("%p %p\n",req, req->netconn);
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001861
Jacek Caban8a1df202011-05-10 09:26:43 +00001862 if(!req->netconn)
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001863 return;
1864
Jacek Caban8a1df202011-05-10 09:26:43 +00001865 if(reuse && req->netconn->keep_alive) {
1866 BOOL run_collector;
1867
1868 EnterCriticalSection(&connection_pool_cs);
1869
1870 list_add_head(&req->netconn->server->conn_pool, &req->netconn->pool_entry);
1871 req->netconn->keep_until = GetTickCount64() + COLLECT_TIME;
1872 req->netconn = NULL;
1873
1874 run_collector = !collector_running;
1875 collector_running = TRUE;
1876
1877 LeaveCriticalSection(&connection_pool_cs);
1878
1879 if(run_collector) {
1880 HANDLE thread = NULL;
1881 HMODULE module;
1882
1883 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)WININET_hModule, &module);
1884 if(module)
1885 thread = CreateThread(NULL, 0, collect_connections_proc, NULL, 0, NULL);
1886 if(!thread) {
1887 EnterCriticalSection(&connection_pool_cs);
1888 collector_running = FALSE;
1889 LeaveCriticalSection(&connection_pool_cs);
1890
1891 if(module)
1892 FreeLibrary(module);
1893 }
Pierre Schweitzer85e2b4d2011-12-30 21:55:42 +01001894 else
1895 CloseHandle(thread);
Jacek Caban8a1df202011-05-10 09:26:43 +00001896 }
1897 return;
1898 }
1899
1900 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001901 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1902
Jacek Caban8a1df202011-05-10 09:26:43 +00001903 free_netconn(req->netconn);
1904 req->netconn = NULL;
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001905
Jacek Caban8a1df202011-05-10 09:26:43 +00001906 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01001907 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1908}
1909
Juan Langb49b2432011-03-01 10:59:39 -08001910static BOOL HTTP_KeepAlive(http_request_t *request)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001911{
1912 WCHAR szVersion[10];
1913 WCHAR szConnectionResponse[20];
1914 DWORD dwBufferSize = sizeof(szVersion);
1915 BOOL keepalive = FALSE;
1916
1917 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1918 * the connection is keep-alive by default */
Juan Langb49b2432011-03-01 10:59:39 -08001919 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS
Jacek Caban9823c232009-12-14 02:27:29 +01001920 && !strcmpiW(szVersion, g_szHttp1_1))
Juan Lang6ae6ea92009-08-10 15:20:45 -07001921 {
1922 keepalive = TRUE;
1923 }
1924
1925 dwBufferSize = sizeof(szConnectionResponse);
Juan Langb49b2432011-03-01 10:59:39 -08001926 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
1927 || HTTP_HttpQueryInfoW(request, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001928 {
1929 keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1930 }
1931
1932 return keepalive;
1933}
1934
Jacek Caban8a1df202011-05-10 09:26:43 +00001935static void HTTPREQ_CloseConnection(object_header_t *hdr)
1936{
1937 http_request_t *req = (http_request_t*)hdr;
1938
Jacek Cabanc4001172012-07-02 17:15:04 +02001939 http_release_netconn(req, drain_content(req, FALSE));
Jacek Caban8a1df202011-05-10 09:26:43 +00001940}
1941
Jacek Caban44d633a2009-07-07 21:46:09 +02001942static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01001943{
Jacek Caban34abacd2009-07-13 01:41:50 +02001944 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e010d82008-03-12 02:23:48 +01001945
Jacek Cabane2933c22008-03-12 02:23:20 +01001946 switch(option) {
Juan Lang6ae6ea92009-08-10 15:20:45 -07001947 case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1948 {
Juan Lang20980062011-03-01 11:18:22 -08001949 http_session_t *session = req->session;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001950 INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1951
1952 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1953
1954 if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1955 return ERROR_INSUFFICIENT_BUFFER;
1956 *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1957 /* FIXME: can't get a SOCKET from our connection since we don't use
1958 * winsock
1959 */
1960 info->Socket = 0;
1961 /* FIXME: get source port from req->netConnection */
1962 info->SourcePort = 0;
Juan Lang8e050392011-03-01 11:02:14 -08001963 info->DestPort = session->hostPort;
Juan Lang6ae6ea92009-08-10 15:20:45 -07001964 info->Flags = 0;
1965 if (HTTP_KeepAlive(req))
1966 info->Flags |= IDSI_FLAG_KEEP_ALIVE;
Juan Lang8e050392011-03-01 11:02:14 -08001967 if (session->appInfo->proxy && session->appInfo->proxy[0] != 0)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001968 info->Flags |= IDSI_FLAG_PROXY;
Jacek Caban8a1df202011-05-10 09:26:43 +00001969 if (req->netconn->useSSL)
Juan Lang6ae6ea92009-08-10 15:20:45 -07001970 info->Flags |= IDSI_FLAG_SECURE;
1971
1972 return ERROR_SUCCESS;
1973 }
1974
Jacek Caban01336832012-06-04 18:01:19 +02001975 case 98:
1976 TRACE("Queried undocumented option 98, forwarding to INTERNET_OPTION_SECURITY_FLAGS\n");
1977 /* fall through */
Aric Stewartc6ae9452009-06-23 15:29:00 +09001978 case INTERNET_OPTION_SECURITY_FLAGS:
1979 {
Juan Lang948173b2010-09-30 13:33:47 -07001980 DWORD flags;
Aric Stewartc6ae9452009-06-23 15:29:00 +09001981
1982 if (*size < sizeof(ULONG))
1983 return ERROR_INSUFFICIENT_BUFFER;
1984
1985 *size = sizeof(DWORD);
Jacek Caban59a0ab52012-05-25 16:34:43 +02001986 flags = req->netconn ? req->netconn->security_flags : req->security_flags | req->server->security_flags;
Juan Lang948173b2010-09-30 13:33:47 -07001987 *(DWORD *)buffer = flags;
Jacek Cabanf3dd75d2012-05-25 16:35:12 +02001988
1989 TRACE("INTERNET_OPTION_SECURITY_FLAGS %x\n", flags);
Aric Stewartc6ae9452009-06-23 15:29:00 +09001990 return ERROR_SUCCESS;
1991 }
1992
Jacek Cabane2933c22008-03-12 02:23:20 +01001993 case INTERNET_OPTION_HANDLE_TYPE:
1994 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1995
1996 if (*size < sizeof(ULONG))
1997 return ERROR_INSUFFICIENT_BUFFER;
1998
1999 *size = sizeof(DWORD);
2000 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
2001 return ERROR_SUCCESS;
Jacek Caban0e010d82008-03-12 02:23:48 +01002002
2003 case INTERNET_OPTION_URL: {
2004 WCHAR url[INTERNET_MAX_URL_LENGTH];
2005 HTTPHEADERW *host;
2006 DWORD len;
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002007 WCHAR *pch;
Jacek Caban0e010d82008-03-12 02:23:48 +01002008
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002009 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
Jacek Caban0e010d82008-03-12 02:23:48 +01002010
2011 TRACE("INTERNET_OPTION_URL\n");
2012
2013 host = HTTP_GetHeader(req, hostW);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002014 strcpyW(url, httpW);
2015 strcatW(url, host->lpszValue);
2016 if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
2017 *pch = 0;
Juan Lang20980062011-03-01 11:18:22 -08002018 strcatW(url, req->path);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04002019
Jacek Caban0e010d82008-03-12 02:23:48 +01002020 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
2021
2022 if(unicode) {
2023 len = (strlenW(url)+1) * sizeof(WCHAR);
2024 if(*size < len)
2025 return ERROR_INSUFFICIENT_BUFFER;
2026
2027 *size = len;
2028 strcpyW(buffer, url);
2029 return ERROR_SUCCESS;
2030 }else {
2031 len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
2032 if(len > *size)
2033 return ERROR_INSUFFICIENT_BUFFER;
2034
2035 *size = len;
2036 return ERROR_SUCCESS;
2037 }
2038 }
Jacek Cabance6a2282008-03-12 02:24:06 +01002039
Hans Leidekkerc2932852009-06-16 15:13:52 +02002040 case INTERNET_OPTION_CACHE_TIMESTAMPS: {
2041 INTERNET_CACHE_ENTRY_INFOW *info;
2042 INTERNET_CACHE_TIMESTAMPS *ts = buffer;
2043 WCHAR url[INTERNET_MAX_URL_LENGTH];
2044 DWORD nbytes, error;
2045 BOOL ret;
2046
2047 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
2048
2049 if (*size < sizeof(*ts))
2050 {
2051 *size = sizeof(*ts);
2052 return ERROR_INSUFFICIENT_BUFFER;
2053 }
2054 nbytes = 0;
2055 HTTP_GetRequestURL(req, url);
2056 ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
2057 error = GetLastError();
2058 if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
2059 {
Jacek Caban354a74e2011-04-21 13:39:03 +02002060 if (!(info = heap_alloc(nbytes)))
Hans Leidekkerc2932852009-06-16 15:13:52 +02002061 return ERROR_OUTOFMEMORY;
2062
2063 GetUrlCacheEntryInfoW(url, info, &nbytes);
2064
2065 ts->ftExpires = info->ExpireTime;
2066 ts->ftLastModified = info->LastModifiedTime;
2067
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002068 heap_free(info);
Hans Leidekkerc2932852009-06-16 15:13:52 +02002069 *size = sizeof(*ts);
2070 return ERROR_SUCCESS;
2071 }
2072 return error;
2073 }
2074
Jacek Cabance6a2282008-03-12 02:24:06 +01002075 case INTERNET_OPTION_DATAFILE_NAME: {
2076 DWORD req_size;
2077
2078 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
2079
Juan Lang20980062011-03-01 11:18:22 -08002080 if(!req->cacheFile) {
Jacek Cabance6a2282008-03-12 02:24:06 +01002081 *size = 0;
2082 return ERROR_INTERNET_ITEM_NOT_FOUND;
2083 }
2084
2085 if(unicode) {
Juan Lang20980062011-03-01 11:18:22 -08002086 req_size = (lstrlenW(req->cacheFile)+1) * sizeof(WCHAR);
Jacek Cabance6a2282008-03-12 02:24:06 +01002087 if(*size < req_size)
2088 return ERROR_INSUFFICIENT_BUFFER;
2089
2090 *size = req_size;
Juan Lang20980062011-03-01 11:18:22 -08002091 memcpy(buffer, req->cacheFile, *size);
Jacek Cabance6a2282008-03-12 02:24:06 +01002092 return ERROR_SUCCESS;
2093 }else {
Juan Lang20980062011-03-01 11:18:22 -08002094 req_size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile, -1, NULL, 0, NULL, NULL);
Jacek Cabance6a2282008-03-12 02:24:06 +01002095 if (req_size > *size)
2096 return ERROR_INSUFFICIENT_BUFFER;
2097
Juan Lang20980062011-03-01 11:18:22 -08002098 *size = WideCharToMultiByte(CP_ACP, 0, req->cacheFile,
Jacek Cabance6a2282008-03-12 02:24:06 +01002099 -1, buffer, *size, NULL, NULL);
2100 return ERROR_SUCCESS;
2101 }
2102 }
Jacek Caban7e63f952008-03-12 02:24:23 +01002103
2104 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
2105 PCCERT_CONTEXT context;
2106
Juan Lang56ebc042010-09-30 13:09:04 -07002107 if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
2108 *size = sizeof(INTERNET_CERTIFICATE_INFOA);
Jacek Caban7e63f952008-03-12 02:24:23 +01002109 return ERROR_INSUFFICIENT_BUFFER;
2110 }
2111
Jacek Caban8a1df202011-05-10 09:26:43 +00002112 context = (PCCERT_CONTEXT)NETCON_GetCert(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002113 if(context) {
Juan Lang56ebc042010-09-30 13:09:04 -07002114 INTERNET_CERTIFICATE_INFOA *info = (INTERNET_CERTIFICATE_INFOA*)buffer;
Jacek Caban7e63f952008-03-12 02:24:23 +01002115 DWORD len;
2116
Thomas Faber7d24e592012-06-17 16:18:36 +02002117 memset(info, 0, sizeof(*info));
Jacek Caban7e63f952008-03-12 02:24:23 +01002118 info->ftExpiry = context->pCertInfo->NotAfter;
2119 info->ftStart = context->pCertInfo->NotBefore;
Juan Lang56ebc042010-09-30 13:09:04 -07002120 len = CertNameToStrA(context->dwCertEncodingType,
Jacek Caban37e483d2012-05-30 12:13:53 +02002121 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0);
Juan Lang56ebc042010-09-30 13:09:04 -07002122 info->lpszSubjectInfo = LocalAlloc(0, len);
2123 if(info->lpszSubjectInfo)
2124 CertNameToStrA(context->dwCertEncodingType,
Jacek Caban37e483d2012-05-30 12:13:53 +02002125 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG,
Juan Lang56ebc042010-09-30 13:09:04 -07002126 info->lpszSubjectInfo, len);
2127 len = CertNameToStrA(context->dwCertEncodingType,
Jacek Caban37e483d2012-05-30 12:13:53 +02002128 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0);
Juan Lang56ebc042010-09-30 13:09:04 -07002129 info->lpszIssuerInfo = LocalAlloc(0, len);
2130 if(info->lpszIssuerInfo)
2131 CertNameToStrA(context->dwCertEncodingType,
Jacek Caban37e483d2012-05-30 12:13:53 +02002132 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG,
Juan Lang56ebc042010-09-30 13:09:04 -07002133 info->lpszIssuerInfo, len);
Jacek Caban8a1df202011-05-10 09:26:43 +00002134 info->dwKeySize = NETCON_GetCipherStrength(req->netconn);
Jacek Caban7e63f952008-03-12 02:24:23 +01002135 CertFreeCertificateContext(context);
2136 return ERROR_SUCCESS;
2137 }
Thomas Faber0b60b8f2012-06-15 11:38:24 +02002138 return ERROR_NOT_SUPPORTED;
Jacek Caban7e63f952008-03-12 02:24:23 +01002139 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01002140 case INTERNET_OPTION_CONNECT_TIMEOUT:
2141 if (*size < sizeof(DWORD))
2142 return ERROR_INSUFFICIENT_BUFFER;
2143
2144 *size = sizeof(DWORD);
2145 *(DWORD *)buffer = req->connect_timeout;
2146 return ERROR_SUCCESS;
Jacek Caban27af8192012-05-24 15:24:43 +02002147 case INTERNET_OPTION_REQUEST_FLAGS: {
2148 DWORD flags = 0;
Jacek Cabanc0400562012-05-23 18:24:02 +02002149
2150 if (*size < sizeof(DWORD))
2151 return ERROR_INSUFFICIENT_BUFFER;
2152
Jacek Caban27af8192012-05-24 15:24:43 +02002153 /* FIXME: Add support for:
2154 * INTERNET_REQFLAG_FROM_CACHE
2155 * INTERNET_REQFLAG_CACHE_WRITE_DISABLED
2156 */
Jacek Cabanc0400562012-05-23 18:24:02 +02002157
Jacek Caban27af8192012-05-24 15:24:43 +02002158 if(req->session->appInfo->proxy)
2159 flags |= INTERNET_REQFLAG_VIA_PROXY;
2160 if(!req->rawHeaders)
2161 flags |= INTERNET_REQFLAG_NO_HEADERS;
2162
2163 TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags);
2164
2165 *size = sizeof(DWORD);
2166 *(DWORD*)buffer = flags;
Jacek Cabanc0400562012-05-23 18:24:02 +02002167 return ERROR_SUCCESS;
Jacek Cabane2933c22008-03-12 02:23:20 +01002168 }
Jacek Caban27af8192012-05-24 15:24:43 +02002169 }
Jacek Cabane2933c22008-03-12 02:23:20 +01002170
Hans Leidekker80dd3672010-05-25 12:19:32 +02002171 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01002172}
2173
Jacek Caban44d633a2009-07-07 21:46:09 +02002174static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Jacek Caban0e33eee2008-02-26 20:22:02 +01002175{
Jacek Caban34abacd2009-07-13 01:41:50 +02002176 http_request_t *req = (http_request_t*)hdr;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002177
2178 switch(option) {
Jacek Caband8b5f462012-06-07 15:40:45 +02002179 case 99: /* Undocumented, seems to be INTERNET_OPTION_SECURITY_FLAGS with argument validation */
2180 TRACE("Undocumented option 99\n");
2181
2182 if (!buffer || size != sizeof(DWORD))
2183 return ERROR_INVALID_PARAMETER;
2184 if(*(DWORD*)buffer & ~SECURITY_SET_MASK)
2185 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2186
2187 /* fall through */
Juan Lang77c4ade2010-09-28 16:46:41 -07002188 case INTERNET_OPTION_SECURITY_FLAGS:
2189 {
2190 DWORD flags;
2191
2192 if (!buffer || size != sizeof(DWORD))
2193 return ERROR_INVALID_PARAMETER;
2194 flags = *(DWORD *)buffer;
Jacek Caban8dbc39b2012-06-06 17:38:30 +02002195 TRACE("INTERNET_OPTION_SECURITY_FLAGS %08x\n", flags);
2196 flags &= SECURITY_SET_MASK;
2197 req->security_flags |= flags;
Jacek Caban8a1df202011-05-10 09:26:43 +00002198 if(req->netconn)
Jacek Caban8dbc39b2012-06-06 17:38:30 +02002199 req->netconn->security_flags |= flags;
Juan Lang77c4ade2010-09-28 16:46:41 -07002200 return ERROR_SUCCESS;
2201 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01002202 case INTERNET_OPTION_CONNECT_TIMEOUT:
Hans Leidekker65223932012-01-13 15:15:48 +01002203 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
Hans Leidekker848cd8a2012-01-13 15:15:20 +01002204 req->connect_timeout = *(DWORD *)buffer;
2205 return ERROR_SUCCESS;
2206
Jacek Caban0e33eee2008-02-26 20:22:02 +01002207 case INTERNET_OPTION_SEND_TIMEOUT:
Hans Leidekker65223932012-01-13 15:15:48 +01002208 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
2209 req->send_timeout = *(DWORD *)buffer;
2210 return ERROR_SUCCESS;
2211
Jacek Caban0e33eee2008-02-26 20:22:02 +01002212 case INTERNET_OPTION_RECEIVE_TIMEOUT:
Hans Leidekker65223932012-01-13 15:15:48 +01002213 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
2214 req->receive_timeout = *(DWORD *)buffer;
2215 return ERROR_SUCCESS;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002216
2217 case INTERNET_OPTION_USERNAME:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002218 heap_free(req->session->userName);
Juan Lang20980062011-03-01 11:18:22 -08002219 if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002220 return ERROR_SUCCESS;
2221
2222 case INTERNET_OPTION_PASSWORD:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02002223 heap_free(req->session->password);
Juan Lang20980062011-03-01 11:18:22 -08002224 if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekkera57cc6d2008-12-02 17:15:07 +01002225 return ERROR_SUCCESS;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002226 case INTERNET_OPTION_HTTP_DECODING:
2227 if(size != sizeof(BOOL))
2228 return ERROR_INVALID_PARAMETER;
2229 req->decoding = *(BOOL*)buffer;
2230 return ERROR_SUCCESS;
Jacek Caban0e33eee2008-02-26 20:22:02 +01002231 }
2232
Jacek Caban48632572012-03-08 12:19:14 +01002233 return INET_SetOption(hdr, option, buffer, size);
Jacek Caban0e33eee2008-02-26 20:22:02 +01002234}
2235
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002236/* read some more data into the read buffer (the read section must be held) */
Jacek Caban1d96e202009-11-30 19:59:56 +01002237static DWORD read_more_data( http_request_t *req, int maxlen )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002238{
Jacek Caban358e7b72009-11-30 19:59:40 +01002239 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002240 int len;
2241
Jacek Caban11ca05f2009-05-29 23:35:13 +02002242 if (req->read_pos)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002243 {
2244 /* move existing data to the start of the buffer */
Jacek Caban11ca05f2009-05-29 23:35:13 +02002245 if(req->read_size)
2246 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002247 req->read_pos = 0;
2248 }
2249
2250 if (maxlen == -1) maxlen = sizeof(req->read_buf);
Jacek Caban11ca05f2009-05-29 23:35:13 +02002251
Jacek Caban8a1df202011-05-10 09:26:43 +00002252 res = NETCON_recv( req->netconn, req->read_buf + req->read_size,
Jacek Caban358e7b72009-11-30 19:59:40 +01002253 maxlen - req->read_size, 0, &len );
Jacek Caban1d96e202009-11-30 19:59:56 +01002254 if(res == ERROR_SUCCESS)
2255 req->read_size += len;
Jacek Caban11ca05f2009-05-29 23:35:13 +02002256
Jacek Caban1d96e202009-11-30 19:59:56 +01002257 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002258}
2259
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002260/* remove some amount of data from the read buffer (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002261static void remove_data( http_request_t *req, int count )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002262{
2263 if (!(req->read_size -= count)) req->read_pos = 0;
2264 else req->read_pos += count;
2265}
2266
Jacek Caban34abacd2009-07-13 01:41:50 +02002267static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002268{
2269 int count, bytes_read, pos = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002270 DWORD res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002271
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002272 EnterCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002273 for (;;)
2274 {
Jacek Caban26bbf072009-05-29 23:34:37 +02002275 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002276
2277 if (eol)
2278 {
2279 count = eol - (req->read_buf + req->read_pos);
2280 bytes_read = count + 1;
2281 }
2282 else count = bytes_read = req->read_size;
2283
2284 count = min( count, *len - pos );
2285 memcpy( buffer + pos, req->read_buf + req->read_pos, count );
2286 pos += count;
2287 remove_data( req, bytes_read );
2288 if (eol) break;
2289
Jacek Caban1d96e202009-11-30 19:59:56 +01002290 if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002291 {
2292 *len = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00002293 TRACE( "returning empty string %u\n", res);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002294 LeaveCriticalSection( &req->read_section );
Jacek Caban1d96e202009-11-30 19:59:56 +01002295 INTERNET_SetLastError(res);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002296 return FALSE;
2297 }
2298 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002299 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002300
2301 if (pos < *len)
2302 {
2303 if (pos && buffer[pos - 1] == '\r') pos--;
2304 *len = pos + 1;
2305 }
2306 buffer[*len - 1] = 0;
2307 TRACE( "returning %s\n", debugstr_a(buffer));
2308 return TRUE;
2309}
2310
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002311/* check if we have reached the end of the data to read (the read section must be held) */
2312static BOOL end_of_read_data( http_request_t *req )
2313{
2314 return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req);
2315}
2316
2317/* fetch some more data into the read buffer (the read section must be held) */
Jacek Caban193da882011-05-23 16:10:09 +02002318static DWORD refill_read_buffer(http_request_t *req, read_mode_t read_mode, DWORD *read_bytes)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002319{
Dan Kegel766eeca2012-07-07 17:34:52 -07002320 DWORD res, read=0, want;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002321
2322 if(req->read_size == sizeof(req->read_buf))
2323 return ERROR_SUCCESS;
2324
2325 if(req->read_pos) {
2326 if(req->read_size)
2327 memmove(req->read_buf, req->read_buf+req->read_pos, req->read_size);
2328 req->read_pos = 0;
2329 }
2330
Dan Kegel766eeca2012-07-07 17:34:52 -07002331 want = sizeof(req->read_buf) - req->read_size;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002332 res = req->data_stream->vtbl->read(req->data_stream, req, req->read_buf+req->read_size,
Dan Kegel766eeca2012-07-07 17:34:52 -07002333 want, &read, read_mode);
2334 assert(read <= want);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002335 req->read_size += read;
2336
2337 TRACE("read %u bytes, read_size %u\n", read, req->read_size);
Jacek Caban193da882011-05-23 16:10:09 +02002338 if(read_bytes)
2339 *read_bytes = read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002340 return res;
2341}
2342
2343/* return the size of data available to be read immediately (the read section must be held) */
2344static DWORD get_avail_data( http_request_t *req )
2345{
2346 return req->read_size + req->data_stream->vtbl->get_avail_data(req->data_stream, req);
2347}
2348
2349static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req)
2350{
Jacek Caban8a1df202011-05-10 09:26:43 +00002351 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002352 DWORD avail = 0;
2353
Jacek Caban8a1df202011-05-10 09:26:43 +00002354 if(req->netconn)
2355 NETCON_query_data_available(req->netconn, &avail);
2356 return netconn_stream->content_length == ~0u
2357 ? avail
2358 : min(avail, netconn_stream->content_length-netconn_stream->content_read);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002359}
2360
2361static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req)
2362{
2363 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Caban8a1df202011-05-10 09:26:43 +00002364 return netconn_stream->content_read == netconn_stream->content_length || !req->netconn;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002365}
2366
2367static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2368 DWORD *read, read_mode_t read_mode)
2369{
2370 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002371 int len = 0;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002372
2373 size = min(size, netconn_stream->content_length-netconn_stream->content_read);
2374
Dan Kegel766eeca2012-07-07 17:34:52 -07002375 if(read_mode == READMODE_NOBLOCK) {
2376 DWORD avail = netconn_get_avail_data(stream, req);
2377 if (size > avail)
2378 size = avail;
2379 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002380
Jacek Caban8a1df202011-05-10 09:26:43 +00002381 if(size && req->netconn) {
2382 if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS)
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002383 len = 0;
Jacek Cabancfdc5392011-06-10 14:47:27 +02002384 if(!len)
2385 netconn_stream->content_length = netconn_stream->content_read;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002386 }
2387
Jacek Cabanaa612ec2011-05-02 11:25:47 +02002388 netconn_stream->content_read += *read = len;
2389 TRACE("read %u bytes\n", len);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002390 return ERROR_SUCCESS;
2391}
2392
Jacek Caban8a1df202011-05-10 09:26:43 +00002393static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req)
2394{
2395 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2396 BYTE buf[1024];
2397 DWORD avail;
2398 int len;
2399
2400 if(netconn_end_of_data(stream, req))
2401 return TRUE;
2402
2403 do {
2404 avail = netconn_get_avail_data(stream, req);
2405 if(!avail)
2406 return FALSE;
2407
2408 if(NETCON_recv(req->netconn, buf, min(avail, sizeof(buf)), 0, &len) != ERROR_SUCCESS)
2409 return FALSE;
2410
2411 netconn_stream->content_read += len;
2412 }while(netconn_stream->content_read < netconn_stream->content_length);
2413
2414 return TRUE;
2415}
2416
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002417static void netconn_destroy(data_stream_t *stream)
2418{
2419}
2420
2421static const data_stream_vtbl_t netconn_stream_vtbl = {
2422 netconn_get_avail_data,
2423 netconn_end_of_data,
2424 netconn_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002425 netconn_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002426 netconn_destroy
2427};
2428
2429/* read some more data into the read buffer (the read section must be held) */
2430static DWORD read_more_chunked_data(chunked_stream_t *stream, http_request_t *req, int maxlen)
2431{
2432 DWORD res;
2433 int len;
2434
2435 if (stream->buf_pos)
2436 {
2437 /* move existing data to the start of the buffer */
2438 if(stream->buf_size)
2439 memmove(stream->buf, stream->buf + stream->buf_pos, stream->buf_size);
2440 stream->buf_pos = 0;
2441 }
2442
2443 if (maxlen == -1) maxlen = sizeof(stream->buf);
2444
Jacek Caban8a1df202011-05-10 09:26:43 +00002445 res = NETCON_recv( req->netconn, stream->buf + stream->buf_size,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002446 maxlen - stream->buf_size, 0, &len );
2447 if(res == ERROR_SUCCESS)
2448 stream->buf_size += len;
2449
2450 return res;
2451}
2452
2453/* remove some amount of data from the read buffer (the read section must be held) */
2454static void remove_chunked_data(chunked_stream_t *stream, int count)
2455{
2456 if (!(stream->buf_size -= count)) stream->buf_pos = 0;
2457 else stream->buf_pos += count;
2458}
2459
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002460/* discard data contents until we reach end of line (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002461static DWORD discard_chunked_eol(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002462{
Jacek Caban1d96e202009-11-30 19:59:56 +01002463 DWORD res;
2464
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002465 do
2466 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002467 BYTE *eol = memchr(stream->buf + stream->buf_pos, '\n', stream->buf_size);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002468 if (eol)
2469 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002470 remove_chunked_data(stream, (eol + 1) - (stream->buf + stream->buf_pos));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002471 break;
2472 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002473 stream->buf_pos = stream->buf_size = 0; /* discard everything */
2474 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2475 } while (stream->buf_size);
Jacek Caban1d96e202009-11-30 19:59:56 +01002476 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002477}
2478
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002479/* read the size of the next chunk (the read section must be held) */
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002480static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002481{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002482 /* TODOO */
Jacek Caban1d96e202009-11-30 19:59:56 +01002483 DWORD chunk_size = 0, res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002484
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002485 if(stream->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
2486 return res;
2487
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002488 for (;;)
2489 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002490 while (stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002491 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002492 char ch = stream->buf[stream->buf_pos];
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002493 if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
2494 else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
2495 else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
2496 else if (ch == ';' || ch == '\r' || ch == '\n')
2497 {
2498 TRACE( "reading %u byte chunk\n", chunk_size );
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002499 stream->chunk_size = chunk_size;
2500 req->contentLength += chunk_size;
2501 return discard_chunked_eol(stream, req);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002502 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002503 remove_chunked_data(stream, 1);
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002504 }
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002505 if ((res = read_more_chunked_data(stream, req, -1)) != ERROR_SUCCESS) return res;
2506 if (!stream->buf_size)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002507 {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002508 stream->chunk_size = 0;
Jacek Caban1d96e202009-11-30 19:59:56 +01002509 return ERROR_SUCCESS;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002510 }
2511 }
2512}
2513
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002514static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002515{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002516 /* Allow reading only from read buffer */
2517 return 0;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002518}
2519
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002520static BOOL chunked_end_of_data(data_stream_t *stream, http_request_t *req)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002521{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002522 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2523 return !chunked_stream->chunk_size;
2524}
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002525
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002526static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
2527 DWORD *read, read_mode_t read_mode)
2528{
2529 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2530 DWORD read_bytes = 0, ret_read = 0, res = ERROR_SUCCESS;
2531
2532 if(chunked_stream->chunk_size == ~0u) {
2533 res = start_next_chunk(chunked_stream, req);
2534 if(res != ERROR_SUCCESS)
2535 return res;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002536 }
2537
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002538 while(size && chunked_stream->chunk_size) {
2539 if(chunked_stream->buf_size) {
2540 read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size));
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002541
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002542 /* this could block */
2543 if(read_mode == READMODE_NOBLOCK && read_bytes == chunked_stream->chunk_size)
2544 break;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002545
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002546 memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
2547 remove_chunked_data(chunked_stream, read_bytes);
2548 }else {
2549 read_bytes = min(size, chunked_stream->chunk_size);
Jacek Cabana76db212009-06-07 21:19:06 +02002550
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002551 if(read_mode == READMODE_NOBLOCK) {
2552 DWORD avail;
Jacek Cabana76db212009-06-07 21:19:06 +02002553
Jacek Caban8a1df202011-05-10 09:26:43 +00002554 if(!NETCON_query_data_available(req->netconn, &avail) || !avail)
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002555 break;
2556 if(read_bytes > avail)
2557 read_bytes = avail;
2558
2559 /* this could block */
2560 if(read_bytes == chunked_stream->chunk_size)
2561 break;
2562 }
2563
Jacek Caban8a1df202011-05-10 09:26:43 +00002564 res = NETCON_recv(req->netconn, (char *)buf+ret_read, read_bytes, 0, (int*)&read_bytes);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002565 if(res != ERROR_SUCCESS)
Jacek Cabana76db212009-06-07 21:19:06 +02002566 break;
2567 }
2568
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002569 chunked_stream->chunk_size -= read_bytes;
2570 size -= read_bytes;
2571 ret_read += read_bytes;
2572 if(!chunked_stream->chunk_size) {
2573 assert(read_mode != READMODE_NOBLOCK);
2574 res = start_next_chunk(chunked_stream, req);
2575 if(res != ERROR_SUCCESS)
2576 break;
Jacek Cabana76db212009-06-07 21:19:06 +02002577 }
Jacek Cabana76db212009-06-07 21:19:06 +02002578
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002579 if(read_mode == READMODE_ASYNC)
2580 read_mode = READMODE_NOBLOCK;
Jacek Cabana76db212009-06-07 21:19:06 +02002581 }
2582
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002583 TRACE("read %u bytes\n", ret_read);
2584 *read = ret_read;
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002585 return res;
2586}
2587
Jacek Caban8a1df202011-05-10 09:26:43 +00002588static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req)
2589{
2590 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2591
2592 /* FIXME: we can do better */
2593 return !chunked_stream->chunk_size;
2594}
2595
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002596static void chunked_destroy(data_stream_t *stream)
Jacek Caban2bb3f4f2011-03-17 01:01:19 +01002597{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002598 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2599 heap_free(chunked_stream);
Jacek Cabana76db212009-06-07 21:19:06 +02002600}
2601
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002602static const data_stream_vtbl_t chunked_stream_vtbl = {
2603 chunked_get_avail_data,
2604 chunked_end_of_data,
2605 chunked_read,
Jacek Caban8a1df202011-05-10 09:26:43 +00002606 chunked_drain_content,
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002607 chunked_destroy
2608};
2609
2610/* set the request content length based on the headers */
Jacek Caban5240e402012-05-03 12:19:47 +02002611static DWORD set_content_length(http_request_t *request)
Jacek Cabana76db212009-06-07 21:19:06 +02002612{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002613 static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
2614 WCHAR encoding[20];
2615 DWORD size;
2616
Jacek Caban5240e402012-05-03 12:19:47 +02002617 if(request->status_code == HTTP_STATUS_NO_CONTENT) {
Jacek Cabana890e3a2011-05-13 13:48:15 +02002618 request->contentLength = request->netconn_stream.content_length = 0;
2619 return ERROR_SUCCESS;
2620 }
2621
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002622 size = sizeof(request->contentLength);
2623 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
2624 &request->contentLength, &size, NULL) != ERROR_SUCCESS)
2625 request->contentLength = ~0u;
2626 request->netconn_stream.content_length = request->contentLength;
2627 request->netconn_stream.content_read = request->read_size;
2628
2629 size = sizeof(encoding);
2630 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS &&
2631 !strcmpiW(encoding, szChunked))
2632 {
2633 chunked_stream_t *chunked_stream;
2634
2635 chunked_stream = heap_alloc(sizeof(*chunked_stream));
2636 if(!chunked_stream)
2637 return ERROR_OUTOFMEMORY;
2638
2639 chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
2640 chunked_stream->buf_size = chunked_stream->buf_pos = 0;
2641 chunked_stream->chunk_size = ~0u;
2642
2643 if(request->read_size) {
2644 memcpy(chunked_stream->buf, request->read_buf+request->read_pos, request->read_size);
2645 chunked_stream->buf_size = request->read_size;
2646 request->read_size = request->read_pos = 0;
2647 }
2648
2649 request->data_stream = &chunked_stream->data_stream;
2650 request->contentLength = ~0u;
2651 request->read_chunked = TRUE;
2652 }
2653
2654 if(request->decoding) {
2655 int encoding_idx;
2656
2657 static const WCHAR gzipW[] = {'g','z','i','p',0};
2658
2659 encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE);
2660 if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW))
2661 return init_gzip_stream(request);
2662 }
2663
2664 return ERROR_SUCCESS;
Jacek Cabana76db212009-06-07 21:19:06 +02002665}
2666
Jacek Cabanc0293df2011-06-10 14:47:04 +02002667static void send_request_complete(http_request_t *req, DWORD_PTR result, DWORD error)
Jacek Caban12931062009-01-13 00:28:25 +01002668{
2669 INTERNET_ASYNC_RESULT iar;
Jacek Cabanc0293df2011-06-10 14:47:04 +02002670
2671 iar.dwResult = result;
2672 iar.dwError = error;
2673
2674 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2675 sizeof(INTERNET_ASYNC_RESULT));
2676}
2677
2678static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2679{
2680 DWORD res, read = 0, avail = 0;
Jacek Caban193da882011-05-23 16:10:09 +02002681 read_mode_t mode;
Jacek Caban12931062009-01-13 00:28:25 +01002682
2683 TRACE("%p\n", req);
2684
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002685 EnterCriticalSection( &req->read_section );
Jacek Caban193da882011-05-23 16:10:09 +02002686
2687 mode = first_notif && req->read_size ? READMODE_NOBLOCK : READMODE_ASYNC;
2688 res = refill_read_buffer(req, mode, &read);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002689 if(res == ERROR_SUCCESS && !first_notif)
2690 avail = get_avail_data(req);
Jacek Caban193da882011-05-23 16:10:09 +02002691
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002692 LeaveCriticalSection( &req->read_section );
Jacek Caban12931062009-01-13 00:28:25 +01002693
Jacek Caban193da882011-05-23 16:10:09 +02002694 if(res != ERROR_SUCCESS || (mode != READMODE_NOBLOCK && !read)) {
2695 WARN("res %u read %u, closing connection\n", res, read);
2696 http_release_netconn(req, FALSE);
2697 }
2698
Jacek Cabanc0293df2011-06-10 14:47:04 +02002699 if(res == ERROR_SUCCESS)
Jacek Caban8e37ed52011-06-10 14:47:16 +02002700 send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail);
Jacek Cabanc0293df2011-06-10 14:47:04 +02002701 else
2702 send_request_complete(req, 0, res);
Jacek Caban12931062009-01-13 00:28:25 +01002703}
2704
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002705/* read data from the http connection (the read section must be held) */
Jacek Caban34abacd2009-07-13 01:41:50 +02002706static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
Jacek Caban3b4ca692008-03-02 19:35:11 +01002707{
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002708 DWORD current_read = 0, ret_read = 0;
2709 read_mode_t read_mode;
2710 DWORD res = ERROR_SUCCESS;
2711
2712 read_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? READMODE_ASYNC : READMODE_SYNC;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002713
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002714 EnterCriticalSection( &req->read_section );
Jacek Cabana76db212009-06-07 21:19:06 +02002715
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002716 if(req->read_size) {
2717 ret_read = min(size, req->read_size);
2718 memcpy(buffer, req->read_buf+req->read_pos, ret_read);
2719 req->read_size -= ret_read;
2720 req->read_pos += ret_read;
2721 if(read_mode == READMODE_ASYNC)
2722 read_mode = READMODE_NOBLOCK;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002723 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002724
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002725 if(ret_read < size) {
2726 res = req->data_stream->vtbl->read(req->data_stream, req, (BYTE*)buffer+ret_read, size-ret_read, &current_read, read_mode);
2727 ret_read += current_read;
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002728 }
Jacek Caban3b4ca692008-03-02 19:35:11 +01002729
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002730 LeaveCriticalSection( &req->read_section );
2731
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002732 *read = ret_read;
2733 TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength );
Jacek Caban3b4ca692008-03-02 19:35:11 +01002734
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002735 if(req->hCacheFile && res == ERROR_SUCCESS && ret_read) {
2736 BOOL res;
2737 DWORD written;
2738
2739 res = WriteFile(req->hCacheFile, buffer, ret_read, &written, NULL);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002740 if(!res)
2741 WARN("WriteFile failed: %u\n", GetLastError());
2742 }
2743
Jacek Caban086eb612011-05-13 13:48:00 +02002744 if(size && !ret_read)
2745 http_release_netconn(req, res == ERROR_SUCCESS);
Jacek Caban3b4ca692008-03-02 19:35:11 +01002746
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002747 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002748}
2749
Jacek Cabanc4001172012-07-02 17:15:04 +02002750static BOOL drain_content(http_request_t *req, BOOL blocking)
2751{
2752 BOOL ret;
2753
2754 if(!req->netconn || req->contentLength == -1)
2755 return FALSE;
2756
2757 if(!strcmpW(req->verb, szHEAD))
2758 return TRUE;
2759
2760 if(!blocking)
2761 return req->data_stream->vtbl->drain_content(req->data_stream, req);
2762
2763 EnterCriticalSection( &req->read_section );
2764
2765 while(1) {
2766 DWORD bytes_read, res;
2767 BYTE buf[4096];
2768
2769 res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read, TRUE);
2770 if(res != ERROR_SUCCESS) {
2771 ret = FALSE;
2772 break;
2773 }
2774 if(!bytes_read) {
2775 ret = TRUE;
2776 break;
2777 }
2778 }
2779
2780 LeaveCriticalSection( &req->read_section );
2781 return ret;
2782}
Hans Leidekker058761f2008-03-26 22:22:04 +01002783
Jacek Caban44d633a2009-07-07 21:46:09 +02002784static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
Hans Leidekker058761f2008-03-26 22:22:04 +01002785{
Jacek Caban34abacd2009-07-13 01:41:50 +02002786 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002787 DWORD res;
2788
2789 EnterCriticalSection( &req->read_section );
2790 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2791 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2792
2793 res = HTTPREQ_Read(req, buffer, size, read, TRUE);
2794 if(res == ERROR_SUCCESS)
2795 res = hdr->dwError;
2796 LeaveCriticalSection( &req->read_section );
2797
2798 return res;
Jacek Caban3b4ca692008-03-02 19:35:11 +01002799}
2800
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002801static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
Jacek Caband597fd12008-03-03 18:07:20 +01002802{
2803 struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
Jacek Caban34abacd2009-07-13 01:41:50 +02002804 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caband597fd12008-03-03 18:07:20 +01002805 DWORD res;
2806
2807 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2808
2809 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2810 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2811
Jacek Cabanc0293df2011-06-10 14:47:04 +02002812 send_request_complete(req, res == ERROR_SUCCESS, res);
Jacek Caband597fd12008-03-03 18:07:20 +01002813}
2814
Jacek Caban44d633a2009-07-07 21:46:09 +02002815static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
Jacek Caband597fd12008-03-03 18:07:20 +01002816 DWORD flags, DWORD_PTR context)
2817{
Jacek Caban34abacd2009-07-13 01:41:50 +02002818 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002819 DWORD res, size, read, error = ERROR_SUCCESS;
Jacek Caband597fd12008-03-03 18:07:20 +01002820
2821 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2822 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2823
2824 if (buffers->dwStructSize != sizeof(*buffers))
2825 return ERROR_INVALID_PARAMETER;
2826
2827 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2828
Piotr Caban898531d2010-07-01 13:10:46 +02002829 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002830 {
2831 WORKREQUEST workRequest;
Jacek Caband597fd12008-03-03 18:07:20 +01002832
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002833 if (TryEnterCriticalSection( &req->read_section ))
2834 {
2835 if (get_avail_data(req))
2836 {
2837 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2838 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002839 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002840 LeaveCriticalSection( &req->read_section );
2841 goto done;
2842 }
2843 LeaveCriticalSection( &req->read_section );
2844 }
2845
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002846 workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2847 workRequest.hdr = WININET_AddRef(&req->hdr);
2848 workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
Jacek Caband597fd12008-03-03 18:07:20 +01002849
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002850 INTERNET_AsyncCall(&workRequest);
Jacek Caband597fd12008-03-03 18:07:20 +01002851
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002852 return ERROR_IO_PENDING;
Jacek Caband597fd12008-03-03 18:07:20 +01002853 }
2854
Piotr Caban21ced8d2010-07-20 00:33:24 +02002855 read = 0;
2856 size = buffers->dwBufferLength;
2857
2858 EnterCriticalSection( &req->read_section );
2859 if(hdr->dwError == ERROR_SUCCESS)
2860 hdr->dwError = INTERNET_HANDLE_IN_USE;
2861 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2862 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2863
2864 while(1) {
2865 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2866 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002867 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002868 break;
2869
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002870 read += buffers->dwBufferLength;
2871 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002872 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002873
Piotr Caban21ced8d2010-07-20 00:33:24 +02002874 LeaveCriticalSection( &req->read_section );
2875
2876 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2877 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2878 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2879 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2880
2881 EnterCriticalSection( &req->read_section );
2882 }
2883
2884 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2885 hdr->dwError = ERROR_SUCCESS;
2886 else
2887 error = hdr->dwError;
2888
2889 LeaveCriticalSection( &req->read_section );
2890 size = buffers->dwBufferLength;
2891 buffers->dwBufferLength = read;
Jacek Caband597fd12008-03-03 18:07:20 +01002892
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002893done:
Jacek Caband597fd12008-03-03 18:07:20 +01002894 if (res == ERROR_SUCCESS) {
Jacek Caband597fd12008-03-03 18:07:20 +01002895 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2896 &size, sizeof(size));
2897 }
2898
Piotr Caban21ced8d2010-07-20 00:33:24 +02002899 return res==ERROR_SUCCESS ? error : res;
Jacek Caband597fd12008-03-03 18:07:20 +01002900}
2901
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002902static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2903{
2904 struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
Jacek Caban34abacd2009-07-13 01:41:50 +02002905 http_request_t *req = (http_request_t*)workRequest->hdr;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002906 DWORD res;
2907
2908 TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2909
2910 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2911 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2912
Jacek Cabanc0293df2011-06-10 14:47:04 +02002913 send_request_complete(req, res == ERROR_SUCCESS, res);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002914}
2915
Jacek Caban44d633a2009-07-07 21:46:09 +02002916static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002917 DWORD flags, DWORD_PTR context)
2918{
2919
Jacek Caban34abacd2009-07-13 01:41:50 +02002920 http_request_t *req = (http_request_t*)hdr;
Piotr Caban21ced8d2010-07-20 00:33:24 +02002921 DWORD res, size, read, error = ERROR_SUCCESS;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002922
2923 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2924 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2925
2926 if (buffers->dwStructSize != sizeof(*buffers))
2927 return ERROR_INVALID_PARAMETER;
2928
2929 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2930
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002931 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002932 {
2933 WORKREQUEST workRequest;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002934
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002935 if (TryEnterCriticalSection( &req->read_section ))
2936 {
2937 if (get_avail_data(req))
2938 {
2939 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2940 &buffers->dwBufferLength, FALSE);
Piotr Caban21ced8d2010-07-20 00:33:24 +02002941 size = buffers->dwBufferLength;
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002942 LeaveCriticalSection( &req->read_section );
2943 goto done;
2944 }
2945 LeaveCriticalSection( &req->read_section );
2946 }
2947
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002948 workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2949 workRequest.hdr = WININET_AddRef(&req->hdr);
2950 workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002951
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002952 INTERNET_AsyncCall(&workRequest);
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002953
Alexandre Julliard3d02c422009-05-14 16:45:38 +02002954 return ERROR_IO_PENDING;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002955 }
2956
Piotr Caban21ced8d2010-07-20 00:33:24 +02002957 read = 0;
2958 size = buffers->dwBufferLength;
2959
2960 EnterCriticalSection( &req->read_section );
2961 if(hdr->dwError == ERROR_SUCCESS)
2962 hdr->dwError = INTERNET_HANDLE_IN_USE;
2963 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2964 hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
2965
2966 while(1) {
2967 res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
2968 &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002969 if(res != ERROR_SUCCESS)
Piotr Caban21ced8d2010-07-20 00:33:24 +02002970 break;
2971
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002972 read += buffers->dwBufferLength;
2973 if(read == size || end_of_read_data(req))
Piotr Caban21ced8d2010-07-20 00:33:24 +02002974 break;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02002975
Piotr Caban21ced8d2010-07-20 00:33:24 +02002976 LeaveCriticalSection( &req->read_section );
2977
2978 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2979 &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
2980 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2981 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2982
2983 EnterCriticalSection( &req->read_section );
2984 }
2985
2986 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
2987 hdr->dwError = ERROR_SUCCESS;
2988 else
2989 error = hdr->dwError;
2990
2991 LeaveCriticalSection( &req->read_section );
2992 size = buffers->dwBufferLength;
2993 buffers->dwBufferLength = read;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002994
Alexandre Julliard5c227a92009-05-28 23:01:28 +02002995done:
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002996 if (res == ERROR_SUCCESS) {
Hans Leidekkerb013ad12009-01-15 16:41:42 +01002997 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2998 &size, sizeof(size));
2999 }
3000
Piotr Caban21ced8d2010-07-20 00:33:24 +02003001 return res==ERROR_SUCCESS ? error : res;
Hans Leidekkerb013ad12009-01-15 16:41:42 +01003002}
3003
Jacek Caban1ee3ad42009-11-30 00:13:39 +01003004static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003005{
Jacek Cabanb77868c2009-11-30 00:13:21 +01003006 DWORD res;
Juan Langb49b2432011-03-01 10:59:39 -08003007 http_request_t *request = (http_request_t*)hdr;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003008
Juan Langb49b2432011-03-01 10:59:39 -08003009 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Hans Leidekker85eb4382009-04-08 15:22:05 +02003010
Hans Leidekker0fabf542009-04-08 15:21:28 +02003011 *written = 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00003012 res = NETCON_send(request->netconn, buffer, size, 0, (LPINT)written);
Jacek Cabanb77868c2009-11-30 00:13:21 +01003013 if (res == ERROR_SUCCESS)
Juan Lang20980062011-03-01 11:18:22 -08003014 request->bytesWritten += *written;
Hans Leidekker0fabf542009-04-08 15:21:28 +02003015
Juan Langb49b2432011-03-01 10:59:39 -08003016 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
Jacek Caban1ee3ad42009-11-30 00:13:39 +01003017 return res;
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003018}
3019
Jacek Caban33141842008-02-29 12:57:57 +01003020static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
3021{
Jacek Caban34abacd2009-07-13 01:41:50 +02003022 http_request_t *req = (http_request_t*)workRequest->hdr;
Jacek Caban33141842008-02-29 12:57:57 +01003023
Jacek Cabane13781a2009-01-22 13:48:23 +01003024 HTTP_ReceiveRequestData(req, FALSE);
Jacek Caban33141842008-02-29 12:57:57 +01003025}
3026
Jacek Caban44d633a2009-07-07 21:46:09 +02003027static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
Jacek Caban33141842008-02-29 12:57:57 +01003028{
Jacek Caban34abacd2009-07-13 01:41:50 +02003029 http_request_t *req = (http_request_t*)hdr;
Jacek Caban33141842008-02-29 12:57:57 +01003030
3031 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
3032
Juan Lang20980062011-03-01 11:18:22 -08003033 if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban33141842008-02-29 12:57:57 +01003034 {
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003035 WORKREQUEST workRequest;
Jacek Caban33141842008-02-29 12:57:57 +01003036
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003037 /* never wait, if we can't enter the section we queue an async request right away */
3038 if (TryEnterCriticalSection( &req->read_section ))
Alexandre Julliard3d02c422009-05-14 16:45:38 +02003039 {
Jacek Caban193da882011-05-23 16:10:09 +02003040 refill_read_buffer(req, READMODE_NOBLOCK, NULL);
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003041 if ((*available = get_avail_data( req ))) goto done;
3042 if (end_of_read_data( req )) goto done;
3043 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02003044 }
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003045
3046 workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
3047 workRequest.hdr = WININET_AddRef( &req->hdr );
3048
3049 INTERNET_AsyncCall(&workRequest);
3050
3051 return ERROR_IO_PENDING;
Jacek Caban33141842008-02-29 12:57:57 +01003052 }
3053
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003054 EnterCriticalSection( &req->read_section );
3055
3056 if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
3057 {
Jacek Caban193da882011-05-23 16:10:09 +02003058 refill_read_buffer( req, READMODE_ASYNC, NULL );
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003059 *available = get_avail_data( req );
3060 }
3061
3062done:
Alexandre Julliard5c227a92009-05-28 23:01:28 +02003063 LeaveCriticalSection( &req->read_section );
Alexandre Julliard3d02c422009-05-14 16:45:38 +02003064
3065 TRACE( "returning %u\n", *available );
Jacek Caban33141842008-02-29 12:57:57 +01003066 return ERROR_SUCCESS;
3067}
3068
Jacek Caban44d633a2009-07-07 21:46:09 +02003069static const object_vtbl_t HTTPREQVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01003070 HTTPREQ_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01003071 HTTPREQ_CloseConnection,
Jacek Cabane2933c22008-03-12 02:23:20 +01003072 HTTPREQ_QueryOption,
Jacek Caban0e33eee2008-02-26 20:22:02 +01003073 HTTPREQ_SetOption,
Jacek Caban3b4ca692008-03-02 19:35:11 +01003074 HTTPREQ_ReadFile,
Jacek Caband597fd12008-03-03 18:07:20 +01003075 HTTPREQ_ReadFileExA,
Hans Leidekkerb013ad12009-01-15 16:41:42 +01003076 HTTPREQ_ReadFileExW,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003077 HTTPREQ_WriteFile,
Jacek Caban33141842008-02-29 12:57:57 +01003078 HTTPREQ_QueryDataAvailable,
Jacek Caban8c45eec2008-02-27 18:55:09 +01003079 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01003080};
3081
Mike McCormacka1c16d22003-07-22 03:17:52 +00003082/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003083 * HTTP_HttpOpenRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003084 *
3085 * Open a HTTP request handle
3086 *
3087 * RETURNS
3088 * HINTERNET a HTTP request handle on success
3089 * NULL on failure
3090 *
3091 */
Juan Langb49b2432011-03-01 10:59:39 -08003092static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
Jacek Caban85a057e2009-11-30 20:00:44 +01003093 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3094 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3095 DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003096{
Jacek Caban8a1df202011-05-10 09:26:43 +00003097 appinfo_t *hIC = session->appInfo;
Juan Langb49b2432011-03-01 10:59:39 -08003098 http_request_t *request;
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02003099 INTERNET_PORT port;
Jacek Caban8a1df202011-05-10 09:26:43 +00003100 DWORD len, res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003101
Francois Gouget0edbaf72005-11-10 12:14:56 +00003102 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00003103
Juan Langb49b2432011-03-01 10:59:39 -08003104 request = alloc_object(&session->hdr, &HTTPREQVtbl, sizeof(http_request_t));
3105 if(!request)
Jacek Cabana073c662011-02-02 22:51:13 +01003106 return ERROR_OUTOFMEMORY;
3107
Juan Langb49b2432011-03-01 10:59:39 -08003108 request->hdr.htype = WH_HHTTPREQ;
3109 request->hdr.dwFlags = dwFlags;
3110 request->hdr.dwContext = dwContext;
Juan Lang20980062011-03-01 11:18:22 -08003111 request->contentLength = ~0u;
Jacek Cabana073c662011-02-02 22:51:13 +01003112
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003113 request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl;
3114 request->data_stream = &request->netconn_stream.data_stream;
Hans Leidekker72273a02012-01-13 15:15:04 +01003115 request->connect_timeout = session->connect_timeout;
Hans Leidekker65223932012-01-13 15:15:48 +01003116 request->send_timeout = session->send_timeout;
3117 request->receive_timeout = session->receive_timeout;
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003118
Juan Langb49b2432011-03-01 10:59:39 -08003119 InitializeCriticalSection( &request->read_section );
Francois Gouget17929b92011-11-16 16:29:44 +01003120 request->read_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.read_section");
Mike McCormack3a1391b2004-07-19 21:49:39 +00003121
Juan Langb49b2432011-03-01 10:59:39 -08003122 WININET_AddRef( &session->hdr );
Juan Lang20980062011-03-01 11:18:22 -08003123 request->session = session;
Juan Langb49b2432011-03-01 10:59:39 -08003124 list_add_head( &session->hdr.children, &request->hdr.entry );
Jacek Cabana9bdc012006-10-29 18:50:25 +01003125
Jacek Caban2ed97eb2012-05-28 13:55:13 +02003126 port = session->hostPort;
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02003127 if(port == INTERNET_INVALID_PORT_NUMBER)
3128 port = dwFlags & INTERNET_FLAG_SECURE ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
3129
Jacek Caban6c764fb2012-06-11 10:22:38 +02003130 request->server = get_server(session->hostName, port, TRUE);
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02003131 if(!request->server) {
3132 WININET_Release(&request->hdr);
3133 return ERROR_OUTOFMEMORY;
3134 }
3135
Juan Lang0b8bfd92011-04-07 08:05:36 -07003136 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_CN_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003137 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
Juan Lang0b8bfd92011-04-07 08:05:36 -07003138 if (dwFlags & INTERNET_FLAG_IGNORE_CERT_DATE_INVALID)
Jacek Caban8a1df202011-05-10 09:26:43 +00003139 request->security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003140
Jacek Cabanf9791342008-02-13 13:34:05 +01003141 if (lpszObjectName && *lpszObjectName) {
Aric Stewartff9b9d42002-06-21 23:59:49 +00003142 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003143
3144 len = 0;
3145 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003146 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003147 len = strlenW(lpszObjectName)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003148 request->path = heap_alloc(len*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003149 rc = UrlEscapeW(lpszObjectName, request->path, &len,
Huw D M Davies0aebee92001-01-21 21:09:00 +00003150 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003151 if (rc != S_OK)
Aric Stewartff9b9d42002-06-21 23:59:49 +00003152 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003153 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
Juan Lang20980062011-03-01 11:18:22 -08003154 strcpyW(request->path,lpszObjectName);
Aric Stewartff9b9d42002-06-21 23:59:49 +00003155 }
Jacek Caband1d1da32009-05-29 23:34:25 +02003156 }else {
3157 static const WCHAR slashW[] = {'/',0};
3158
Juan Lang20980062011-03-01 11:18:22 -08003159 request->path = heap_strdupW(slashW);
Huw D M Davies0aebee92001-01-21 21:09:00 +00003160 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003161
Jacek Cabanf9791342008-02-13 13:34:05 +01003162 if (lpszReferrer && *lpszReferrer)
Juan Langb49b2432011-03-01 10:59:39 -08003163 HTTP_ProcessHeader(request, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003164
Hans Leidekker2024f682007-02-12 15:19:17 +01003165 if (lpszAcceptTypes)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003166 {
3167 int i;
Hans Leidekker2024f682007-02-12 15:19:17 +01003168 for (i = 0; lpszAcceptTypes[i]; i++)
3169 {
3170 if (!*lpszAcceptTypes[i]) continue;
Juan Langb49b2432011-03-01 10:59:39 -08003171 HTTP_ProcessHeader(request, HTTP_ACCEPT, lpszAcceptTypes[i],
Hans Leidekker2024f682007-02-12 15:19:17 +01003172 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
3173 HTTP_ADDHDR_FLAG_REQ |
3174 (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
3175 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003176 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00003177
Juan Lang20980062011-03-01 11:18:22 -08003178 request->verb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
3179 request->version = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
Hans Leidekkerd0033db2008-02-17 20:41:42 +01003180
Juan Lang8e050392011-03-01 11:02:14 -08003181 if (session->hostPort != INTERNET_INVALID_PORT_NUMBER &&
3182 session->hostPort != INTERNET_DEFAULT_HTTP_PORT &&
3183 session->hostPort != INTERNET_DEFAULT_HTTPS_PORT)
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003184 {
Jacek Caban59f2e832011-05-02 11:26:10 +02003185 WCHAR *host_name;
3186
3187 static const WCHAR host_formatW[] = {'%','s',':','%','u',0};
3188
3189 host_name = heap_alloc((strlenW(session->hostName) + 7 /* length of ":65535" + 1 */) * sizeof(WCHAR));
3190 if (!host_name) {
3191 res = ERROR_OUTOFMEMORY;
3192 goto lend;
3193 }
3194
3195 sprintfW(host_name, host_formatW, session->hostName, session->hostPort);
3196 HTTP_ProcessHeader(request, hostW, host_name, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
3197 heap_free(host_name);
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003198 }
3199 else
Juan Lang8e050392011-03-01 11:02:14 -08003200 HTTP_ProcessHeader(request, hostW, session->hostName,
Alexander Morozov4f51b6c2008-07-03 16:34:40 +04003201 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
Robert Shearman37f2cc82004-09-13 19:33:17 +00003202
Juan Lang8e050392011-03-01 11:02:14 -08003203 if (session->hostPort == INTERNET_INVALID_PORT_NUMBER)
3204 session->hostPort = (dwFlags & INTERNET_FLAG_SECURE ?
Hans Leidekkere4c59c22008-03-30 19:17:31 +01003205 INTERNET_DEFAULT_HTTPS_PORT :
3206 INTERNET_DEFAULT_HTTP_PORT);
Mike McCormack403e58f2005-10-19 19:07:08 +00003207
Jacek Caban8a1df202011-05-10 09:26:43 +00003208 if (hIC->proxy && hIC->proxy[0])
Juan Langb49b2432011-03-01 10:59:39 -08003209 HTTP_DealWithProxy( hIC, session, request );
Ulrich Czekallac2757242000-06-11 20:04:44 +00003210
Juan Langb49b2432011-03-01 10:59:39 -08003211 INTERNET_SendCallback(&session->hdr, dwContext,
3212 INTERNET_STATUS_HANDLE_CREATED, &request->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01003213 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00003214
Mike McCormack3a1391b2004-07-19 21:49:39 +00003215lend:
Juan Langb49b2432011-03-01 10:59:39 -08003216 TRACE("<-- %u (%p)\n", res, request);
Mike McCormack3a1391b2004-07-19 21:49:39 +00003217
Jacek Cabana073c662011-02-02 22:51:13 +01003218 if(res != ERROR_SUCCESS) {
Juan Langb49b2432011-03-01 10:59:39 -08003219 WININET_Release( &request->hdr );
Jacek Cabana073c662011-02-02 22:51:13 +01003220 *ret = NULL;
3221 return res;
3222 }
3223
Juan Langb49b2432011-03-01 10:59:39 -08003224 *ret = request->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01003225 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003226}
3227
Jacek Caban47c71fc2009-11-30 20:00:28 +01003228/***********************************************************************
3229 * HttpOpenRequestW (WININET.@)
3230 *
3231 * Open a HTTP request handle
3232 *
3233 * RETURNS
3234 * HINTERNET a HTTP request handle on success
3235 * NULL on failure
3236 *
3237 */
3238HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
3239 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3240 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3241 DWORD dwFlags, DWORD_PTR dwContext)
3242{
Juan Langb49b2432011-03-01 10:59:39 -08003243 http_session_t *session;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003244 HINTERNET handle = NULL;
Jacek Caban85a057e2009-11-30 20:00:44 +01003245 DWORD res;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003246
3247 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
3248 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
3249 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
3250 dwFlags, dwContext);
3251 if(lpszAcceptTypes!=NULL)
3252 {
3253 int i;
3254 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
3255 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
3256 }
3257
Juan Langb49b2432011-03-01 10:59:39 -08003258 session = (http_session_t*) get_handle_object( hHttpSession );
3259 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban47c71fc2009-11-30 20:00:28 +01003260 {
Jacek Caban85a057e2009-11-30 20:00:44 +01003261 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3262 goto lend;
Jacek Caban47c71fc2009-11-30 20:00:28 +01003263 }
3264
3265 /*
3266 * My tests seem to show that the windows version does not
3267 * become asynchronous until after this point. And anyhow
3268 * if this call was asynchronous then how would you get the
3269 * necessary HINTERNET pointer returned by this function.
3270 *
3271 */
Juan Langb49b2432011-03-01 10:59:39 -08003272 res = HTTP_HttpOpenRequestW(session, lpszVerb, lpszObjectName,
Jacek Caban85a057e2009-11-30 20:00:44 +01003273 lpszVersion, lpszReferrer, lpszAcceptTypes,
3274 dwFlags, dwContext, &handle);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003275lend:
Juan Langb49b2432011-03-01 10:59:39 -08003276 if( session )
3277 WININET_Release( &session->hdr );
Jacek Caban47c71fc2009-11-30 20:00:28 +01003278 TRACE("returning %p\n", handle);
Jacek Caban85a057e2009-11-30 20:00:44 +01003279 if(res != ERROR_SUCCESS)
3280 SetLastError(res);
Jacek Caban47c71fc2009-11-30 20:00:28 +01003281 return handle;
3282}
3283
Mike McCormack7f5e2732006-03-30 18:02:54 +09003284static const LPCWSTR header_lookup[] = {
3285 szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
3286 szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
3287 szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
3288 szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
3289 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
3290 szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
3291 szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
3292 szAllow, /* HTTP_QUERY_ALLOW = 7 */
3293 szPublic, /* HTTP_QUERY_PUBLIC = 8 */
3294 szDate, /* HTTP_QUERY_DATE = 9 */
3295 szExpires, /* HTTP_QUERY_EXPIRES = 10 */
3296 szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
3297 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
3298 szURI, /* HTTP_QUERY_URI = 13 */
3299 szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
3300 NULL, /* HTTP_QUERY_COST = 15 */
3301 NULL, /* HTTP_QUERY_LINK = 16 */
3302 szPragma, /* HTTP_QUERY_PRAGMA = 17 */
3303 NULL, /* HTTP_QUERY_VERSION = 18 */
3304 szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
3305 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
3306 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
3307 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
3308 szConnection, /* HTTP_QUERY_CONNECTION = 23 */
3309 szAccept, /* HTTP_QUERY_ACCEPT = 24 */
3310 szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
3311 szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
3312 szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
3313 szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
3314 szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
3315 NULL, /* HTTP_QUERY_FORWARDED = 30 */
3316 NULL, /* HTTP_QUERY_FROM = 31 */
3317 szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
3318 szLocation, /* HTTP_QUERY_LOCATION = 33 */
3319 NULL, /* HTTP_QUERY_ORIG_URI = 34 */
3320 szReferer, /* HTTP_QUERY_REFERER = 35 */
3321 szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
3322 szServer, /* HTTP_QUERY_SERVER = 37 */
3323 NULL, /* HTTP_TITLE = 38 */
3324 szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
3325 szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
3326 szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
3327 szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
3328 szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
3329 szCookie, /* HTTP_QUERY_COOKIE = 44 */
3330 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
3331 NULL, /* HTTP_QUERY_REFRESH = 46 */
Alexander Morozovef95a792012-05-23 17:49:24 +04003332 szContent_Disposition, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
Mike McCormack7f5e2732006-03-30 18:02:54 +09003333 szAge, /* HTTP_QUERY_AGE = 48 */
3334 szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
3335 szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
3336 szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
3337 szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
3338 szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
3339 szETag, /* HTTP_QUERY_ETAG = 54 */
Jacek Caban83170892009-05-29 23:34:14 +02003340 hostW, /* HTTP_QUERY_HOST = 55 */
Mike McCormack7f5e2732006-03-30 18:02:54 +09003341 szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
3342 szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
3343 szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
3344 szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
3345 szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
3346 szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
3347 szRange, /* HTTP_QUERY_RANGE = 62 */
3348 szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
3349 szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
3350 szVary, /* HTTP_QUERY_VARY = 65 */
3351 szVia, /* HTTP_QUERY_VIA = 66 */
3352 szWarning, /* HTTP_QUERY_WARNING = 67 */
3353 szExpect, /* HTTP_QUERY_EXPECT = 68 */
3354 szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
3355 szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
Aric Stewart1e946d32005-12-13 17:07:41 +01003356};
3357
Mike McCormack7f5e2732006-03-30 18:02:54 +09003358#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
3359
Alexandre Julliard48243e32004-07-15 18:57:32 +00003360/***********************************************************************
Mike McCormackb288f712004-06-14 17:57:26 +00003361 * HTTP_HttpQueryInfoW (internal)
3362 */
Juan Langb49b2432011-03-01 10:59:39 -08003363static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003364 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Mike McCormackb288f712004-06-14 17:57:26 +00003365{
3366 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01003367 BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
Mike McCormackae300882006-03-30 18:01:48 +09003368 INT requested_index = lpdwIndex ? *lpdwIndex : 0;
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003369 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
Mike McCormackae300882006-03-30 18:01:48 +09003370 INT index = -1;
Mike McCormackb288f712004-06-14 17:57:26 +00003371
3372 /* Find requested header structure */
Mike McCormackae300882006-03-30 18:01:48 +09003373 switch (level)
Mike McCormackb288f712004-06-14 17:57:26 +00003374 {
Mike McCormackae300882006-03-30 18:01:48 +09003375 case HTTP_QUERY_CUSTOM:
Jacek Caban9823c232009-12-14 02:27:29 +01003376 if (!lpBuffer) return ERROR_INVALID_PARAMETER;
Juan Langb49b2432011-03-01 10:59:39 -08003377 index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only);
Mike McCormackae300882006-03-30 18:01:48 +09003378 break;
Mike McCormackae300882006-03-30 18:01:48 +09003379 case HTTP_QUERY_RAW_HEADERS_CRLF:
Robert Shearmandee87512004-07-19 20:09:20 +00003380 {
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003381 LPWSTR headers;
Lei Zhangbc9e2142008-08-27 16:54:17 -07003382 DWORD len = 0;
Jacek Caban9823c232009-12-14 02:27:29 +01003383 DWORD res = ERROR_INVALID_PARAMETER;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003384
3385 if (request_only)
Juan Lang20980062011-03-01 11:18:22 -08003386 headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003387 else
Juan Lang20980062011-03-01 11:18:22 -08003388 headers = request->rawHeaders;
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003389
Lei Zhangbc9e2142008-08-27 16:54:17 -07003390 if (headers)
3391 len = strlenW(headers) * sizeof(WCHAR);
3392
Dan Kegel1e7f8912008-07-30 06:49:04 -07003393 if (len + sizeof(WCHAR) > *lpdwBufferLength)
Robert Shearmandee87512004-07-19 20:09:20 +00003394 {
Dan Kegel1e7f8912008-07-30 06:49:04 -07003395 len += sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003396 res = ERROR_INSUFFICIENT_BUFFER;
Hans Leidekker694a0922008-05-18 21:09:50 +02003397 }
3398 else if (lpBuffer)
Mikołaj Zalewskiab7d1772007-08-15 16:29:58 -07003399 {
Lei Zhangbc9e2142008-08-27 16:54:17 -07003400 if (headers)
3401 memcpy(lpBuffer, headers, len + sizeof(WCHAR));
3402 else
3403 {
Lei Zhangf7e56d12008-08-27 17:03:13 -07003404 len = strlenW(szCrLf) * sizeof(WCHAR);
3405 memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
Lei Zhangbc9e2142008-08-27 16:54:17 -07003406 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003407 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
Jacek Caban9823c232009-12-14 02:27:29 +01003408 res = ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003409 }
Hans Leidekker694a0922008-05-18 21:09:50 +02003410 *lpdwBufferLength = len;
Robert Shearman4385d302004-07-21 21:17:03 +00003411
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003412 if (request_only) heap_free(headers);
Jacek Caban9823c232009-12-14 02:27:29 +01003413 return res;
Robert Shearmandee87512004-07-19 20:09:20 +00003414 }
Mike McCormackae300882006-03-30 18:01:48 +09003415 case HTTP_QUERY_RAW_HEADERS:
Robert Shearmandee87512004-07-19 20:09:20 +00003416 {
Juan Lang20980062011-03-01 11:18:22 -08003417 LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf);
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003418 DWORD i, size = 0;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003419 LPWSTR pszString = lpBuffer;
Robert Shearmandee87512004-07-19 20:09:20 +00003420
3421 for (i = 0; ppszRawHeaderLines[i]; i++)
3422 size += strlenW(ppszRawHeaderLines[i]) + 1;
3423
3424 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
3425 {
3426 HTTP_FreeTokens(ppszRawHeaderLines);
3427 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003428 return ERROR_INSUFFICIENT_BUFFER;
Robert Shearmandee87512004-07-19 20:09:20 +00003429 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003430 if (pszString)
Robert Shearmandee87512004-07-19 20:09:20 +00003431 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003432 for (i = 0; ppszRawHeaderLines[i]; i++)
3433 {
3434 DWORD len = strlenW(ppszRawHeaderLines[i]);
3435 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
3436 pszString += len+1;
3437 }
3438 *pszString = '\0';
3439 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
Robert Shearmandee87512004-07-19 20:09:20 +00003440 }
Robert Shearman4385d302004-07-21 21:17:03 +00003441 *lpdwBufferLength = size * sizeof(WCHAR);
Robert Shearmandee87512004-07-19 20:09:20 +00003442 HTTP_FreeTokens(ppszRawHeaderLines);
3443
Jacek Caban9823c232009-12-14 02:27:29 +01003444 return ERROR_SUCCESS;
Robert Shearmandee87512004-07-19 20:09:20 +00003445 }
Mike McCormackae300882006-03-30 18:01:48 +09003446 case HTTP_QUERY_STATUS_TEXT:
Juan Lang20980062011-03-01 11:18:22 -08003447 if (request->statusText)
Aric Stewart1e946d32005-12-13 17:07:41 +01003448 {
Juan Lang20980062011-03-01 11:18:22 -08003449 DWORD len = strlenW(request->statusText);
Aric Stewart1e946d32005-12-13 17:07:41 +01003450 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3451 {
3452 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003453 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003454 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003455 if (lpBuffer)
3456 {
Juan Lang20980062011-03-01 11:18:22 -08003457 memcpy(lpBuffer, request->statusText, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003458 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3459 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003460 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003461 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003462 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003463 break;
Mike McCormackae300882006-03-30 18:01:48 +09003464 case HTTP_QUERY_VERSION:
Juan Lang20980062011-03-01 11:18:22 -08003465 if (request->version)
Aric Stewart1e946d32005-12-13 17:07:41 +01003466 {
Juan Lang20980062011-03-01 11:18:22 -08003467 DWORD len = strlenW(request->version);
Aric Stewart1e946d32005-12-13 17:07:41 +01003468 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
3469 {
3470 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003471 return ERROR_INSUFFICIENT_BUFFER;
Aric Stewart1e946d32005-12-13 17:07:41 +01003472 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003473 if (lpBuffer)
3474 {
Juan Lang20980062011-03-01 11:18:22 -08003475 memcpy(lpBuffer, request->version, (len + 1) * sizeof(WCHAR));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003476 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
3477 }
Aric Stewart1e946d32005-12-13 17:07:41 +01003478 *lpdwBufferLength = len * sizeof(WCHAR);
Jacek Caban9823c232009-12-14 02:27:29 +01003479 return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01003480 }
Mike McCormack739cd1e2006-05-30 22:55:42 +09003481 break;
Jacek Caban11ca05f2009-05-29 23:35:13 +02003482 case HTTP_QUERY_CONTENT_ENCODING:
Jacek Cabanccd11eb2011-04-02 15:20:33 +02003483 index = HTTP_GetCustomHeaderIndex(request, header_lookup[request->read_gzip ? HTTP_QUERY_CONTENT_TYPE : level],
Jacek Caban11ca05f2009-05-29 23:35:13 +02003484 requested_index,request_only);
3485 break;
Jacek Caban0d764892012-05-03 12:20:25 +02003486 case HTTP_QUERY_STATUS_CODE: {
3487 DWORD res = ERROR_SUCCESS;
3488
Jacek Caban07e5b872012-05-14 10:41:31 +02003489 if(request_only)
3490 return ERROR_HTTP_INVALID_QUERY_REQUEST;
3491
3492 if(requested_index)
Jacek Caban0d764892012-05-03 12:20:25 +02003493 break;
3494
3495 if(dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) {
3496 if(*lpdwBufferLength >= sizeof(DWORD))
3497 *(DWORD*)lpBuffer = request->status_code;
3498 else
3499 res = ERROR_INSUFFICIENT_BUFFER;
3500 *lpdwBufferLength = sizeof(DWORD);
3501 }else {
3502 WCHAR buf[12];
3503 DWORD size;
3504 static const WCHAR formatW[] = {'%','u',0};
3505
Jacek Caban120c4132012-06-15 18:15:20 +02003506 size = sprintfW(buf, formatW, request->status_code) * sizeof(WCHAR);
Jacek Caban0d764892012-05-03 12:20:25 +02003507
Jacek Caban120c4132012-06-15 18:15:20 +02003508 if(size <= *lpdwBufferLength) {
3509 memcpy(lpBuffer, buf, size+sizeof(WCHAR));
3510 }else {
3511 size += sizeof(WCHAR);
Jacek Caban0d764892012-05-03 12:20:25 +02003512 res = ERROR_INSUFFICIENT_BUFFER;
Jacek Caban120c4132012-06-15 18:15:20 +02003513 }
Jacek Caban0d764892012-05-03 12:20:25 +02003514
3515 *lpdwBufferLength = size;
3516 }
3517 return res;
3518 }
Mike McCormackae300882006-03-30 18:01:48 +09003519 default:
Mike McCormack7f5e2732006-03-30 18:02:54 +09003520 assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
3521
Andrew Talbotbc8d8e52008-12-08 16:51:08 +00003522 if (level < LAST_TABLE_HEADER && header_lookup[level])
Juan Langb49b2432011-03-01 10:59:39 -08003523 index = HTTP_GetCustomHeaderIndex(request, header_lookup[level],
Mike McCormack7f5e2732006-03-30 18:02:54 +09003524 requested_index,request_only);
Mike McCormackb288f712004-06-14 17:57:26 +00003525 }
3526
Mike McCormackae300882006-03-30 18:01:48 +09003527 if (index >= 0)
Juan Lang20980062011-03-01 11:18:22 -08003528 lphttpHdr = &request->custHeaders[index];
Mike McCormackae300882006-03-30 18:01:48 +09003529
Austin English0e4adae2008-01-04 13:37:14 -06003530 /* Ensure header satisfies requested attributes */
Mike McCormackae300882006-03-30 18:01:48 +09003531 if (!lphttpHdr ||
3532 ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
3533 (~lphttpHdr->wFlags & HDR_ISREQUEST)))
Alexandre Julliard48243e32004-07-15 18:57:32 +00003534 {
Jacek Caban9823c232009-12-14 02:27:29 +01003535 return ERROR_HTTP_HEADER_NOT_FOUND;
Alexandre Julliard48243e32004-07-15 18:57:32 +00003536 }
Mike McCormackb288f712004-06-14 17:57:26 +00003537
Jacek Caban0d764892012-05-03 12:20:25 +02003538 if (lpdwIndex) (*lpdwIndex)++;
Mike McCormackae300882006-03-30 18:01:48 +09003539
Austin English0e4adae2008-01-04 13:37:14 -06003540 /* coalesce value to requested type */
Hans Leidekker128b8a52008-10-06 15:48:28 +02003541 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003542 {
Hans Leidekker128b8a52008-10-06 15:48:28 +02003543 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
3544 TRACE(" returning number: %d\n", *(int *)lpBuffer);
Jacek Caban9823c232009-12-14 02:27:29 +01003545 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003546 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
Mike McCormackb288f712004-06-14 17:57:26 +00003547 {
3548 time_t tmpTime;
3549 struct tm tmpTM;
3550 SYSTEMTIME *STHook;
3551
3552 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
3553
3554 tmpTM = *gmtime(&tmpTime);
Hans Leidekker128b8a52008-10-06 15:48:28 +02003555 STHook = (SYSTEMTIME *)lpBuffer;
Hans Leidekker128b8a52008-10-06 15:48:28 +02003556 STHook->wDay = tmpTM.tm_mday;
3557 STHook->wHour = tmpTM.tm_hour;
3558 STHook->wMilliseconds = 0;
3559 STHook->wMinute = tmpTM.tm_min;
3560 STHook->wDayOfWeek = tmpTM.tm_wday;
3561 STHook->wMonth = tmpTM.tm_mon + 1;
3562 STHook->wSecond = tmpTM.tm_sec;
3563 STHook->wYear = tmpTM.tm_year;
Jacek Caban9823c232009-12-14 02:27:29 +01003564
Hans Leidekker128b8a52008-10-06 15:48:28 +02003565 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
3566 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
3567 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
Mike McCormackb288f712004-06-14 17:57:26 +00003568 }
Aric Stewart7bca41a2005-12-08 12:44:45 +01003569 else if (lphttpHdr->lpszValue)
Mike McCormackb288f712004-06-14 17:57:26 +00003570 {
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003571 DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003572
3573 if (len > *lpdwBufferLength)
3574 {
3575 *lpdwBufferLength = len;
Jacek Caban9823c232009-12-14 02:27:29 +01003576 return ERROR_INSUFFICIENT_BUFFER;
Mike McCormackb288f712004-06-14 17:57:26 +00003577 }
Hans Leidekker128b8a52008-10-06 15:48:28 +02003578 if (lpBuffer)
3579 {
3580 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
Jacek Caban9823c232009-12-14 02:27:29 +01003581 TRACE("! returning string: %s\n", debugstr_w(lpBuffer));
Hans Leidekker128b8a52008-10-06 15:48:28 +02003582 }
Mike McCormackb288f712004-06-14 17:57:26 +00003583 *lpdwBufferLength = len - sizeof(WCHAR);
Mike McCormackb288f712004-06-14 17:57:26 +00003584 }
Jacek Caban9823c232009-12-14 02:27:29 +01003585 return ERROR_SUCCESS;
Mike McCormackb288f712004-06-14 17:57:26 +00003586}
3587
3588/***********************************************************************
Mike McCormack1baf39f2004-03-30 20:37:49 +00003589 * HttpQueryInfoW (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003590 *
3591 * Queries for information about an HTTP request
3592 *
3593 * RETURNS
3594 * TRUE on success
3595 * FALSE on failure
3596 *
3597 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003598BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003599 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003600{
Juan Langb49b2432011-03-01 10:59:39 -08003601 http_request_t *request;
Jacek Caban9823c232009-12-14 02:27:29 +01003602 DWORD res;
Vincent Béron9a624912002-05-31 23:06:46 +00003603
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003604 if (TRACE_ON(wininet)) {
3605#define FE(x) { x, #x }
3606 static const wininet_flag_info query_flags[] = {
3607 FE(HTTP_QUERY_MIME_VERSION),
3608 FE(HTTP_QUERY_CONTENT_TYPE),
3609 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
3610 FE(HTTP_QUERY_CONTENT_ID),
3611 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
3612 FE(HTTP_QUERY_CONTENT_LENGTH),
3613 FE(HTTP_QUERY_CONTENT_LANGUAGE),
3614 FE(HTTP_QUERY_ALLOW),
3615 FE(HTTP_QUERY_PUBLIC),
3616 FE(HTTP_QUERY_DATE),
3617 FE(HTTP_QUERY_EXPIRES),
3618 FE(HTTP_QUERY_LAST_MODIFIED),
3619 FE(HTTP_QUERY_MESSAGE_ID),
3620 FE(HTTP_QUERY_URI),
3621 FE(HTTP_QUERY_DERIVED_FROM),
3622 FE(HTTP_QUERY_COST),
3623 FE(HTTP_QUERY_LINK),
3624 FE(HTTP_QUERY_PRAGMA),
3625 FE(HTTP_QUERY_VERSION),
3626 FE(HTTP_QUERY_STATUS_CODE),
3627 FE(HTTP_QUERY_STATUS_TEXT),
3628 FE(HTTP_QUERY_RAW_HEADERS),
3629 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
3630 FE(HTTP_QUERY_CONNECTION),
3631 FE(HTTP_QUERY_ACCEPT),
3632 FE(HTTP_QUERY_ACCEPT_CHARSET),
3633 FE(HTTP_QUERY_ACCEPT_ENCODING),
3634 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
3635 FE(HTTP_QUERY_AUTHORIZATION),
3636 FE(HTTP_QUERY_CONTENT_ENCODING),
3637 FE(HTTP_QUERY_FORWARDED),
3638 FE(HTTP_QUERY_FROM),
3639 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
3640 FE(HTTP_QUERY_LOCATION),
3641 FE(HTTP_QUERY_ORIG_URI),
3642 FE(HTTP_QUERY_REFERER),
3643 FE(HTTP_QUERY_RETRY_AFTER),
3644 FE(HTTP_QUERY_SERVER),
3645 FE(HTTP_QUERY_TITLE),
3646 FE(HTTP_QUERY_USER_AGENT),
3647 FE(HTTP_QUERY_WWW_AUTHENTICATE),
3648 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
3649 FE(HTTP_QUERY_ACCEPT_RANGES),
Aric Stewart1e946d32005-12-13 17:07:41 +01003650 FE(HTTP_QUERY_SET_COOKIE),
3651 FE(HTTP_QUERY_COOKIE),
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003652 FE(HTTP_QUERY_REQUEST_METHOD),
3653 FE(HTTP_QUERY_REFRESH),
3654 FE(HTTP_QUERY_CONTENT_DISPOSITION),
3655 FE(HTTP_QUERY_AGE),
3656 FE(HTTP_QUERY_CACHE_CONTROL),
3657 FE(HTTP_QUERY_CONTENT_BASE),
3658 FE(HTTP_QUERY_CONTENT_LOCATION),
3659 FE(HTTP_QUERY_CONTENT_MD5),
3660 FE(HTTP_QUERY_CONTENT_RANGE),
3661 FE(HTTP_QUERY_ETAG),
3662 FE(HTTP_QUERY_HOST),
3663 FE(HTTP_QUERY_IF_MATCH),
3664 FE(HTTP_QUERY_IF_NONE_MATCH),
3665 FE(HTTP_QUERY_IF_RANGE),
3666 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
3667 FE(HTTP_QUERY_MAX_FORWARDS),
3668 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
3669 FE(HTTP_QUERY_RANGE),
3670 FE(HTTP_QUERY_TRANSFER_ENCODING),
3671 FE(HTTP_QUERY_UPGRADE),
3672 FE(HTTP_QUERY_VARY),
3673 FE(HTTP_QUERY_VIA),
3674 FE(HTTP_QUERY_WARNING),
3675 FE(HTTP_QUERY_CUSTOM)
3676 };
3677 static const wininet_flag_info modifier_flags[] = {
3678 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
3679 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
3680 FE(HTTP_QUERY_FLAG_NUMBER),
3681 FE(HTTP_QUERY_FLAG_COALESCE)
3682 };
3683#undef FE
3684 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
3685 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00003686 DWORD i;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003687
Juan Lang66b4ad22009-12-04 14:39:37 -08003688 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003689 TRACE(" Attribute:");
3690 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
3691 if (query_flags[i].val == info) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003692 TRACE(" %s", query_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003693 break;
3694 }
3695 }
3696 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003697 TRACE(" Unknown (%08x)", info);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003698 }
3699
Diego Pettenò869a66a2005-01-07 17:09:39 +00003700 TRACE(" Modifier:");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003701 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
3702 if (modifier_flags[i].val & info_mod) {
Diego Pettenò869a66a2005-01-07 17:09:39 +00003703 TRACE(" %s", modifier_flags[i].name);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003704 info_mod &= ~ modifier_flags[i].val;
3705 }
3706 }
3707
3708 if (info_mod) {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003709 TRACE(" Unknown (%08x)", info_mod);
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003710 }
Diego Pettenò869a66a2005-01-07 17:09:39 +00003711 TRACE("\n");
Lionel Ulmer1d5e6b62004-02-09 22:01:49 +00003712 }
3713
Juan Langb49b2432011-03-01 10:59:39 -08003714 request = (http_request_t*) get_handle_object( hHttpRequest );
3715 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Ulrich Czekallac2757242000-06-11 20:04:44 +00003716 {
Jacek Caban9823c232009-12-14 02:27:29 +01003717 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3718 goto lend;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003719 }
3720
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003721 if (lpBuffer == NULL)
3722 *lpdwBufferLength = 0;
Juan Langb49b2432011-03-01 10:59:39 -08003723 res = HTTP_HttpQueryInfoW( request, dwInfoLevel,
Jacek Caban9823c232009-12-14 02:27:29 +01003724 lpBuffer, lpdwBufferLength, lpdwIndex);
Ulrich Czekallac2757242000-06-11 20:04:44 +00003725
Mike McCormack3a1391b2004-07-19 21:49:39 +00003726lend:
Juan Langb49b2432011-03-01 10:59:39 -08003727 if( request )
3728 WININET_Release( &request->hdr );
Mike McCormack3a1391b2004-07-19 21:49:39 +00003729
Jacek Caban9823c232009-12-14 02:27:29 +01003730 TRACE("%u <--\n", res);
3731 if(res != ERROR_SUCCESS)
3732 SetLastError(res);
3733 return res == ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00003734}
3735
Alberto Massarid476a5a2002-11-12 02:13:04 +00003736/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00003737 * HttpQueryInfoA (WININET.@)
Alberto Massarid476a5a2002-11-12 02:13:04 +00003738 *
3739 * Queries for information about an HTTP request
3740 *
3741 * RETURNS
3742 * TRUE on success
3743 * FALSE on failure
3744 *
3745 */
Mike McCormacka4e902c2004-03-30 04:36:09 +00003746BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
Alberto Massarid476a5a2002-11-12 02:13:04 +00003747 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3748{
3749 BOOL result;
Mike McCormack1baf39f2004-03-30 20:37:49 +00003750 DWORD len;
3751 WCHAR* bufferW;
3752
Alberto Massarid476a5a2002-11-12 02:13:04 +00003753 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3754 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3755 {
Mike McCormack1baf39f2004-03-30 20:37:49 +00003756 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3757 lpdwBufferLength, lpdwIndex );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003758 }
Mike McCormack1baf39f2004-03-30 20:37:49 +00003759
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003760 if (lpBuffer)
3761 {
Rob Shearman719cd822008-02-18 19:37:35 +00003762 DWORD alloclen;
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003763 len = (*lpdwBufferLength)*sizeof(WCHAR);
Rob Shearman719cd822008-02-18 19:37:35 +00003764 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3765 {
3766 alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3767 if (alloclen < len)
3768 alloclen = len;
3769 }
3770 else
3771 alloclen = len;
Jacek Caban354a74e2011-04-21 13:39:03 +02003772 bufferW = heap_alloc(alloclen);
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003773 /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3774 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
Rob Shearman719cd822008-02-18 19:37:35 +00003775 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
Mikołaj Zalewski3fa49f02007-08-15 16:55:15 -07003776 } else
3777 {
3778 bufferW = NULL;
3779 len = 0;
3780 }
3781
Mike McCormack1baf39f2004-03-30 20:37:49 +00003782 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3783 &len, lpdwIndex );
3784 if( result )
Alberto Massarid476a5a2002-11-12 02:13:04 +00003785 {
Robert Shearman4385d302004-07-21 21:17:03 +00003786 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
Mike McCormack1baf39f2004-03-30 20:37:49 +00003787 lpBuffer, *lpdwBufferLength, NULL, NULL );
Robert Shearman4385d302004-07-21 21:17:03 +00003788 *lpdwBufferLength = len - 1;
3789
3790 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
Alberto Massarid476a5a2002-11-12 02:13:04 +00003791 }
Robert Shearman907ac442004-07-20 01:21:08 +00003792 else
3793 /* since the strings being returned from HttpQueryInfoW should be
3794 * only ASCII characters, it is reasonable to assume that all of
3795 * the Unicode characters can be reduced to a single byte */
3796 *lpdwBufferLength = len / sizeof(WCHAR);
Robert Shearman4385d302004-07-21 21:17:03 +00003797
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003798 heap_free( bufferW );
Alberto Massarid476a5a2002-11-12 02:13:04 +00003799 return result;
3800}
Huw D M Daviesf9b6d7b2000-10-28 00:30:23 +00003801
3802/***********************************************************************
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003803 * HTTP_GetRedirectURL (internal)
3804 */
Juan Langb49b2432011-03-01 10:59:39 -08003805static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003806{
3807 static WCHAR szHttp[] = {'h','t','t','p',0};
3808 static WCHAR szHttps[] = {'h','t','t','p','s',0};
Juan Lang20980062011-03-01 11:18:22 -08003809 http_session_t *session = request->session;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003810 URL_COMPONENTSW urlComponents;
3811 DWORD url_length = 0;
3812 LPWSTR orig_url;
3813 LPWSTR combined_url;
3814
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003815 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Juan Langb49b2432011-03-01 10:59:39 -08003816 urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003817 urlComponents.dwSchemeLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003818 urlComponents.lpszHostName = session->hostName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003819 urlComponents.dwHostNameLength = 0;
Juan Lang8e050392011-03-01 11:02:14 -08003820 urlComponents.nPort = session->hostPort;
3821 urlComponents.lpszUserName = session->userName;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003822 urlComponents.dwUserNameLength = 0;
3823 urlComponents.lpszPassword = NULL;
3824 urlComponents.dwPasswordLength = 0;
Juan Lang20980062011-03-01 11:18:22 -08003825 urlComponents.lpszUrlPath = request->path;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003826 urlComponents.dwUrlPathLength = 0;
3827 urlComponents.lpszExtraInfo = NULL;
3828 urlComponents.dwExtraInfoLength = 0;
3829
3830 if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
3831 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3832 return NULL;
3833
Jacek Caban354a74e2011-04-21 13:39:03 +02003834 orig_url = heap_alloc(url_length);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003835
3836 /* convert from bytes to characters */
3837 url_length = url_length / sizeof(WCHAR) - 1;
3838 if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
3839 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003840 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003841 return NULL;
3842 }
3843
3844 url_length = 0;
3845 if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
3846 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3847 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003848 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003849 return NULL;
3850 }
Jacek Caban354a74e2011-04-21 13:39:03 +02003851 combined_url = heap_alloc(url_length * sizeof(WCHAR));
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003852
3853 if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
3854 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003855 heap_free(orig_url);
3856 heap_free(combined_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003857 return NULL;
3858 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003859 heap_free(orig_url);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003860 return combined_url;
3861}
3862
3863
3864/***********************************************************************
Alberto Massaribc8bd722002-12-06 23:20:31 +00003865 * HTTP_HandleRedirect (internal)
3866 */
Juan Langb49b2432011-03-01 10:59:39 -08003867static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003868{
Juan Lang20980062011-03-01 11:18:22 -08003869 http_session_t *session = request->session;
Juan Lang8e050392011-03-01 11:02:14 -08003870 appinfo_t *hIC = session->appInfo;
Juan Lang72431562011-03-01 11:00:49 -08003871 BOOL using_proxy = hIC->proxy && hIC->proxy[0];
André Hentschel0fda1352011-08-22 21:30:55 +02003872 WCHAR path[INTERNET_MAX_PATH_LENGTH];
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003873 int index;
Mike McCormack7cc70c02004-02-07 01:03:41 +00003874
Alberto Massaribc8bd722002-12-06 23:20:31 +00003875 if(lpszUrl[0]=='/')
3876 {
3877 /* if it's an absolute path, keep the same session info */
Hans Leidekker612f3c12008-03-31 20:26:16 +02003878 lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003879 }
3880 else
3881 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00003882 URL_COMPONENTSW urlComponents;
André Hentschel0fda1352011-08-22 21:30:55 +02003883 WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
3884 WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
3885 WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
Jacek Cabanac265172012-01-24 17:31:17 +01003886 BOOL custom_port = FALSE;
3887
3888 static WCHAR httpW[] = {'h','t','t','p',0};
3889 static WCHAR httpsW[] = {'h','t','t','p','s',0};
Robert Shearman05900252006-03-09 15:11:59 +00003890
Aric Stewart1fc760d2005-11-28 17:31:02 +01003891 userName[0] = 0;
3892 hostName[0] = 0;
3893 protocol[0] = 0;
3894
Mike McCormacka4e902c2004-03-30 04:36:09 +00003895 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003896 urlComponents.lpszScheme = protocol;
André Hentschel0fda1352011-08-22 21:30:55 +02003897 urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003898 urlComponents.lpszHostName = hostName;
André Hentschel0fda1352011-08-22 21:30:55 +02003899 urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003900 urlComponents.lpszUserName = userName;
André Hentschel0fda1352011-08-22 21:30:55 +02003901 urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003902 urlComponents.lpszPassword = NULL;
3903 urlComponents.dwPasswordLength = 0;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003904 urlComponents.lpszUrlPath = path;
André Hentschel0fda1352011-08-22 21:30:55 +02003905 urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
Robert Shearmandc5f1cb2005-11-30 12:01:50 +01003906 urlComponents.lpszExtraInfo = NULL;
3907 urlComponents.dwExtraInfoLength = 0;
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02003908 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003909 return INTERNET_GetLastError();
Robert Shearmanefac01b2005-11-29 11:25:31 +01003910
Jacek Cabanac265172012-01-24 17:31:17 +01003911 if(!strcmpiW(protocol, httpW)) {
3912 if(request->hdr.dwFlags & INTERNET_FLAG_SECURE) {
3913 TRACE("redirect from secure page to non-secure page\n");
3914 /* FIXME: warn about from secure redirect to non-secure page */
3915 request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
3916 }
Robert Shearmanefac01b2005-11-29 11:25:31 +01003917
Jacek Cabanac265172012-01-24 17:31:17 +01003918 if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
Aric Stewart1fc760d2005-11-28 17:31:02 +01003919 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
Jacek Cabanac265172012-01-24 17:31:17 +01003920 else if(urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT)
3921 custom_port = TRUE;
3922 }else if(!strcmpiW(protocol, httpsW)) {
3923 if(!(request->hdr.dwFlags & INTERNET_FLAG_SECURE)) {
3924 TRACE("redirect from non-secure page to secure page\n");
3925 /* FIXME: notify about redirect to secure page */
3926 request->hdr.dwFlags |= INTERNET_FLAG_SECURE;
3927 }
3928
3929 if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
3930 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3931 else if(urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
3932 custom_port = TRUE;
Aric Stewart1fc760d2005-11-28 17:31:02 +01003933 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003934
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003935 heap_free(session->hostName);
Jacek Cabanac265172012-01-24 17:31:17 +01003936
3937 if(custom_port) {
Aric Stewart1fc760d2005-11-28 17:31:02 +01003938 int len;
André Hentschel1a39e292011-03-27 15:27:46 +02003939 static const WCHAR fmt[] = {'%','s',':','%','u',0};
Aric Stewart1fc760d2005-11-28 17:31:02 +01003940 len = lstrlenW(hostName);
Robert Shearman8a8ce9c2005-11-29 11:35:19 +01003941 len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
Jacek Caban354a74e2011-04-21 13:39:03 +02003942 session->hostName = heap_alloc(len*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08003943 sprintfW(session->hostName, fmt, hostName, urlComponents.nPort);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003944 }
3945 else
Juan Lang8e050392011-03-01 11:02:14 -08003946 session->hostName = heap_strdupW(hostName);
Aric Stewart1fc760d2005-11-28 17:31:02 +01003947
Juan Lang8e050392011-03-01 11:02:14 -08003948 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 +01003949
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003950 heap_free(session->userName);
Juan Lang8e050392011-03-01 11:02:14 -08003951 session->userName = NULL;
Robert Shearmanef209362006-03-10 12:28:52 +00003952 if (userName[0])
Juan Lang8e050392011-03-01 11:02:14 -08003953 session->userName = heap_strdupW(userName);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003954
Jacek Caban8a1df202011-05-10 09:26:43 +00003955 reset_data_stream(request);
Jacek Caban36cb1ef2009-11-30 00:14:02 +01003956
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02003957 if(!using_proxy && (strcmpiW(request->server->name, hostName) || request->server->port != urlComponents.nPort)) {
3958 server_t *new_server;
3959
Jacek Caban6c764fb2012-06-11 10:22:38 +02003960 new_server = get_server(hostName, urlComponents.nPort, TRUE);
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02003961 server_release(request->server);
3962 request->server = new_server;
Hans Leidekker8210e1b2008-03-31 20:25:57 +02003963 }
Alberto Massaribc8bd722002-12-06 23:20:31 +00003964 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02003965 heap_free(request->path);
Juan Lang20980062011-03-01 11:18:22 -08003966 request->path=NULL;
Jacek Cabanf9791342008-02-13 13:34:05 +01003967 if (*path)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003968 {
3969 DWORD needed = 0;
3970 HRESULT rc;
Mike McCormacka4e902c2004-03-30 04:36:09 +00003971
3972 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003973 if (rc != E_POINTER)
Mike McCormacka4e902c2004-03-30 04:36:09 +00003974 needed = strlenW(path)+1;
Jacek Caban354a74e2011-04-21 13:39:03 +02003975 request->path = heap_alloc(needed*sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08003976 rc = UrlEscapeW(path, request->path, &needed,
Alberto Massaribc8bd722002-12-06 23:20:31 +00003977 URL_ESCAPE_SPACES_ONLY);
Rob Shearmand31ce9a2008-10-01 11:20:49 +01003978 if (rc != S_OK)
Alberto Massaribc8bd722002-12-06 23:20:31 +00003979 {
Hans Leidekkercd2c4582006-10-05 13:18:56 +02003980 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
Juan Lang20980062011-03-01 11:18:22 -08003981 strcpyW(request->path,path);
Alberto Massaribc8bd722002-12-06 23:20:31 +00003982 }
3983 }
3984
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003985 /* Remove custom content-type/length headers on redirects. */
Juan Langb49b2432011-03-01 10:59:39 -08003986 index = HTTP_GetCustomHeaderIndex(request, szContent_Type, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003987 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003988 HTTP_DeleteCustomHeader(request, index);
3989 index = HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003990 if (0 <= index)
Juan Langb49b2432011-03-01 10:59:39 -08003991 HTTP_DeleteCustomHeader(request, index);
Dan Hipschmana1ebffb2008-04-22 15:48:28 -07003992
Jacek Cabana9ecdc62009-12-03 14:49:56 +01003993 return ERROR_SUCCESS;
Alberto Massaribc8bd722002-12-06 23:20:31 +00003994}
3995
3996/***********************************************************************
Mike McCormacka4969062004-07-04 00:24:47 +00003997 * HTTP_build_req (internal)
3998 *
3999 * concatenate all the strings in the request together
4000 */
4001static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
4002{
4003 LPCWSTR *t;
4004 LPWSTR str;
4005
4006 for( t = list; *t ; t++ )
4007 len += strlenW( *t );
4008 len++;
4009
Jacek Caban354a74e2011-04-21 13:39:03 +02004010 str = heap_alloc(len*sizeof(WCHAR));
Mike McCormacka4969062004-07-04 00:24:47 +00004011 *str = 0;
4012
4013 for( t = list; *t ; t++ )
4014 strcatW( str, *t );
4015
4016 return str;
4017}
4018
Juan Langb49b2432011-03-01 10:59:39 -08004019static DWORD HTTP_SecureProxyConnect(http_request_t *request)
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004020{
4021 LPWSTR lpszPath;
4022 LPWSTR requestString;
4023 INT len;
4024 INT cnt;
4025 INT responseLen;
4026 char *ascii_req;
Jacek Cabanb77868c2009-11-30 00:13:21 +01004027 DWORD res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004028 static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
André Hentschel1a39e292011-03-27 15:27:46 +02004029 static const WCHAR szFormat[] = {'%','s',':','%','u',0};
Juan Lang20980062011-03-01 11:18:22 -08004030 http_session_t *session = request->session;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004031
4032 TRACE("\n");
4033
Jacek Caban354a74e2011-04-21 13:39:03 +02004034 lpszPath = heap_alloc((lstrlenW( session->hostName ) + 13)*sizeof(WCHAR));
Juan Lang8e050392011-03-01 11:02:14 -08004035 sprintfW( lpszPath, szFormat, session->hostName, session->hostPort );
Juan Langb49b2432011-03-01 10:59:39 -08004036 requestString = HTTP_BuildHeaderRequestString( request, szConnect, lpszPath, g_szHttp1_1 );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004037 heap_free( lpszPath );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004038
4039 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4040 NULL, 0, NULL, NULL );
4041 len--; /* the nul terminator isn't needed */
Jacek Caban354a74e2011-04-21 13:39:03 +02004042 ascii_req = heap_alloc(len);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004043 WideCharToMultiByte( CP_ACP, 0, requestString, -1, ascii_req, len, NULL, NULL );
4044 heap_free( requestString );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004045
4046 TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
4047
Hans Leidekker65223932012-01-13 15:15:48 +01004048 NETCON_set_timeout( request->netconn, TRUE, request->send_timeout );
Jacek Caban8a1df202011-05-10 09:26:43 +00004049 res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt );
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004050 heap_free( ascii_req );
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004051 if (res != ERROR_SUCCESS)
4052 return res;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004053
Juan Langb49b2432011-03-01 10:59:39 -08004054 responseLen = HTTP_GetResponseHeaders( request, TRUE );
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004055 if (!responseLen)
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004056 return ERROR_HTTP_INVALID_HEADER;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004057
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004058 return ERROR_SUCCESS;
Robert Shearman0e7c41e2005-11-28 11:55:16 +01004059}
4060
Juan Langb49b2432011-03-01 10:59:39 -08004061static void HTTP_InsertCookies(http_request_t *request)
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004062{
Jacek Cabandce91812011-05-19 16:11:30 +02004063 DWORD cookie_size, size, cnt = 0;
4064 HTTPHEADERW *host;
4065 WCHAR *cookies;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004066
Jacek Cabandce91812011-05-19 16:11:30 +02004067 static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' ',0};
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004068
Jacek Cabandce91812011-05-19 16:11:30 +02004069 host = HTTP_GetHeader(request, hostW);
4070 if(!host)
4071 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004072
Jacek Cabandce91812011-05-19 16:11:30 +02004073 if(!get_cookie(host->lpszValue, request->path, NULL, &cookie_size))
4074 return;
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004075
Jacek Cabandce91812011-05-19 16:11:30 +02004076 size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf);
4077 if(!(cookies = heap_alloc(size)))
4078 return;
4079
4080 cnt += sprintfW(cookies, cookieW);
4081 get_cookie(host->lpszValue, request->path, cookies+cnt, &cookie_size);
4082 strcatW(cookies, szCrLf);
4083
4084 HTTP_HttpAddRequestHeadersW(request, cookies, strlenW(cookies), HTTP_ADDREQ_FLAG_REPLACE);
4085
4086 heap_free(cookies);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004087}
4088
Juan Langaeca2f92011-10-21 22:55:14 -07004089static WORD HTTP_ParseWkday(LPCWSTR day)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004090{
Francois Gouget4bacb3f2011-03-11 18:22:23 +01004091 static const WCHAR days[7][4] = {{ 's','u','n',0 },
4092 { 'm','o','n',0 },
4093 { 't','u','e',0 },
4094 { 'w','e','d',0 },
4095 { 't','h','u',0 },
4096 { 'f','r','i',0 },
4097 { 's','a','t',0 }};
4098 int i;
4099 for (i = 0; i < sizeof(days)/sizeof(*days); i++)
4100 if (!strcmpiW(day, days[i]))
4101 return i;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004102
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004103 /* Invalid */
4104 return 7;
4105}
4106
4107static WORD HTTP_ParseMonth(LPCWSTR month)
4108{
4109 static const WCHAR jan[] = { 'j','a','n',0 };
4110 static const WCHAR feb[] = { 'f','e','b',0 };
4111 static const WCHAR mar[] = { 'm','a','r',0 };
4112 static const WCHAR apr[] = { 'a','p','r',0 };
4113 static const WCHAR may[] = { 'm','a','y',0 };
4114 static const WCHAR jun[] = { 'j','u','n',0 };
4115 static const WCHAR jul[] = { 'j','u','l',0 };
4116 static const WCHAR aug[] = { 'a','u','g',0 };
4117 static const WCHAR sep[] = { 's','e','p',0 };
4118 static const WCHAR oct[] = { 'o','c','t',0 };
4119 static const WCHAR nov[] = { 'n','o','v',0 };
4120 static const WCHAR dec[] = { 'd','e','c',0 };
4121
4122 if (!strcmpiW(month, jan)) return 1;
4123 if (!strcmpiW(month, feb)) return 2;
4124 if (!strcmpiW(month, mar)) return 3;
4125 if (!strcmpiW(month, apr)) return 4;
4126 if (!strcmpiW(month, may)) return 5;
4127 if (!strcmpiW(month, jun)) return 6;
4128 if (!strcmpiW(month, jul)) return 7;
4129 if (!strcmpiW(month, aug)) return 8;
4130 if (!strcmpiW(month, sep)) return 9;
4131 if (!strcmpiW(month, oct)) return 10;
4132 if (!strcmpiW(month, nov)) return 11;
4133 if (!strcmpiW(month, dec)) return 12;
4134 /* Invalid */
4135 return 0;
4136}
4137
Juan Lang28e92292011-03-04 11:43:54 -08004138/* Parses the string pointed to by *str, assumed to be a 24-hour time HH:MM:SS,
4139 * optionally preceded by whitespace.
4140 * Upon success, returns TRUE, sets the wHour, wMinute, and wSecond fields of
4141 * st, and sets *str to the first character after the time format.
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004142 */
Juan Lang28e92292011-03-04 11:43:54 -08004143static BOOL HTTP_ParseTime(SYSTEMTIME *st, LPCWSTR *str)
4144{
4145 LPCWSTR ptr = *str;
4146 WCHAR *nextPtr;
4147 unsigned long num;
4148
4149 while (isspaceW(*ptr))
4150 ptr++;
4151
4152 num = strtoulW(ptr, &nextPtr, 10);
4153 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4154 {
4155 ERR("unexpected time format %s\n", debugstr_w(ptr));
4156 return FALSE;
4157 }
4158 if (num > 23)
4159 {
4160 ERR("unexpected hour in time format %s\n", debugstr_w(ptr));
4161 return FALSE;
4162 }
4163 ptr = nextPtr + 1;
4164 st->wHour = (WORD)num;
4165 num = strtoulW(ptr, &nextPtr, 10);
4166 if (!nextPtr || nextPtr <= ptr || *nextPtr != ':')
4167 {
4168 ERR("unexpected time format %s\n", debugstr_w(ptr));
4169 return FALSE;
4170 }
4171 if (num > 59)
4172 {
4173 ERR("unexpected minute in time format %s\n", debugstr_w(ptr));
4174 return FALSE;
4175 }
4176 ptr = nextPtr + 1;
4177 st->wMinute = (WORD)num;
4178 num = strtoulW(ptr, &nextPtr, 10);
4179 if (!nextPtr || nextPtr <= ptr)
4180 {
4181 ERR("unexpected time format %s\n", debugstr_w(ptr));
4182 return FALSE;
4183 }
4184 if (num > 59)
4185 {
4186 ERR("unexpected second in time format %s\n", debugstr_w(ptr));
4187 return FALSE;
4188 }
4189 ptr = nextPtr + 1;
4190 *str = ptr;
4191 st->wSecond = (WORD)num;
4192 return TRUE;
4193}
4194
4195static BOOL HTTP_ParseDateAsAsctime(LPCWSTR value, FILETIME *ft)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004196{
4197 static const WCHAR gmt[]= { 'G','M','T',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004198 WCHAR day[4], *dayPtr, month[4], *monthPtr, *nextPtr;
4199 LPCWSTR ptr;
4200 SYSTEMTIME st = { 0 };
4201 unsigned long num;
4202
4203 for (ptr = value, dayPtr = day; *ptr && !isspaceW(*ptr) &&
4204 dayPtr - day < sizeof(day) / sizeof(day[0]) - 1; ptr++, dayPtr++)
4205 *dayPtr = *ptr;
4206 *dayPtr = 0;
Juan Langaeca2f92011-10-21 22:55:14 -07004207 st.wDayOfWeek = HTTP_ParseWkday(day);
Juan Lang28e92292011-03-04 11:43:54 -08004208 if (st.wDayOfWeek >= 7)
4209 {
4210 ERR("unexpected weekday %s\n", debugstr_w(day));
4211 return FALSE;
4212 }
4213
4214 while (isspaceW(*ptr))
4215 ptr++;
4216
4217 for (monthPtr = month; !isspace(*ptr) &&
4218 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4219 monthPtr++, ptr++)
4220 *monthPtr = *ptr;
4221 *monthPtr = 0;
4222 st.wMonth = HTTP_ParseMonth(month);
4223 if (!st.wMonth || st.wMonth > 12)
4224 {
4225 ERR("unexpected month %s\n", debugstr_w(month));
4226 return FALSE;
4227 }
4228
4229 while (isspaceW(*ptr))
4230 ptr++;
4231
4232 num = strtoulW(ptr, &nextPtr, 10);
4233 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4234 {
4235 ERR("unexpected day %s\n", debugstr_w(ptr));
4236 return FALSE;
4237 }
4238 ptr = nextPtr;
4239 st.wDay = (WORD)num;
4240
4241 while (isspaceW(*ptr))
4242 ptr++;
4243
4244 if (!HTTP_ParseTime(&st, &ptr))
4245 return FALSE;
4246
4247 while (isspaceW(*ptr))
4248 ptr++;
4249
4250 num = strtoulW(ptr, &nextPtr, 10);
4251 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4252 {
4253 ERR("unexpected year %s\n", debugstr_w(ptr));
4254 return FALSE;
4255 }
4256 ptr = nextPtr;
4257 st.wYear = (WORD)num;
4258
4259 while (isspaceW(*ptr))
4260 ptr++;
4261
4262 /* asctime() doesn't report a timezone, but some web servers do, so accept
4263 * with or without GMT.
4264 */
4265 if (*ptr && strcmpW(ptr, gmt))
4266 {
4267 ERR("unexpected timezone %s\n", debugstr_w(ptr));
4268 return FALSE;
4269 }
4270 return SystemTimeToFileTime(&st, ft);
4271}
4272
4273static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft)
4274{
4275 static const WCHAR gmt[]= { 'G','M','T',0 };
4276 WCHAR *nextPtr, day[4], month[4], *monthPtr;
4277 LPCWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004278 unsigned long num;
Juan Langb9673bc2011-03-07 13:13:11 -08004279 SYSTEMTIME st = { 0 };
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004280
4281 ptr = strchrW(value, ',');
4282 if (!ptr)
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004283 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004284 if (ptr - value != 3)
4285 {
Juan Langaeca2f92011-10-21 22:55:14 -07004286 WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004287 return FALSE;
4288 }
4289 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4290 day[3] = 0;
Juan Langaeca2f92011-10-21 22:55:14 -07004291 st.wDayOfWeek = HTTP_ParseWkday(day);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004292 if (st.wDayOfWeek > 6)
4293 {
Juan Langaeca2f92011-10-21 22:55:14 -07004294 WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004295 return FALSE;
4296 }
4297 ptr++;
4298
4299 while (isspaceW(*ptr))
4300 ptr++;
4301
4302 num = strtoulW(ptr, &nextPtr, 10);
4303 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4304 {
Juan Langaeca2f92011-10-21 22:55:14 -07004305 WARN("unexpected day %s\n", debugstr_w(value));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004306 return FALSE;
4307 }
4308 ptr = nextPtr;
4309 st.wDay = (WORD)num;
4310
4311 while (isspaceW(*ptr))
4312 ptr++;
4313
4314 for (monthPtr = month; !isspace(*ptr) &&
4315 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4316 monthPtr++, ptr++)
4317 *monthPtr = *ptr;
4318 *monthPtr = 0;
4319 st.wMonth = HTTP_ParseMonth(month);
4320 if (!st.wMonth || st.wMonth > 12)
4321 {
Juan Langaeca2f92011-10-21 22:55:14 -07004322 WARN("unexpected month %s\n", debugstr_w(month));
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004323 return FALSE;
4324 }
4325
4326 while (isspaceW(*ptr))
4327 ptr++;
4328
4329 num = strtoulW(ptr, &nextPtr, 10);
4330 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4331 {
4332 ERR("unexpected year %s\n", debugstr_w(value));
4333 return FALSE;
4334 }
4335 ptr = nextPtr;
4336 st.wYear = (WORD)num;
4337
Juan Lang28e92292011-03-04 11:43:54 -08004338 if (!HTTP_ParseTime(&st, &ptr))
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004339 return FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004340
4341 while (isspaceW(*ptr))
4342 ptr++;
4343
4344 if (strcmpW(ptr, gmt))
4345 {
4346 ERR("unexpected time zone %s\n", debugstr_w(ptr));
4347 return FALSE;
4348 }
4349 return SystemTimeToFileTime(&st, ft);
4350}
4351
Juan Langaeca2f92011-10-21 22:55:14 -07004352static WORD HTTP_ParseWeekday(LPCWSTR day)
4353{
4354 static const WCHAR days[7][10] = {{ 's','u','n','d','a','y',0 },
4355 { 'm','o','n','d','a','y',0 },
4356 { 't','u','e','s','d','a','y',0 },
4357 { 'w','e','d','n','e','s','d','a','y',0 },
4358 { 't','h','u','r','s','d','a','y',0 },
4359 { 'f','r','i','d','a','y',0 },
4360 { 's','a','t','u','r','d','a','y',0 }};
4361 int i;
4362 for (i = 0; i < sizeof(days)/sizeof(*days); i++)
4363 if (!strcmpiW(day, days[i]))
4364 return i;
4365
4366 /* Invalid */
4367 return 7;
4368}
4369
4370static BOOL HTTP_ParseRfc850Date(LPCWSTR value, FILETIME *ft)
4371{
4372 static const WCHAR gmt[]= { 'G','M','T',0 };
4373 WCHAR *nextPtr, day[10], month[4], *monthPtr;
4374 LPCWSTR ptr;
4375 unsigned long num;
4376 SYSTEMTIME st = { 0 };
4377
4378 ptr = strchrW(value, ',');
4379 if (!ptr)
4380 return FALSE;
4381 if (ptr - value == 3)
4382 {
4383 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4384 day[3] = 0;
4385 st.wDayOfWeek = HTTP_ParseWkday(day);
4386 if (st.wDayOfWeek > 6)
4387 {
4388 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4389 return FALSE;
4390 }
4391 }
Juan Langad3e22d2011-10-24 13:21:10 -07004392 else if (ptr - value < sizeof(day) / sizeof(day[0]))
Juan Langaeca2f92011-10-21 22:55:14 -07004393 {
4394 memcpy(day, value, (ptr - value) * sizeof(WCHAR));
4395 day[ptr - value + 1] = 0;
4396 st.wDayOfWeek = HTTP_ParseWeekday(day);
4397 if (st.wDayOfWeek > 6)
4398 {
4399 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4400 return FALSE;
4401 }
4402 }
4403 else
4404 {
4405 ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value));
4406 return FALSE;
4407 }
4408 ptr++;
4409
4410 while (isspaceW(*ptr))
4411 ptr++;
4412
4413 num = strtoulW(ptr, &nextPtr, 10);
4414 if (!nextPtr || nextPtr <= ptr || !num || num > 31)
4415 {
4416 ERR("unexpected day %s\n", debugstr_w(value));
4417 return FALSE;
4418 }
4419 ptr = nextPtr;
4420 st.wDay = (WORD)num;
4421
4422 if (*ptr != '-')
4423 {
4424 ERR("unexpected month format %s\n", debugstr_w(ptr));
4425 return FALSE;
4426 }
4427 ptr++;
4428
4429 for (monthPtr = month; *ptr != '-' &&
4430 monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
4431 monthPtr++, ptr++)
4432 *monthPtr = *ptr;
4433 *monthPtr = 0;
4434 st.wMonth = HTTP_ParseMonth(month);
4435 if (!st.wMonth || st.wMonth > 12)
4436 {
4437 ERR("unexpected month %s\n", debugstr_w(month));
4438 return FALSE;
4439 }
4440
4441 if (*ptr != '-')
4442 {
4443 ERR("unexpected year format %s\n", debugstr_w(ptr));
4444 return FALSE;
4445 }
4446 ptr++;
4447
4448 num = strtoulW(ptr, &nextPtr, 10);
4449 if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827)
4450 {
4451 ERR("unexpected year %s\n", debugstr_w(value));
4452 return FALSE;
4453 }
4454 ptr = nextPtr;
4455 st.wYear = (WORD)num;
4456
4457 if (!HTTP_ParseTime(&st, &ptr))
4458 return FALSE;
4459
4460 while (isspaceW(*ptr))
4461 ptr++;
4462
4463 if (strcmpW(ptr, gmt))
4464 {
4465 ERR("unexpected time zone %s\n", debugstr_w(ptr));
4466 return FALSE;
4467 }
4468 return SystemTimeToFileTime(&st, ft);
4469}
4470
Juan Lang28e92292011-03-04 11:43:54 -08004471static BOOL HTTP_ParseDate(LPCWSTR value, FILETIME *ft)
4472{
Juan Langd797e5f2011-05-13 06:47:49 -07004473 static const WCHAR zero[] = { '0',0 };
Juan Lang28e92292011-03-04 11:43:54 -08004474 BOOL ret;
4475
Juan Langd797e5f2011-05-13 06:47:49 -07004476 if (!strcmpW(value, zero))
4477 {
4478 ft->dwLowDateTime = ft->dwHighDateTime = 0;
4479 ret = TRUE;
4480 }
4481 else if (strchrW(value, ','))
Juan Langaeca2f92011-10-21 22:55:14 -07004482 {
Juan Lang28e92292011-03-04 11:43:54 -08004483 ret = HTTP_ParseRfc1123Date(value, ft);
Juan Langaeca2f92011-10-21 22:55:14 -07004484 if (!ret)
4485 {
4486 ret = HTTP_ParseRfc850Date(value, ft);
4487 if (!ret)
4488 ERR("unexpected date format %s\n", debugstr_w(value));
4489 }
4490 }
Juan Lang28e92292011-03-04 11:43:54 -08004491 else
4492 {
4493 ret = HTTP_ParseDateAsAsctime(value, ft);
4494 if (!ret)
4495 ERR("unexpected date format %s\n", debugstr_w(value));
4496 }
4497 return ret;
4498}
4499
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004500static void HTTP_ProcessExpires(http_request_t *request)
4501{
Juan Langab16c752011-03-03 10:54:07 -08004502 BOOL expirationFound = FALSE;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004503 int headerIndex;
4504
Juan Lang488c2d02011-03-03 10:54:47 -08004505 /* Look for a Cache-Control header with a max-age directive, as it takes
4506 * precedence over the Expires header.
4507 */
4508 headerIndex = HTTP_GetCustomHeaderIndex(request, szCache_Control, 0, FALSE);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004509 if (headerIndex != -1)
4510 {
Juan Lang488c2d02011-03-03 10:54:47 -08004511 LPHTTPHEADERW ccHeader = &request->custHeaders[headerIndex];
4512 LPWSTR ptr;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004513
Juan Lang488c2d02011-03-03 10:54:47 -08004514 for (ptr = ccHeader->lpszValue; ptr && *ptr; )
Juan Langab16c752011-03-03 10:54:07 -08004515 {
Juan Lang488c2d02011-03-03 10:54:47 -08004516 LPWSTR comma = strchrW(ptr, ','), end, equal;
4517
4518 if (comma)
4519 end = comma;
4520 else
4521 end = ptr + strlenW(ptr);
4522 for (equal = end - 1; equal > ptr && *equal != '='; equal--)
4523 ;
4524 if (*equal == '=')
4525 {
4526 static const WCHAR max_age[] = {
4527 'm','a','x','-','a','g','e',0 };
4528
4529 if (!strncmpiW(ptr, max_age, equal - ptr - 1))
4530 {
4531 LPWSTR nextPtr;
4532 unsigned long age;
4533
4534 age = strtoulW(equal + 1, &nextPtr, 10);
4535 if (nextPtr > equal + 1)
4536 {
4537 LARGE_INTEGER ft;
4538
4539 NtQuerySystemTime( &ft );
4540 /* Age is in seconds, FILETIME resolution is in
4541 * 100 nanosecond intervals.
4542 */
4543 ft.QuadPart += age * (ULONGLONG)1000000;
4544 request->expires.dwLowDateTime = ft.u.LowPart;
4545 request->expires.dwHighDateTime = ft.u.HighPart;
4546 expirationFound = TRUE;
4547 }
4548 }
4549 }
4550 if (comma)
4551 {
4552 ptr = comma + 1;
4553 while (isspaceW(*ptr))
4554 ptr++;
4555 }
4556 else
4557 ptr = NULL;
4558 }
4559 }
4560 if (!expirationFound)
4561 {
4562 headerIndex = HTTP_GetCustomHeaderIndex(request, szExpires, 0, FALSE);
4563 if (headerIndex != -1)
4564 {
4565 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4566 FILETIME ft;
4567
4568 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4569 {
4570 expirationFound = TRUE;
4571 request->expires = ft;
4572 }
Juan Langab16c752011-03-03 10:54:07 -08004573 }
4574 }
4575 if (!expirationFound)
4576 {
Juan Lang2d323432011-03-03 10:54:07 -08004577 LARGE_INTEGER t;
Juan Langab16c752011-03-03 10:54:07 -08004578
4579 /* With no known age, default to 10 minutes until expiration. */
Juan Lang2d323432011-03-03 10:54:07 -08004580 NtQuerySystemTime( &t );
4581 t.QuadPart += 10 * 60 * (ULONGLONG)10000000;
4582 request->expires.dwLowDateTime = t.u.LowPart;
4583 request->expires.dwHighDateTime = t.u.HighPart;
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004584 }
4585}
4586
Juan Lang28e92292011-03-04 11:43:54 -08004587static void HTTP_ProcessLastModified(http_request_t *request)
4588{
4589 int headerIndex;
4590
4591 headerIndex = HTTP_GetCustomHeaderIndex(request, szLast_Modified, 0, FALSE);
4592 if (headerIndex != -1)
4593 {
4594 LPHTTPHEADERW expiresHeader = &request->custHeaders[headerIndex];
4595 FILETIME ft;
4596
4597 if (HTTP_ParseDate(expiresHeader->lpszValue, &ft))
4598 request->last_modified = ft;
4599 }
4600}
4601
Jacek Caban8a1df202011-05-10 09:26:43 +00004602static void http_process_keep_alive(http_request_t *req)
4603{
4604 int index;
4605
4606 index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE);
4607 if(index != -1)
4608 req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive);
4609 else
4610 req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1);
4611}
4612
Juan Lang666353d2011-03-02 10:06:37 -08004613static void HTTP_CacheRequest(http_request_t *request)
4614{
4615 WCHAR url[INTERNET_MAX_URL_LENGTH];
4616 WCHAR cacheFileName[MAX_PATH+1];
4617 BOOL b;
4618
4619 b = HTTP_GetRequestURL(request, url);
4620 if(!b) {
4621 WARN("Could not get URL\n");
4622 return;
4623 }
4624
Juan Lang7685dad2011-03-03 08:55:32 -08004625 b = CreateUrlCacheEntryW(url, request->contentLength, NULL, cacheFileName, 0);
Juan Lang666353d2011-03-02 10:06:37 -08004626 if(b) {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004627 heap_free(request->cacheFile);
Juan Lang666353d2011-03-02 10:06:37 -08004628 CloseHandle(request->hCacheFile);
4629
4630 request->cacheFile = heap_strdupW(cacheFileName);
4631 request->hCacheFile = CreateFileW(request->cacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
4632 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
4633 if(request->hCacheFile == INVALID_HANDLE_VALUE) {
4634 WARN("Could not create file: %u\n", GetLastError());
4635 request->hCacheFile = NULL;
4636 }
4637 }else {
4638 WARN("Could not create cache entry: %08x\n", GetLastError());
4639 }
4640}
4641
Jacek Caban8a1df202011-05-10 09:26:43 +00004642static DWORD open_http_connection(http_request_t *request, BOOL *reusing)
4643{
4644 const BOOL is_https = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) != 0;
Jacek Caban8a1df202011-05-10 09:26:43 +00004645 netconn_t *netconn = NULL;
Jacek Caban8a1df202011-05-10 09:26:43 +00004646 DWORD res;
4647
4648 assert(!request->netconn);
4649 reset_data_stream(request);
4650
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004651 res = HTTP_ResolveName(request);
4652 if(res != ERROR_SUCCESS)
Jacek Caban8a1df202011-05-10 09:26:43 +00004653 return res;
Jacek Caban8a1df202011-05-10 09:26:43 +00004654
4655 EnterCriticalSection(&connection_pool_cs);
4656
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004657 while(!list_empty(&request->server->conn_pool)) {
4658 netconn = LIST_ENTRY(list_head(&request->server->conn_pool), netconn_t, pool_entry);
Jacek Caban8a1df202011-05-10 09:26:43 +00004659 list_remove(&netconn->pool_entry);
4660
4661 if(NETCON_is_alive(netconn))
4662 break;
4663
4664 TRACE("connection %p closed during idle\n", netconn);
4665 free_netconn(netconn);
4666 netconn = NULL;
4667 }
4668
4669 LeaveCriticalSection(&connection_pool_cs);
4670
4671 if(netconn) {
4672 TRACE("<-- reusing %p netconn\n", netconn);
4673 request->netconn = netconn;
4674 *reusing = TRUE;
4675 return ERROR_SUCCESS;
4676 }
4677
4678 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4679 INTERNET_STATUS_CONNECTING_TO_SERVER,
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004680 request->server->addr_str,
4681 strlen(request->server->addr_str)+1);
Jacek Caban8a1df202011-05-10 09:26:43 +00004682
Jacek Caban868575a2012-05-25 16:51:20 +02004683 res = create_netconn(is_https, request->server, request->security_flags,
4684 (request->hdr.ErrorMask & INTERNET_ERROR_MASK_COMBINED_SEC_CERT) != 0,
4685 request->connect_timeout, &netconn);
Jacek Caban8a1df202011-05-10 09:26:43 +00004686 if(res != ERROR_SUCCESS) {
4687 ERR("create_netconn failed: %u\n", res);
4688 return res;
4689 }
4690
4691 request->netconn = netconn;
4692
4693 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
4694 INTERNET_STATUS_CONNECTED_TO_SERVER,
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004695 request->server->addr_str, strlen(request->server->addr_str)+1);
Jacek Caban8a1df202011-05-10 09:26:43 +00004696
4697 if(is_https) {
4698 /* Note: we differ from Microsoft's WinINet here. they seem to have
4699 * a bug that causes no status callbacks to be sent when starting
4700 * a tunnel to a proxy server using the CONNECT verb. i believe our
4701 * behaviour to be more correct and to not cause any incompatibilities
4702 * because using a secure connection through a proxy server is a rare
4703 * case that would be hard for anyone to depend on */
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004704 if(request->session->appInfo->proxy)
Jacek Caban8a1df202011-05-10 09:26:43 +00004705 res = HTTP_SecureProxyConnect(request);
4706 if(res == ERROR_SUCCESS)
Jacek Caban905ede62012-04-30 14:49:41 +02004707 res = NETCON_secure_connect(request->netconn);
Jacek Caban8a1df202011-05-10 09:26:43 +00004708 }
4709
4710 if(res != ERROR_SUCCESS) {
4711 http_release_netconn(request, FALSE);
4712 return res;
4713 }
4714
4715 *reusing = FALSE;
Jacek Caban3aeb8eb2012-05-25 16:34:24 +02004716 TRACE("Created connection to %s: %p\n", debugstr_w(request->server->name), netconn);
Jacek Caban8a1df202011-05-10 09:26:43 +00004717 return ERROR_SUCCESS;
4718}
4719
Mike McCormacka4969062004-07-04 00:24:47 +00004720/***********************************************************************
Mike McCormacka4e902c2004-03-30 04:36:09 +00004721 * HTTP_HttpSendRequestW (internal)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004722 *
4723 * Sends the specified request to the HTTP server
4724 *
4725 * RETURNS
Juan Langb2ed9c52011-03-02 17:09:45 -08004726 * ERROR_SUCCESS on success
4727 * win32 error code on failure
Ulrich Czekallac2757242000-06-11 20:04:44 +00004728 *
4729 */
Juan Langb49b2432011-03-01 10:59:39 -08004730static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004731 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
4732 DWORD dwContentLength, BOOL bEndRequest)
Ulrich Czekallac2757242000-06-11 20:04:44 +00004733{
4734 INT cnt;
Jacek Cabanc952e812009-12-03 14:48:54 +01004735 BOOL redirected = FALSE;
Mike McCormacka4e902c2004-03-30 04:36:09 +00004736 LPWSTR requestString = NULL;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004737 INT responseLen;
Rob Shearman14fb4182007-01-04 18:21:13 +00004738 BOOL loop_next;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004739 static const WCHAR szPost[] = { 'P','O','S','T',0 };
Hans Leidekker64359c22007-10-28 16:32:46 +01004740 static const WCHAR szContentLength[] =
4741 { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
4742 WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
Jacek Caban36cb1ef2009-11-30 00:14:02 +01004743 DWORD res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00004744
Juan Langb49b2432011-03-01 10:59:39 -08004745 TRACE("--> %p\n", request);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004746
Juan Langb49b2432011-03-01 10:59:39 -08004747 assert(request->hdr.htype == WH_HHTTPREQ);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004748
Jacek Cabanf9791342008-02-13 13:34:05 +01004749 /* if the verb is NULL default to GET */
Juan Lang20980062011-03-01 11:18:22 -08004750 if (!request->verb)
4751 request->verb = heap_strdupW(szGET);
Jacek Cabanf9791342008-02-13 13:34:05 +01004752
Juan Lang20980062011-03-01 11:18:22 -08004753 if (dwContentLength || strcmpW(request->verb, szGET))
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004754 {
4755 sprintfW(contentLengthStr, szContentLength, dwContentLength);
Juan Langb49b2432011-03-01 10:59:39 -08004756 HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
Juan Lang20980062011-03-01 11:18:22 -08004757 request->bytesToWrite = dwContentLength;
Hans Leidekkerb0912d12008-02-02 16:08:28 +01004758 }
Juan Lang20980062011-03-01 11:18:22 -08004759 if (request->session->appInfo->agent)
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004760 {
4761 WCHAR *agent_header;
4762 static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
4763 int len;
4764
Juan Lang20980062011-03-01 11:18:22 -08004765 len = strlenW(request->session->appInfo->agent) + strlenW(user_agent);
Jacek Caban354a74e2011-04-21 13:39:03 +02004766 agent_header = heap_alloc(len * sizeof(WCHAR));
Juan Lang20980062011-03-01 11:18:22 -08004767 sprintfW(agent_header, user_agent, request->session->appInfo->agent);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004768
Juan Langb49b2432011-03-01 10:59:39 -08004769 HTTP_HttpAddRequestHeadersW(request, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004770 heap_free(agent_header);
Hans Leidekkere2f690a2008-05-02 21:59:24 +02004771 }
Juan Langb49b2432011-03-01 10:59:39 -08004772 if (request->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE)
Hans Leidekker34ff5552008-06-23 20:58:25 +02004773 {
4774 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 -08004775 HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Hans Leidekker34ff5552008-06-23 20:58:25 +02004776 }
Juan Lang20980062011-03-01 11:18:22 -08004777 if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost))
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004778 {
4779 static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
4780 ' ','n','o','-','c','a','c','h','e','\r','\n',0};
Juan Langb49b2432011-03-01 10:59:39 -08004781 HTTP_HttpAddRequestHeadersW(request, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
Alexander Morozovad2f53d2008-07-04 14:00:29 +04004782 }
David Hammerton6226f3f2003-08-05 18:31:02 +00004783
Jacek Cabandfa9f4b2012-01-24 17:31:38 +01004784 /* add the headers the caller supplied */
4785 if( lpszHeaders && dwHeaderLength )
4786 HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
4787
David Hammerton852c7ae2003-06-20 23:26:56 +00004788 do
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004789 {
Aric Stewartbe918f42005-11-21 15:17:55 +00004790 DWORD len;
Piotr Cabanee684732010-06-29 12:20:51 +02004791 BOOL reusing_connection;
Mike McCormacka4969062004-07-04 00:24:47 +00004792 char *ascii_req;
4793
Rob Shearman14fb4182007-01-04 18:21:13 +00004794 loop_next = FALSE;
Jacek Cabanc4001172012-07-02 17:15:04 +02004795 reusing_connection = request->netconn != NULL;
Rob Shearman272954b2007-01-04 18:23:17 +00004796
Piotr Caban224af0d2010-05-20 02:35:38 +02004797 if(redirected) {
Juan Lang20980062011-03-01 11:18:22 -08004798 request->contentLength = ~0u;
4799 request->bytesToWrite = 0;
Piotr Caban224af0d2010-05-20 02:35:38 +02004800 }
Rob Shearman14fb4182007-01-04 18:21:13 +00004801
Rob Shearman4319ec62006-12-07 00:53:27 +00004802 if (TRACE_ON(wininet))
4803 {
Juan Langb49b2432011-03-01 10:59:39 -08004804 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Juan Lang20980062011-03-01 11:18:22 -08004805 TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(request->path));
Rob Shearman4319ec62006-12-07 00:53:27 +00004806 }
Nikolas Zimmermann76598822001-10-04 18:12:41 +00004807
Juan Langb49b2432011-03-01 10:59:39 -08004808 HTTP_FixURL(request);
4809 if (request->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION)
Hans Leidekker656a0352008-05-31 21:47:24 +02004810 {
Juan Langb49b2432011-03-01 10:59:39 -08004811 HTTP_ProcessHeader(request, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
Hans Leidekker656a0352008-05-31 21:47:24 +02004812 }
Juan Lang20980062011-03-01 11:18:22 -08004813 HTTP_InsertAuthorization(request, request->authInfo, szAuthorization);
4814 HTTP_InsertAuthorization(request, request->proxyAuthInfo, szProxy_Authorization);
Ulrich Czekallac2757242000-06-11 20:04:44 +00004815
Juan Langb49b2432011-03-01 10:59:39 -08004816 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
4817 HTTP_InsertCookies(request);
Hans Leidekker572b0ba2008-07-19 19:55:39 +02004818
Juan Lang20980062011-03-01 11:18:22 -08004819 if (request->session->appInfo->proxy && request->session->appInfo->proxy[0])
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004820 {
Juan Langb49b2432011-03-01 10:59:39 -08004821 WCHAR *url = HTTP_BuildProxyRequestUrl(request);
Juan Lang20980062011-03-01 11:18:22 -08004822 requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004823 heap_free(url);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004824 }
4825 else
Juan Lang20980062011-03-01 11:18:22 -08004826 requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version);
Hans Leidekker0ffe9f52008-03-30 19:16:52 +01004827
Mike McCormacka4969062004-07-04 00:24:47 +00004828
4829 TRACE("Request header -> %s\n", debugstr_w(requestString) );
Aric Stewartff9b9d42002-06-21 23:59:49 +00004830
Jacek Cabanc4001172012-07-02 17:15:04 +02004831 if (!reusing_connection && (res = open_http_connection(request, &reusing_connection)) != ERROR_SUCCESS)
Jacek Caban8a1df202011-05-10 09:26:43 +00004832 break;
Aric Stewartff9b9d42002-06-21 23:59:49 +00004833
Mike McCormacka4969062004-07-04 00:24:47 +00004834 /* send the request as ASCII, tack on the optional data */
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004835 if (!lpOptional || redirected)
Mike McCormacka4969062004-07-04 00:24:47 +00004836 dwOptionalLength = 0;
4837 len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4838 NULL, 0, NULL, NULL );
Jacek Caban354a74e2011-04-21 13:39:03 +02004839 ascii_req = heap_alloc(len + dwOptionalLength);
Mike McCormacka4969062004-07-04 00:24:47 +00004840 WideCharToMultiByte( CP_ACP, 0, requestString, -1,
4841 ascii_req, len, NULL, NULL );
4842 if( lpOptional )
Mike McCormackf1d7b142004-07-21 19:36:34 +00004843 memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
4844 len = (len + dwOptionalLength - 1);
4845 ascii_req[len] = 0;
Aric Stewart44cbdf22005-10-19 18:28:35 +00004846 TRACE("full request -> %s\n", debugstr_a(ascii_req) );
Mike McCormackf1d7b142004-07-21 19:36:34 +00004847
Juan Langb49b2432011-03-01 10:59:39 -08004848 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004849 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
Mike McCormackf1d7b142004-07-21 19:36:34 +00004850
Hans Leidekker65223932012-01-13 15:15:48 +01004851 NETCON_set_timeout( request->netconn, TRUE, request->send_timeout );
Jacek Caban8a1df202011-05-10 09:26:43 +00004852 res = NETCON_send(request->netconn, ascii_req, len, 0, &cnt);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004853 heap_free( ascii_req );
Jacek Caban8a1df202011-05-10 09:26:43 +00004854 if(res != ERROR_SUCCESS) {
4855 TRACE("send failed: %u\n", res);
4856 if(!reusing_connection)
4857 break;
4858 http_release_netconn(request, FALSE);
4859 loop_next = TRUE;
4860 continue;
4861 }
David Hammerton852c7ae2003-06-20 23:26:56 +00004862
Juan Lang20980062011-03-01 11:18:22 -08004863 request->bytesWritten = dwOptionalLength;
Hans Leidekker0fabf542009-04-08 15:21:28 +02004864
Juan Langb49b2432011-03-01 10:59:39 -08004865 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmande2666f2005-11-29 10:44:05 +01004866 INTERNET_STATUS_REQUEST_SENT,
4867 &len, sizeof(DWORD));
David Hammerton852c7ae2003-06-20 23:26:56 +00004868
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004869 if (bEndRequest)
4870 {
Rob Shearmanac1b5272007-01-04 18:21:49 +00004871 DWORD dwBufferSize;
4872
Juan Langb49b2432011-03-01 10:59:39 -08004873 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004874 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
4875
Juan Langb49b2432011-03-01 10:59:39 -08004876 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Piotr Cabanee684732010-06-29 12:20:51 +02004877 /* FIXME: We should know that connection is closed before sending
4878 * headers. Otherwise wrong callbacks are executed */
4879 if(!responseLen && reusing_connection) {
4880 TRACE("Connection closed by server, reconnecting\n");
Jacek Caban8a1df202011-05-10 09:26:43 +00004881 http_release_netconn(request, FALSE);
Piotr Cabanee684732010-06-29 12:20:51 +02004882 loop_next = TRUE;
4883 continue;
4884 }
Jacek Caban8a1df202011-05-10 09:26:43 +00004885
Juan Langb49b2432011-03-01 10:59:39 -08004886 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004887 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
4888 sizeof(DWORD));
Rob Shearman4319ec62006-12-07 00:53:27 +00004889
Jacek Caban8a1df202011-05-10 09:26:43 +00004890 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08004891 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08004892 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08004893 HTTP_ProcessLastModified(request);
Rob Shearman4319ec62006-12-07 00:53:27 +00004894
Jacek Caban5240e402012-05-03 12:19:47 +02004895 res = set_content_length(request);
Jacek Cabana890e3a2011-05-13 13:48:15 +02004896 if(res != ERROR_SUCCESS)
4897 goto lend;
4898 if(!request->contentLength)
4899 http_release_netconn(request, TRUE);
4900
Juan Langb49b2432011-03-01 10:59:39 -08004901 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
Rob Shearman4319ec62006-12-07 00:53:27 +00004902 {
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004903 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
Rob Shearman9efe0832007-01-12 19:19:18 -06004904 dwBufferSize=sizeof(szNewLocation);
Jacek Caban4cf3f782012-05-03 12:19:58 +02004905 switch(request->status_code) {
4906 case HTTP_STATUS_REDIRECT:
4907 case HTTP_STATUS_MOVED:
4908 case HTTP_STATUS_REDIRECT_KEEP_VERB:
4909 case HTTP_STATUS_REDIRECT_METHOD:
4910 if(HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) != ERROR_SUCCESS)
4911 break;
4912
Hans Leidekker14d4d192011-06-01 11:50:32 +02004913 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
Jacek Caban4cf3f782012-05-03 12:19:58 +02004914 request->status_code != HTTP_STATUS_REDIRECT_KEEP_VERB)
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004915 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004916 heap_free(request->verb);
Juan Lang20980062011-03-01 11:18:22 -08004917 request->verb = heap_strdupW(szGET);
Hans Leidekkerfa4c25d2009-07-22 11:56:33 +02004918 }
Jacek Cabanc4001172012-07-02 17:15:04 +02004919 http_release_netconn(request, drain_content(request, FALSE));
Juan Langb49b2432011-03-01 10:59:39 -08004920 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
Rob Shearman4319ec62006-12-07 00:53:27 +00004921 {
Juan Langb49b2432011-03-01 10:59:39 -08004922 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004923 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
Juan Langb49b2432011-03-01 10:59:39 -08004924 res = HTTP_HandleRedirect(request, new_url);
Jacek Cabana9ecdc62009-12-03 14:49:56 +01004925 if (res == ERROR_SUCCESS)
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004926 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004927 heap_free(requestString);
Alexandre Julliard9ee1b062009-05-04 20:49:15 +02004928 loop_next = TRUE;
4929 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004930 heap_free( new_url );
Rob Shearman4319ec62006-12-07 00:53:27 +00004931 }
Hans Leidekker6bb143a2009-05-06 15:57:56 +02004932 redirected = TRUE;
Rob Shearman4319ec62006-12-07 00:53:27 +00004933 }
4934 }
Juan Langb49b2432011-03-01 10:59:39 -08004935 if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004936 {
Rob Shearman4b507682007-05-21 14:26:26 +01004937 WCHAR szAuthValue[2048];
4938 dwBufferSize=2048;
Jacek Caban4cf3f782012-05-03 12:19:58 +02004939 if (request->status_code == HTTP_STATUS_DENIED)
Rob Shearman4b507682007-05-21 14:26:26 +01004940 {
Juan Langb49b2432011-03-01 10:59:39 -08004941 LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW);
Rob Shearman4b507682007-05-21 14:26:26 +01004942 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004943 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearman4b507682007-05-21 14:26:26 +01004944 {
Juan Langb49b2432011-03-01 10:59:39 -08004945 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004946 &request->authInfo,
4947 request->session->userName,
4948 request->session->password,
Aric Stewartfc508932009-10-12 14:24:18 -05004949 Host->lpszValue))
Rob Shearmancb289692007-06-05 19:49:58 +01004950 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02004951 heap_free(requestString);
Jacek Cabanc4001172012-07-02 17:15:04 +02004952 if(!drain_content(request, TRUE)) {
4953 FIXME("Could not drain content\n");
4954 http_release_netconn(request, FALSE);
4955 }
Rob Shearmancb289692007-06-05 19:49:58 +01004956 loop_next = TRUE;
4957 break;
4958 }
4959 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004960
4961 if(!loop_next) {
4962 TRACE("Cleaning wrong authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004963 destroy_authinfo(request->authInfo);
4964 request->authInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004965 }
Rob Shearmancb289692007-06-05 19:49:58 +01004966 }
Jacek Caban4cf3f782012-05-03 12:19:58 +02004967 if (request->status_code == HTTP_STATUS_PROXY_AUTH_REQ)
Rob Shearmancb289692007-06-05 19:49:58 +01004968 {
4969 DWORD dwIndex = 0;
Juan Langb49b2432011-03-01 10:59:39 -08004970 while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
Rob Shearmancb289692007-06-05 19:49:58 +01004971 {
Juan Langb49b2432011-03-01 10:59:39 -08004972 if (HTTP_DoAuthorization(request, szAuthValue,
Juan Lang20980062011-03-01 11:18:22 -08004973 &request->proxyAuthInfo,
4974 request->session->appInfo->proxyUsername,
4975 request->session->appInfo->proxyPassword,
Aric Stewartfc508932009-10-12 14:24:18 -05004976 NULL))
Rob Shearman4b507682007-05-21 14:26:26 +01004977 {
Jacek Cabanc4001172012-07-02 17:15:04 +02004978 if(!drain_content(request, TRUE)) {
4979 FIXME("Could not drain content\n");
4980 http_release_netconn(request, FALSE);
4981 }
Rob Shearman4b507682007-05-21 14:26:26 +01004982 loop_next = TRUE;
4983 break;
4984 }
4985 }
Piotr Caban98fb7472010-07-17 14:08:11 +02004986
4987 if(!loop_next) {
4988 TRACE("Cleaning wrong proxy authorization data\n");
Juan Lang20980062011-03-01 11:18:22 -08004989 destroy_authinfo(request->proxyAuthInfo);
4990 request->proxyAuthInfo = NULL;
Piotr Caban98fb7472010-07-17 14:08:11 +02004991 }
Rob Shearman4b507682007-05-21 14:26:26 +01004992 }
4993 }
Robert Shearmanf6252cf2005-11-30 12:31:22 +01004994 }
4995 else
Jacek Cabanc952e812009-12-03 14:48:54 +01004996 res = ERROR_SUCCESS;
David Hammerton852c7ae2003-06-20 23:26:56 +00004997 }
4998 while (loop_next);
Aric Stewartff9b9d42002-06-21 23:59:49 +00004999
Juan Lang666353d2011-03-02 10:06:37 -08005000 if(res == ERROR_SUCCESS)
5001 HTTP_CacheRequest(request);
Jacek Caband7a49e82008-02-13 13:32:49 +01005002
Ulrich Czekallac2757242000-06-11 20:04:44 +00005003lend:
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005004 heap_free(requestString);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005005
Alberto Massaribc8bd722002-12-06 23:20:31 +00005006 /* TODO: send notification for P3P header */
Vincent Béron9a624912002-05-31 23:06:46 +00005007
Juan Lang20980062011-03-01 11:18:22 -08005008 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Hans Leidekker3a711fb2009-04-08 15:22:26 +02005009 {
Jacek Caban8e37ed52011-06-10 14:47:16 +02005010 if (res == ERROR_SUCCESS) {
Andy Claytonda110752011-11-23 08:45:44 -06005011 if(bEndRequest && request->contentLength && request->bytesWritten == request->bytesToWrite)
Jacek Caban8e37ed52011-06-10 14:47:16 +02005012 HTTP_ReceiveRequestData(request, TRUE);
5013 else
5014 send_request_complete(request,
5015 request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0);
5016 }else {
5017 send_request_complete(request, 0, res);
5018 }
Jacek Caban12931062009-01-13 00:28:25 +01005019 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005020
5021 TRACE("<--\n");
Jacek Cabanc952e812009-12-03 14:48:54 +01005022 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005023}
5024
Ulrich Czekallac2757242000-06-11 20:04:44 +00005025/***********************************************************************
Jacek Caban34fcbb52009-11-30 20:01:17 +01005026 *
5027 * Helper functions for the HttpSendRequest(Ex) functions
5028 *
5029 */
5030static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
5031{
5032 struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08005033 http_request_t *request = (http_request_t*) workRequest->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005034
Juan Langb49b2432011-03-01 10:59:39 -08005035 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005036
Juan Langb49b2432011-03-01 10:59:39 -08005037 HTTP_HttpSendRequestW(request, req->lpszHeader,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005038 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
5039 req->dwContentLength, req->bEndRequest);
5040
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005041 heap_free(req->lpszHeader);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005042}
5043
5044
Juan Langb49b2432011-03-01 10:59:39 -08005045static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005046{
Jacek Caban34fcbb52009-11-30 20:01:17 +01005047 DWORD dwBufferSize;
Jacek Caban797a17b2012-05-03 12:20:10 +02005048 INT responseLen;
Jacek Caban741b6612009-12-03 14:49:29 +01005049 DWORD res = ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005050
Jacek Caban892d3cd2011-12-07 16:40:27 +01005051 if(!request->netconn) {
5052 WARN("Not connected\n");
5053 send_request_complete(request, 0, ERROR_INTERNET_OPERATION_CANCELLED);
5054 return ERROR_INTERNET_OPERATION_CANCELLED;
5055 }
5056
Juan Langb49b2432011-03-01 10:59:39 -08005057 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005058 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
5059
Juan Langb49b2432011-03-01 10:59:39 -08005060 responseLen = HTTP_GetResponseHeaders(request, TRUE);
Jacek Caban741b6612009-12-03 14:49:29 +01005061 if (!responseLen)
5062 res = ERROR_HTTP_HEADER_NOT_FOUND;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005063
Juan Langb49b2432011-03-01 10:59:39 -08005064 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005065 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
5066
5067 /* process cookies here. Is this right? */
Jacek Caban8a1df202011-05-10 09:26:43 +00005068 http_process_keep_alive(request);
Juan Langb49b2432011-03-01 10:59:39 -08005069 HTTP_ProcessCookies(request);
Juan Lang0b5ea6f2011-03-03 11:20:11 -08005070 HTTP_ProcessExpires(request);
Juan Lang28e92292011-03-04 11:43:54 -08005071 HTTP_ProcessLastModified(request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005072
Jacek Caban5240e402012-05-03 12:19:47 +02005073 if ((res = set_content_length(request)) == ERROR_SUCCESS) {
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005074 if(!request->contentLength)
Jacek Caban8a1df202011-05-10 09:26:43 +00005075 http_release_netconn(request, TRUE);
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005076 }
Jacek Caban34fcbb52009-11-30 20:01:17 +01005077
Jacek Cabanccd11eb2011-04-02 15:20:33 +02005078 if (res == ERROR_SUCCESS && !(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
Jacek Caban34fcbb52009-11-30 20:01:17 +01005079 {
Jacek Caban797a17b2012-05-03 12:20:10 +02005080 switch(request->status_code) {
5081 case HTTP_STATUS_REDIRECT:
5082 case HTTP_STATUS_MOVED:
5083 case HTTP_STATUS_REDIRECT_METHOD:
5084 case HTTP_STATUS_REDIRECT_KEEP_VERB: {
Jacek Caban34fcbb52009-11-30 20:01:17 +01005085 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
5086 dwBufferSize=sizeof(szNewLocation);
Jacek Caban797a17b2012-05-03 12:20:10 +02005087 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) != ERROR_SUCCESS)
5088 break;
5089
5090 if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
5091 request->status_code != HTTP_STATUS_REDIRECT_KEEP_VERB)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005092 {
Jacek Caban797a17b2012-05-03 12:20:10 +02005093 heap_free(request->verb);
5094 request->verb = heap_strdupW(szGET);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005095 }
Jacek Cabanc4001172012-07-02 17:15:04 +02005096 http_release_netconn(request, drain_content(request, FALSE));
Jacek Caban797a17b2012-05-03 12:20:10 +02005097 if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
5098 {
5099 INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
5100 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
5101 res = HTTP_HandleRedirect(request, new_url);
5102 if (res == ERROR_SUCCESS)
5103 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE);
5104 heap_free( new_url );
5105 }
5106 }
Jacek Caban34fcbb52009-11-30 20:01:17 +01005107 }
5108 }
5109
Jacek Cabanc0293df2011-06-10 14:47:04 +02005110 if (res == ERROR_SUCCESS && request->contentLength)
Jacek Caban685daf22011-03-17 01:01:49 +01005111 HTTP_ReceiveRequestData(request, TRUE);
Jacek Cabanc0293df2011-06-10 14:47:04 +02005112 else
Jacek Caban8e37ed52011-06-10 14:47:16 +02005113 send_request_complete(request, res == ERROR_SUCCESS, res);
Jacek Caban685daf22011-03-17 01:01:49 +01005114
Jacek Caban741b6612009-12-03 14:49:29 +01005115 return res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005116}
5117
5118/***********************************************************************
5119 * HttpEndRequestA (WININET.@)
5120 *
5121 * Ends an HTTP request that was started by HttpSendRequestEx
5122 *
5123 * RETURNS
5124 * TRUE if successful
5125 * FALSE on failure
5126 *
5127 */
5128BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
5129 LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
5130{
5131 TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
5132
5133 if (lpBuffersOut)
5134 {
Jacek Cabane1958a62009-12-21 13:58:18 +01005135 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005136 return FALSE;
5137 }
5138
5139 return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
5140}
5141
5142static void AsyncHttpEndRequestProc(WORKREQUEST *work)
5143{
5144 struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
Juan Langb49b2432011-03-01 10:59:39 -08005145 http_request_t *request = (http_request_t*)work->hdr;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005146
Juan Langb49b2432011-03-01 10:59:39 -08005147 TRACE("%p\n", request);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005148
Juan Langb49b2432011-03-01 10:59:39 -08005149 HTTP_HttpEndRequestW(request, req->dwFlags, req->dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005150}
5151
5152/***********************************************************************
5153 * HttpEndRequestW (WININET.@)
5154 *
5155 * Ends an HTTP request that was started by HttpSendRequestEx
5156 *
5157 * RETURNS
5158 * TRUE if successful
5159 * FALSE on failure
5160 *
5161 */
5162BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
5163 LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
5164{
Juan Langb49b2432011-03-01 10:59:39 -08005165 http_request_t *request;
Jacek Caban741b6612009-12-03 14:49:29 +01005166 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005167
Jacek Cabanc0293df2011-06-10 14:47:04 +02005168 TRACE("%p %p %x %lx -->\n", hRequest, lpBuffersOut, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005169
5170 if (lpBuffersOut)
5171 {
Jacek Caban741b6612009-12-03 14:49:29 +01005172 SetLastError(ERROR_INVALID_PARAMETER);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005173 return FALSE;
5174 }
5175
Juan Langb49b2432011-03-01 10:59:39 -08005176 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005177
Juan Langb49b2432011-03-01 10:59:39 -08005178 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005179 {
Jacek Caban741b6612009-12-03 14:49:29 +01005180 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
Juan Langb49b2432011-03-01 10:59:39 -08005181 if (request)
5182 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005183 return FALSE;
5184 }
Juan Langb49b2432011-03-01 10:59:39 -08005185 request->hdr.dwFlags |= dwFlags;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005186
Juan Lang20980062011-03-01 11:18:22 -08005187 if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005188 {
5189 WORKREQUEST work;
Juan Langb49b2432011-03-01 10:59:39 -08005190 struct WORKREQ_HTTPENDREQUESTW *work_endrequest;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005191
5192 work.asyncproc = AsyncHttpEndRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005193 work.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005194
Juan Langb49b2432011-03-01 10:59:39 -08005195 work_endrequest = &work.u.HttpEndRequestW;
5196 work_endrequest->dwFlags = dwFlags;
5197 work_endrequest->dwContext = dwContext;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005198
5199 INTERNET_AsyncCall(&work);
Jacek Caban741b6612009-12-03 14:49:29 +01005200 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005201 }
5202 else
Juan Langb49b2432011-03-01 10:59:39 -08005203 res = HTTP_HttpEndRequestW(request, dwFlags, dwContext);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005204
Juan Langb49b2432011-03-01 10:59:39 -08005205 WININET_Release( &request->hdr );
Jacek Caban741b6612009-12-03 14:49:29 +01005206 TRACE("%u <--\n", res);
5207 if(res != ERROR_SUCCESS)
5208 SetLastError(res);
5209 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005210}
5211
5212/***********************************************************************
5213 * HttpSendRequestExA (WININET.@)
5214 *
5215 * Sends the specified request to the HTTP server and allows chunked
5216 * transfers.
5217 *
5218 * RETURNS
5219 * Success: TRUE
5220 * Failure: FALSE, call GetLastError() for more information.
5221 */
5222BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
5223 LPINTERNET_BUFFERSA lpBuffersIn,
5224 LPINTERNET_BUFFERSA lpBuffersOut,
5225 DWORD dwFlags, DWORD_PTR dwContext)
5226{
5227 INTERNET_BUFFERSW BuffersInW;
5228 BOOL rc = FALSE;
5229 DWORD headerlen;
5230 LPWSTR header = NULL;
5231
5232 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5233 lpBuffersOut, dwFlags, dwContext);
5234
5235 if (lpBuffersIn)
5236 {
5237 BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
5238 if (lpBuffersIn->lpcszHeader)
5239 {
5240 headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
5241 lpBuffersIn->dwHeadersLength,0,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005242 header = heap_alloc(headerlen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005243 if (!(BuffersInW.lpcszHeader = header))
5244 {
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005245 SetLastError(ERROR_OUTOFMEMORY);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005246 return FALSE;
5247 }
5248 BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
5249 lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
5250 header, headerlen);
5251 }
5252 else
5253 BuffersInW.lpcszHeader = NULL;
5254 BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
5255 BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
5256 BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
5257 BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
5258 BuffersInW.Next = NULL;
5259 }
5260
5261 rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
5262
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005263 heap_free(header);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005264 return rc;
5265}
5266
5267/***********************************************************************
5268 * HttpSendRequestExW (WININET.@)
5269 *
5270 * Sends the specified request to the HTTP server and allows chunked
5271 * transfers
5272 *
5273 * RETURNS
5274 * Success: TRUE
5275 * Failure: FALSE, call GetLastError() for more information.
5276 */
5277BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
5278 LPINTERNET_BUFFERSW lpBuffersIn,
5279 LPINTERNET_BUFFERSW lpBuffersOut,
5280 DWORD dwFlags, DWORD_PTR dwContext)
5281{
Juan Langb49b2432011-03-01 10:59:39 -08005282 http_request_t *request;
5283 http_session_t *session;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005284 appinfo_t *hIC;
Jacek Cabanc952e812009-12-03 14:48:54 +01005285 DWORD res;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005286
5287 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
5288 lpBuffersOut, dwFlags, dwContext);
5289
Juan Langb49b2432011-03-01 10:59:39 -08005290 request = (http_request_t*) get_handle_object( hRequest );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005291
Juan Langb49b2432011-03-01 10:59:39 -08005292 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005293 {
Jacek Cabanc952e812009-12-03 14:48:54 +01005294 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005295 goto lend;
5296 }
5297
Juan Lang20980062011-03-01 11:18:22 -08005298 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005299 assert(session->hdr.htype == WH_HHTTPSESSION);
Juan Lang8e050392011-03-01 11:02:14 -08005300 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005301 assert(hIC->hdr.htype == WH_HINIT);
5302
5303 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5304 {
5305 WORKREQUEST workRequest;
5306 struct WORKREQ_HTTPSENDREQUESTW *req;
5307
5308 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005309 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005310 req = &workRequest.u.HttpSendRequestW;
5311 if (lpBuffersIn)
5312 {
5313 DWORD size = 0;
5314
5315 if (lpBuffersIn->lpcszHeader)
5316 {
5317 if (lpBuffersIn->dwHeadersLength == ~0u)
5318 size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
5319 else
5320 size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
5321
Jacek Caban354a74e2011-04-21 13:39:03 +02005322 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005323 memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
5324 }
5325 else req->lpszHeader = NULL;
5326
5327 req->dwHeaderLength = size / sizeof(WCHAR);
5328 req->lpOptional = lpBuffersIn->lpvBuffer;
5329 req->dwOptionalLength = lpBuffersIn->dwBufferLength;
5330 req->dwContentLength = lpBuffersIn->dwBufferTotal;
5331 }
5332 else
5333 {
5334 req->lpszHeader = NULL;
5335 req->dwHeaderLength = 0;
5336 req->lpOptional = NULL;
5337 req->dwOptionalLength = 0;
5338 req->dwContentLength = 0;
5339 }
5340
5341 req->bEndRequest = FALSE;
5342
5343 INTERNET_AsyncCall(&workRequest);
5344 /*
5345 * This is from windows.
5346 */
Jacek Cabanc952e812009-12-03 14:48:54 +01005347 res = ERROR_IO_PENDING;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005348 }
5349 else
5350 {
5351 if (lpBuffersIn)
Juan Langb49b2432011-03-01 10:59:39 -08005352 res = HTTP_HttpSendRequestW(request, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005353 lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
5354 lpBuffersIn->dwBufferTotal, FALSE);
5355 else
Juan Langb49b2432011-03-01 10:59:39 -08005356 res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, FALSE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005357 }
5358
5359lend:
Juan Langb49b2432011-03-01 10:59:39 -08005360 if ( request )
5361 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005362
5363 TRACE("<---\n");
Hans Leidekker68453a52009-12-21 11:13:44 +01005364 SetLastError(res);
Jacek Cabanc952e812009-12-03 14:48:54 +01005365 return res == ERROR_SUCCESS;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005366}
5367
5368/***********************************************************************
5369 * HttpSendRequestW (WININET.@)
5370 *
5371 * Sends the specified request to the HTTP server
5372 *
5373 * RETURNS
5374 * TRUE on success
5375 * FALSE on failure
5376 *
5377 */
5378BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
5379 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5380{
Juan Langb49b2432011-03-01 10:59:39 -08005381 http_request_t *request;
5382 http_session_t *session = NULL;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005383 appinfo_t *hIC = NULL;
5384 DWORD res = ERROR_SUCCESS;
5385
5386 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
5387 debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
5388
Juan Langb49b2432011-03-01 10:59:39 -08005389 request = (http_request_t*) get_handle_object( hHttpRequest );
5390 if (NULL == request || request->hdr.htype != WH_HHTTPREQ)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005391 {
5392 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5393 goto lend;
5394 }
5395
Juan Lang20980062011-03-01 11:18:22 -08005396 session = request->session;
Juan Langb49b2432011-03-01 10:59:39 -08005397 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
Jacek Caban34fcbb52009-11-30 20:01:17 +01005398 {
5399 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5400 goto lend;
5401 }
5402
Juan Lang8e050392011-03-01 11:02:14 -08005403 hIC = session->appInfo;
Jacek Caban34fcbb52009-11-30 20:01:17 +01005404 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
5405 {
5406 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
5407 goto lend;
5408 }
5409
5410 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
5411 {
5412 WORKREQUEST workRequest;
5413 struct WORKREQ_HTTPSENDREQUESTW *req;
5414
5415 workRequest.asyncproc = AsyncHttpSendRequestProc;
Juan Langb49b2432011-03-01 10:59:39 -08005416 workRequest.hdr = WININET_AddRef( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005417 req = &workRequest.u.HttpSendRequestW;
5418 if (lpszHeaders)
5419 {
5420 DWORD size;
5421
5422 if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
5423 else size = dwHeaderLength * sizeof(WCHAR);
5424
Jacek Caban354a74e2011-04-21 13:39:03 +02005425 req->lpszHeader = heap_alloc(size);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005426 memcpy(req->lpszHeader, lpszHeaders, size);
5427 }
5428 else
5429 req->lpszHeader = 0;
5430 req->dwHeaderLength = dwHeaderLength;
5431 req->lpOptional = lpOptional;
5432 req->dwOptionalLength = dwOptionalLength;
5433 req->dwContentLength = dwOptionalLength;
5434 req->bEndRequest = TRUE;
5435
5436 INTERNET_AsyncCall(&workRequest);
5437 /*
5438 * This is from windows.
5439 */
5440 res = ERROR_IO_PENDING;
5441 }
5442 else
5443 {
Juan Langb49b2432011-03-01 10:59:39 -08005444 res = HTTP_HttpSendRequestW(request, lpszHeaders,
Jacek Caban34fcbb52009-11-30 20:01:17 +01005445 dwHeaderLength, lpOptional, dwOptionalLength,
5446 dwOptionalLength, TRUE);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005447 }
5448lend:
Juan Langb49b2432011-03-01 10:59:39 -08005449 if( request )
5450 WININET_Release( &request->hdr );
Jacek Caban34fcbb52009-11-30 20:01:17 +01005451
Hans Leidekker68453a52009-12-21 11:13:44 +01005452 SetLastError(res);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005453 return res == ERROR_SUCCESS;
5454}
5455
5456/***********************************************************************
5457 * HttpSendRequestA (WININET.@)
5458 *
5459 * Sends the specified request to the HTTP server
5460 *
5461 * RETURNS
5462 * TRUE on success
5463 * FALSE on failure
5464 *
5465 */
5466BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
5467 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
5468{
5469 BOOL result;
5470 LPWSTR szHeaders=NULL;
5471 DWORD nLen=dwHeaderLength;
5472 if(lpszHeaders!=NULL)
5473 {
5474 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
Jacek Caban354a74e2011-04-21 13:39:03 +02005475 szHeaders = heap_alloc(nLen*sizeof(WCHAR));
Jacek Caban34fcbb52009-11-30 20:01:17 +01005476 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
5477 }
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005478 result = HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
5479 heap_free(szHeaders);
Jacek Caban34fcbb52009-11-30 20:01:17 +01005480 return result;
5481}
5482
5483/***********************************************************************
Jacek Caban5a535d62008-02-26 20:20:41 +01005484 * HTTPSESSION_Destroy (internal)
5485 *
5486 * Deallocate session handle
5487 *
5488 */
Jacek Caban44d633a2009-07-07 21:46:09 +02005489static void HTTPSESSION_Destroy(object_header_t *hdr)
Jacek Caban5a535d62008-02-26 20:20:41 +01005490{
Juan Langb49b2432011-03-01 10:59:39 -08005491 http_session_t *session = (http_session_t*) hdr;
Jacek Caban5a535d62008-02-26 20:20:41 +01005492
Juan Langb49b2432011-03-01 10:59:39 -08005493 TRACE("%p\n", session);
Jacek Caban5a535d62008-02-26 20:20:41 +01005494
Juan Lang8e050392011-03-01 11:02:14 -08005495 WININET_Release(&session->appInfo->hdr);
Jacek Caban5a535d62008-02-26 20:20:41 +01005496
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005497 heap_free(session->hostName);
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005498 heap_free(session->password);
5499 heap_free(session->userName);
Jacek Caban5a535d62008-02-26 20:20:41 +01005500}
5501
Jacek Caban44d633a2009-07-07 21:46:09 +02005502static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
Jacek Cabane2933c22008-03-12 02:23:20 +01005503{
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005504 http_session_t *ses = (http_session_t *)hdr;
5505
Jacek Cabane2933c22008-03-12 02:23:20 +01005506 switch(option) {
5507 case INTERNET_OPTION_HANDLE_TYPE:
5508 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
5509
5510 if (*size < sizeof(ULONG))
5511 return ERROR_INSUFFICIENT_BUFFER;
5512
5513 *size = sizeof(DWORD);
5514 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
5515 return ERROR_SUCCESS;
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005516 case INTERNET_OPTION_CONNECT_TIMEOUT:
5517 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
5518
5519 if (*size < sizeof(DWORD))
5520 return ERROR_INSUFFICIENT_BUFFER;
5521
5522 *size = sizeof(DWORD);
5523 *(DWORD *)buffer = ses->connect_timeout;
5524 return ERROR_SUCCESS;
Hans Leidekker65223932012-01-13 15:15:48 +01005525
5526 case INTERNET_OPTION_SEND_TIMEOUT:
5527 TRACE("INTERNET_OPTION_SEND_TIMEOUT\n");
5528
5529 if (*size < sizeof(DWORD))
5530 return ERROR_INSUFFICIENT_BUFFER;
5531
5532 *size = sizeof(DWORD);
5533 *(DWORD *)buffer = ses->send_timeout;
5534 return ERROR_SUCCESS;
5535
5536 case INTERNET_OPTION_RECEIVE_TIMEOUT:
5537 TRACE("INTERNET_OPTION_RECEIVE_TIMEOUT\n");
5538
5539 if (*size < sizeof(DWORD))
5540 return ERROR_INSUFFICIENT_BUFFER;
5541
5542 *size = sizeof(DWORD);
5543 *(DWORD *)buffer = ses->receive_timeout;
5544 return ERROR_SUCCESS;
Jacek Cabane2933c22008-03-12 02:23:20 +01005545 }
5546
Hans Leidekker80dd3672010-05-25 12:19:32 +02005547 return INET_QueryOption(hdr, option, buffer, size, unicode);
Jacek Cabane2933c22008-03-12 02:23:20 +01005548}
Jacek Caban5a535d62008-02-26 20:20:41 +01005549
Jacek Caban44d633a2009-07-07 21:46:09 +02005550static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
Hans Leidekker8c201242008-09-24 16:54:37 +02005551{
Jacek Cabane9f4a402009-07-13 01:41:18 +02005552 http_session_t *ses = (http_session_t*)hdr;
Hans Leidekker8c201242008-09-24 16:54:37 +02005553
5554 switch(option) {
5555 case INTERNET_OPTION_USERNAME:
5556 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005557 heap_free(ses->userName);
Juan Lang8e050392011-03-01 11:02:14 -08005558 if (!(ses->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005559 return ERROR_SUCCESS;
5560 }
5561 case INTERNET_OPTION_PASSWORD:
5562 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005563 heap_free(ses->password);
Juan Lang8e050392011-03-01 11:02:14 -08005564 if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
Hans Leidekker8c201242008-09-24 16:54:37 +02005565 return ERROR_SUCCESS;
5566 }
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005567 case INTERNET_OPTION_CONNECT_TIMEOUT:
5568 {
Hans Leidekker65223932012-01-13 15:15:48 +01005569 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
Hans Leidekker848cd8a2012-01-13 15:15:20 +01005570 ses->connect_timeout = *(DWORD *)buffer;
5571 return ERROR_SUCCESS;
5572 }
Hans Leidekker65223932012-01-13 15:15:48 +01005573 case INTERNET_OPTION_SEND_TIMEOUT:
5574 {
5575 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
5576 ses->send_timeout = *(DWORD *)buffer;
5577 return ERROR_SUCCESS;
5578 }
5579 case INTERNET_OPTION_RECEIVE_TIMEOUT:
5580 {
5581 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
5582 ses->receive_timeout = *(DWORD *)buffer;
5583 return ERROR_SUCCESS;
5584 }
Hans Leidekker8c201242008-09-24 16:54:37 +02005585 default: break;
5586 }
5587
Jacek Caban48632572012-03-08 12:19:14 +01005588 return INET_SetOption(hdr, option, buffer, size);
Hans Leidekker8c201242008-09-24 16:54:37 +02005589}
5590
Jacek Caban44d633a2009-07-07 21:46:09 +02005591static const object_vtbl_t HTTPSESSIONVtbl = {
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005592 HTTPSESSION_Destroy,
Jacek Caban1ffcfbc2008-02-26 20:21:34 +01005593 NULL,
Jacek Cabane2933c22008-03-12 02:23:20 +01005594 HTTPSESSION_QueryOption,
Hans Leidekker8c201242008-09-24 16:54:37 +02005595 HTTPSESSION_SetOption,
Jacek Caban8c45eec2008-02-27 18:55:09 +01005596 NULL,
Jacek Caban33141842008-02-29 12:57:57 +01005597 NULL,
Jacek Caban3b4ca692008-03-02 19:35:11 +01005598 NULL,
Jacek Caband597fd12008-03-03 18:07:20 +01005599 NULL,
Jacek Caban7dc9bf62008-02-26 20:21:00 +01005600 NULL
Jacek Caban5a535d62008-02-26 20:20:41 +01005601};
5602
5603
5604/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005605 * HTTP_Connect (internal)
5606 *
5607 * Create http session handle
5608 *
5609 * RETURNS
5610 * HINTERNET a session handle on success
5611 * NULL on failure
5612 *
5613 */
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005614DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
Juan Lang8e050392011-03-01 11:02:14 -08005615 INTERNET_PORT serverPort, LPCWSTR lpszUserName,
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005616 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
5617 DWORD dwInternalFlags, HINTERNET *ret)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005618{
Juan Langb49b2432011-03-01 10:59:39 -08005619 http_session_t *session = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005620
Aric Stewartff9b9d42002-06-21 23:59:49 +00005621 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005622
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005623 if (!lpszServerName || !lpszServerName[0])
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005624 return ERROR_INVALID_PARAMETER;
Rob Shearman59ab0cf2008-01-31 14:47:25 +00005625
Mike McCormack3a1391b2004-07-19 21:49:39 +00005626 assert( hIC->hdr.htype == WH_HINIT );
Ulrich Czekallac2757242000-06-11 20:04:44 +00005627
Juan Langb49b2432011-03-01 10:59:39 -08005628 session = alloc_object(&hIC->hdr, &HTTPSESSIONVtbl, sizeof(http_session_t));
5629 if (!session)
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005630 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005631
Aric Stewartff9b9d42002-06-21 23:59:49 +00005632 /*
5633 * According to my tests. The name is not resolved until a request is sent
5634 */
Ulrich Czekallac2757242000-06-11 20:04:44 +00005635
Juan Langb49b2432011-03-01 10:59:39 -08005636 session->hdr.htype = WH_HHTTPSESSION;
5637 session->hdr.dwFlags = dwFlags;
5638 session->hdr.dwContext = dwContext;
5639 session->hdr.dwInternalFlags |= dwInternalFlags;
Mike McCormack3a1391b2004-07-19 21:49:39 +00005640
Jacek Cabanc2506172006-10-29 18:48:48 +01005641 WININET_AddRef( &hIC->hdr );
Juan Lang8e050392011-03-01 11:02:14 -08005642 session->appInfo = hIC;
Juan Langb49b2432011-03-01 10:59:39 -08005643 list_add_head( &hIC->hdr.children, &session->hdr.entry );
Jacek Cabanc2506172006-10-29 18:48:48 +01005644
Juan Lang72431562011-03-01 11:00:49 -08005645 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) {
5646 if(hIC->proxyBypass)
Dominik Strasser94c02fe2003-04-14 21:32:36 +00005647 FIXME("Proxy bypass is ignored.\n");
5648 }
Juan Lang8e050392011-03-01 11:02:14 -08005649 session->hostName = heap_strdupW(lpszServerName);
Robert Shearmanef209362006-03-10 12:28:52 +00005650 if (lpszUserName && lpszUserName[0])
Juan Lang8e050392011-03-01 11:02:14 -08005651 session->userName = heap_strdupW(lpszUserName);
Rob Shearman4b507682007-05-21 14:26:26 +01005652 if (lpszPassword && lpszPassword[0])
Juan Lang8e050392011-03-01 11:02:14 -08005653 session->password = heap_strdupW(lpszPassword);
Juan Lang8e050392011-03-01 11:02:14 -08005654 session->hostPort = serverPort;
Piotr Caban0b421002012-05-14 13:49:29 +02005655 session->connect_timeout = hIC->connect_timeout;
Hans Leidekker65223932012-01-13 15:15:48 +01005656 session->send_timeout = INFINITE;
5657 session->receive_timeout = INFINITE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005658
Kevin Koltzau917df922004-05-13 05:17:25 +00005659 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
Juan Langb49b2432011-03-01 10:59:39 -08005660 if (!(session->hdr.dwInternalFlags & INET_OPENURL))
Ulrich Czekallac2757242000-06-11 20:04:44 +00005661 {
Robert Shearmande2666f2005-11-29 10:44:05 +01005662 INTERNET_SendCallback(&hIC->hdr, dwContext,
Juan Langb49b2432011-03-01 10:59:39 -08005663 INTERNET_STATUS_HANDLE_CREATED, &session->hdr.hInternet,
Jacek Cabana073c662011-02-02 22:51:13 +01005664 sizeof(HINTERNET));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005665 }
5666
Aric Stewartff9b9d42002-06-21 23:59:49 +00005667/*
Francois Gouget93416cd2005-03-23 13:15:18 +00005668 * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
Aric Stewartff9b9d42002-06-21 23:59:49 +00005669 * windows
5670 */
Vincent Béron9a624912002-05-31 23:06:46 +00005671
Juan Langb49b2432011-03-01 10:59:39 -08005672 TRACE("%p --> %p\n", hIC, session);
Jacek Cabanb73e31c2009-12-21 13:58:53 +01005673
Juan Langb49b2432011-03-01 10:59:39 -08005674 *ret = session->hdr.hInternet;
Jacek Cabana073c662011-02-02 22:51:13 +01005675 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005676}
5677
Ulrich Czekallac2757242000-06-11 20:04:44 +00005678/***********************************************************************
Alexandre Julliard48243e32004-07-15 18:57:32 +00005679 * HTTP_clear_response_headers (internal)
5680 *
5681 * clear out any old response headers
5682 */
Juan Langb49b2432011-03-01 10:59:39 -08005683static void HTTP_clear_response_headers( http_request_t *request )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005684{
5685 DWORD i;
5686
Juan Langb49b2432011-03-01 10:59:39 -08005687 for( i=0; i<request->nCustHeaders; i++)
Alexandre Julliard48243e32004-07-15 18:57:32 +00005688 {
Juan Lang20980062011-03-01 11:18:22 -08005689 if( !request->custHeaders[i].lpszField )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005690 continue;
Juan Lang20980062011-03-01 11:18:22 -08005691 if( !request->custHeaders[i].lpszValue )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005692 continue;
Juan Lang20980062011-03-01 11:18:22 -08005693 if ( request->custHeaders[i].wFlags & HDR_ISREQUEST )
Alexandre Julliard48243e32004-07-15 18:57:32 +00005694 continue;
Juan Langb49b2432011-03-01 10:59:39 -08005695 HTTP_DeleteCustomHeader( request, i );
Robert Shearman7707a762005-03-10 11:14:24 +00005696 i--;
Alexandre Julliard48243e32004-07-15 18:57:32 +00005697 }
5698}
5699
5700/***********************************************************************
Ulrich Czekallac2757242000-06-11 20:04:44 +00005701 * HTTP_GetResponseHeaders (internal)
5702 *
5703 * Read server response
5704 *
5705 * RETURNS
5706 *
5707 * TRUE on success
5708 * FALSE on error
5709 */
Juan Langb49b2432011-03-01 10:59:39 -08005710static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005711{
5712 INT cbreaks = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005713 WCHAR buffer[MAX_REPLY_LEN];
Ulrich Czekallac2757242000-06-11 20:04:44 +00005714 DWORD buflen = MAX_REPLY_LEN;
5715 BOOL bSuccess = FALSE;
Aric Stewartff9b9d42002-06-21 23:59:49 +00005716 INT rc = 0;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005717 char bufferA[MAX_REPLY_LEN];
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005718 LPWSTR status_code = NULL, status_text = NULL;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005719 DWORD cchMaxRawHeaders = 1024;
Hans Leidekker911d0df2010-02-23 13:03:37 +01005720 LPWSTR lpszRawHeaders = NULL;
Eric van Beurden5caf8092009-06-04 10:52:16 -04005721 LPWSTR temp;
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00005722 DWORD cchRawHeaders = 0;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005723 BOOL codeHundred = FALSE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005724
Aric Stewartff9b9d42002-06-21 23:59:49 +00005725 TRACE("-->\n");
Ulrich Czekallac2757242000-06-11 20:04:44 +00005726
Jacek Caban8a1df202011-05-10 09:26:43 +00005727 if(!request->netconn)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005728 goto lend;
5729
Hans Leidekker65223932012-01-13 15:15:48 +01005730 NETCON_set_timeout( request->netconn, FALSE, request->receive_timeout );
Hans Leidekker2617fb62008-02-17 20:41:56 +01005731 do {
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005732 static const WCHAR szHundred[] = {'1','0','0',0};
Hans Leidekker2617fb62008-02-17 20:41:56 +01005733 /*
Hans Leidekker2617fb62008-02-17 20:41:56 +01005734 * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
5735 */
Hans Leidekker96b639d2009-03-04 12:42:43 +01005736 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005737 if (!read_line(request, bufferA, &buflen))
Hans Leidekker2617fb62008-02-17 20:41:56 +01005738 goto lend;
Piotr Cabanee684732010-06-29 12:20:51 +02005739
5740 /* clear old response headers (eg. from a redirect response) */
5741 if (clear) {
Juan Langb49b2432011-03-01 10:59:39 -08005742 HTTP_clear_response_headers( request );
Piotr Cabanee684732010-06-29 12:20:51 +02005743 clear = FALSE;
5744 }
5745
Hans Leidekker96b639d2009-03-04 12:42:43 +01005746 rc += buflen;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005747 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005748 /* check is this a status code line? */
5749 if (!strncmpW(buffer, g_szHttp1_0, 4))
5750 {
5751 /* split the version from the status code */
5752 status_code = strchrW( buffer, ' ' );
5753 if( !status_code )
5754 goto lend;
5755 *status_code++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005756
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005757 /* split the status code from the status text */
5758 status_text = strchrW( status_code, ' ' );
5759 if( !status_text )
5760 goto lend;
5761 *status_text++=0;
Hans Leidekker2617fb62008-02-17 20:41:56 +01005762
Jacek Caban5240e402012-05-03 12:19:47 +02005763 request->status_code = atoiW(status_code);
5764
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005765 TRACE("version [%s] status code [%s] status text [%s]\n",
5766 debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
Hans Leidekker2617fb62008-02-17 20:41:56 +01005767
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005768 codeHundred = (!strcmpW(status_code, szHundred));
5769 }
5770 else if (!codeHundred)
5771 {
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005772 WARN("No status line at head of response (%s)\n", debugstr_w(buffer));
5773
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005774 heap_free(request->version);
5775 heap_free(request->statusText);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005776
Jacek Caban2aa3d692012-05-03 12:20:38 +02005777 request->status_code = HTTP_STATUS_OK;
Juan Lang20980062011-03-01 11:18:22 -08005778 request->version = heap_strdupW(g_szHttp1_0);
5779 request->statusText = heap_strdupW(szOK);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005780
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005781 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005782 request->rawHeaders = heap_strdupW(szDefaultHeader);
Hans Leidekker2ed570e2010-02-22 12:28:03 +01005783
5784 bSuccess = TRUE;
Erik Inge Bolsø5af1a492009-09-29 21:50:12 +02005785 goto lend;
Aric Stewartb9f2f9d2009-06-23 14:30:38 +09005786 }
5787 } while (codeHundred);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005788
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005789 /* Add status code */
Juan Langb49b2432011-03-01 10:59:39 -08005790 HTTP_ProcessHeader(request, szStatus, status_code,
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005791 HTTP_ADDHDR_FLAG_REPLACE);
5792
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005793 heap_free(request->version);
5794 heap_free(request->statusText);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005795
Juan Lang20980062011-03-01 11:18:22 -08005796 request->version = heap_strdupW(buffer);
5797 request->statusText = heap_strdupW(status_text);
Maarten Lankhorst5132fb42008-02-25 11:05:41 -08005798
5799 /* Restore the spaces */
5800 *(status_code-1) = ' ';
5801 *(status_text-1) = ' ';
5802
Robert Shearmandee87512004-07-19 20:09:20 +00005803 /* regenerate raw headers */
Jacek Caban354a74e2011-04-21 13:39:03 +02005804 lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR));
Hans Leidekker911d0df2010-02-23 13:03:37 +01005805 if (!lpszRawHeaders) goto lend;
5806
Robert Shearmandee87512004-07-19 20:09:20 +00005807 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
Robert Shearmandee87512004-07-19 20:09:20 +00005808 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005809 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden5caf8092009-06-04 10:52:16 -04005810 if (temp == NULL) goto lend;
5811 lpszRawHeaders = temp;
Robert Shearmandee87512004-07-19 20:09:20 +00005812 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5813 cchRawHeaders += (buflen-1);
5814 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5815 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5816 lpszRawHeaders[cchRawHeaders] = '\0';
5817
Ulrich Czekallac2757242000-06-11 20:04:44 +00005818 /* Parse each response line */
5819 do
5820 {
5821 buflen = MAX_REPLY_LEN;
Juan Langb49b2432011-03-01 10:59:39 -08005822 if (read_line(request, bufferA, &buflen))
Robert Shearmanb72a6822004-09-23 22:53:50 +00005823 {
5824 LPWSTR * pFieldAndValue;
5825
Francois Gougetda8b3dd2005-01-26 21:09:04 +00005826 TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
Hans Leidekker100ee0a2009-03-04 12:44:22 +01005827
5828 if (!bufferA[0]) break;
Mike McCormacka4e902c2004-03-30 04:36:09 +00005829 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
Robert Shearmandee87512004-07-19 20:09:20 +00005830
Robert Shearmanb72a6822004-09-23 22:53:50 +00005831 pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
Eric van Beurden59a21782009-06-04 10:52:59 -04005832 if (pFieldAndValue)
5833 {
5834 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
5835 cchMaxRawHeaders *= 2;
Jacek Caban55b27222011-04-22 12:35:05 +02005836 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
Eric van Beurden59a21782009-06-04 10:52:59 -04005837 if (temp == NULL) goto lend;
5838 lpszRawHeaders = temp;
5839 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
5840 cchRawHeaders += (buflen-1);
5841 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
5842 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
5843 lpszRawHeaders[cchRawHeaders] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005844
Juan Langb49b2432011-03-01 10:59:39 -08005845 HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1],
Eric van Beurden59a21782009-06-04 10:52:59 -04005846 HTTP_ADDREQ_FLAG_ADD );
Robert Shearmanb72a6822004-09-23 22:53:50 +00005847
Eric van Beurden59a21782009-06-04 10:52:59 -04005848 HTTP_FreeTokens(pFieldAndValue);
5849 }
5850 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005851 else
5852 {
5853 cbreaks++;
5854 if (cbreaks >= 2)
5855 break;
5856 }
5857 }while(1);
5858
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005859 /* make sure the response header is terminated with an empty line. Some apps really
5860 truly care about that empty line being there for some reason. Just add it to the
5861 header. */
5862 if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
5863 {
5864 cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
Jacek Caban55b27222011-04-22 12:35:05 +02005865 temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
Eric van Beurden42c7dc92009-06-24 13:28:00 -04005866 if (temp == NULL) goto lend;
5867 lpszRawHeaders = temp;
5868 }
5869
5870 memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
5871
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005872 heap_free(request->rawHeaders);
Juan Lang20980062011-03-01 11:18:22 -08005873 request->rawHeaders = lpszRawHeaders;
Robert Shearmandee87512004-07-19 20:09:20 +00005874 TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
Ulrich Czekallac2757242000-06-11 20:04:44 +00005875 bSuccess = TRUE;
5876
5877lend:
5878
Aric Stewartff9b9d42002-06-21 23:59:49 +00005879 TRACE("<--\n");
5880 if (bSuccess)
5881 return rc;
5882 else
Hans Leidekkere3e26222008-07-19 19:52:47 +02005883 {
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02005884 heap_free(lpszRawHeaders);
Robert Shearman0e7c41e2005-11-28 11:55:16 +01005885 return 0;
Hans Leidekkere3e26222008-07-19 19:52:47 +02005886 }
Ulrich Czekallac2757242000-06-11 20:04:44 +00005887}
5888
Ulrich Czekallac2757242000-06-11 20:04:44 +00005889/***********************************************************************
5890 * HTTP_InterpretHttpHeader (internal)
5891 *
5892 * Parse server response
5893 *
5894 * RETURNS
5895 *
Robert Shearmanb72a6822004-09-23 22:53:50 +00005896 * Pointer to array of field, value, NULL on success.
5897 * NULL on error.
Ulrich Czekallac2757242000-06-11 20:04:44 +00005898 */
Jacek Caban02708c62005-10-26 10:07:58 +00005899static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005900{
Robert Shearmanb72a6822004-09-23 22:53:50 +00005901 LPWSTR * pTokenPair;
5902 LPWSTR pszColon;
5903 INT len;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005904
Jacek Caban354a74e2011-04-21 13:39:03 +02005905 pTokenPair = heap_alloc_zero(sizeof(*pTokenPair)*3);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005906
Robert Shearmanb72a6822004-09-23 22:53:50 +00005907 pszColon = strchrW(buffer, ':');
5908 /* must have two tokens */
5909 if (!pszColon)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005910 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005911 HTTP_FreeTokens(pTokenPair);
Robert Shearman7707a762005-03-10 11:14:24 +00005912 if (buffer[0])
5913 TRACE("No ':' in line: %s\n", debugstr_w(buffer));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005914 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005915 }
5916
Jacek Caban354a74e2011-04-21 13:39:03 +02005917 pTokenPair[0] = heap_alloc((pszColon - buffer + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005918 if (!pTokenPair[0])
Ulrich Czekallac2757242000-06-11 20:04:44 +00005919 {
Robert Shearmanb72a6822004-09-23 22:53:50 +00005920 HTTP_FreeTokens(pTokenPair);
5921 return NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005922 }
Robert Shearmanb72a6822004-09-23 22:53:50 +00005923 memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
5924 pTokenPair[0][pszColon - buffer] = '\0';
Ulrich Czekallac2757242000-06-11 20:04:44 +00005925
Robert Shearmanb72a6822004-09-23 22:53:50 +00005926 /* skip colon */
5927 pszColon++;
5928 len = strlenW(pszColon);
Jacek Caban354a74e2011-04-21 13:39:03 +02005929 pTokenPair[1] = heap_alloc((len + 1) * sizeof(WCHAR));
Robert Shearmanb72a6822004-09-23 22:53:50 +00005930 if (!pTokenPair[1])
5931 {
5932 HTTP_FreeTokens(pTokenPair);
5933 return NULL;
5934 }
5935 memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
5936
5937 strip_spaces(pTokenPair[0]);
5938 strip_spaces(pTokenPair[1]);
5939
5940 TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
5941 return pTokenPair;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005942}
5943
Ulrich Czekallac2757242000-06-11 20:04:44 +00005944/***********************************************************************
5945 * HTTP_ProcessHeader (internal)
5946 *
5947 * Stuff header into header tables according to <dwModifier>
5948 *
5949 */
5950
Juan Langa1ab4a72007-11-07 14:45:06 -08005951#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 +00005952
Juan Langb49b2432011-03-01 10:59:39 -08005953static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005954{
Mike McCormacka4e902c2004-03-30 04:36:09 +00005955 LPHTTPHEADERW lphttpHdr = NULL;
Aric Stewart1e946d32005-12-13 17:07:41 +01005956 INT index = -1;
Aric Stewart1e946d32005-12-13 17:07:41 +01005957 BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
Jacek Cabane9749652009-11-30 20:01:00 +01005958 DWORD res = ERROR_HTTP_INVALID_HEADER;
Ulrich Czekallac2757242000-06-11 20:04:44 +00005959
Hans Leidekkercd2c4582006-10-05 13:18:56 +02005960 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
Ulrich Czekallac2757242000-06-11 20:04:44 +00005961
Aric Stewart1e946d32005-12-13 17:07:41 +01005962 /* REPLACE wins out over ADD */
5963 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5964 dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
5965
5966 if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
5967 index = -1;
5968 else
Juan Langb49b2432011-03-01 10:59:39 -08005969 index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only);
Aric Stewart1e946d32005-12-13 17:07:41 +01005970
5971 if (index >= 0)
Ulrich Czekallac2757242000-06-11 20:04:44 +00005972 {
Aric Stewart1e946d32005-12-13 17:07:41 +01005973 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
Jacek Cabane9749652009-11-30 20:01:00 +01005974 return ERROR_HTTP_INVALID_HEADER;
Juan Lang20980062011-03-01 11:18:22 -08005975 lphttpHdr = &request->custHeaders[index];
Aric Stewart1e946d32005-12-13 17:07:41 +01005976 }
5977 else if (value)
5978 {
5979 HTTPHEADERW hdr;
5980
5981 hdr.lpszField = (LPWSTR)field;
5982 hdr.lpszValue = (LPWSTR)value;
5983 hdr.wFlags = hdr.wCount = 0;
5984
5985 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5986 hdr.wFlags |= HDR_ISREQUEST;
5987
Juan Langb49b2432011-03-01 10:59:39 -08005988 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewart1e946d32005-12-13 17:07:41 +01005989 }
Rob Shearman7b002a32007-01-12 19:16:49 -06005990 /* no value to delete */
Jacek Cabane9749652009-11-30 20:01:00 +01005991 else return ERROR_SUCCESS;
Aric Stewart1e946d32005-12-13 17:07:41 +01005992
5993 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
5994 lphttpHdr->wFlags |= HDR_ISREQUEST;
5995 else
5996 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
5997
5998 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
5999 {
Juan Langb49b2432011-03-01 10:59:39 -08006000 HTTP_DeleteCustomHeader( request, index );
Aric Stewart1e946d32005-12-13 17:07:41 +01006001
6002 if (value)
Aric Stewartff9b9d42002-06-21 23:59:49 +00006003 {
Mike McCormacka4e902c2004-03-30 04:36:09 +00006004 HTTPHEADERW hdr;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006005
Mike McCormacka4e902c2004-03-30 04:36:09 +00006006 hdr.lpszField = (LPWSTR)field;
6007 hdr.lpszValue = (LPWSTR)value;
Aric Stewartff9b9d42002-06-21 23:59:49 +00006008 hdr.wFlags = hdr.wCount = 0;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006009
6010 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
6011 hdr.wFlags |= HDR_ISREQUEST;
6012
Juan Langb49b2432011-03-01 10:59:39 -08006013 return HTTP_InsertCustomHeader(request, &hdr);
Aric Stewartff9b9d42002-06-21 23:59:49 +00006014 }
Aric Stewart1e946d32005-12-13 17:07:41 +01006015
Jacek Cabane9749652009-11-30 20:01:00 +01006016 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006017 }
Juan Langa1ab4a72007-11-07 14:45:06 -08006018 else if (dwModifier & COALESCEFLAGS)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006019 {
Aric Stewart1e946d32005-12-13 17:07:41 +01006020 LPWSTR lpsztmp;
6021 WCHAR ch = 0;
6022 INT len = 0;
6023 INT origlen = strlenW(lphttpHdr->lpszValue);
6024 INT valuelen = strlenW(value);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006025
Aric Stewart1e946d32005-12-13 17:07:41 +01006026 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006027 {
Aric Stewart1e946d32005-12-13 17:07:41 +01006028 ch = ',';
6029 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
6030 }
6031 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
6032 {
6033 ch = ';';
6034 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006035 }
6036
Aric Stewart1e946d32005-12-13 17:07:41 +01006037 len = origlen + valuelen + ((ch > 0) ? 2 : 0);
6038
Jacek Caban55b27222011-04-22 12:35:05 +02006039 lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
Aric Stewart1e946d32005-12-13 17:07:41 +01006040 if (lpsztmp)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006041 {
Aric Stewart1e946d32005-12-13 17:07:41 +01006042 lphttpHdr->lpszValue = lpsztmp;
6043 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
6044 if (ch > 0)
6045 {
6046 lphttpHdr->lpszValue[origlen] = ch;
6047 origlen++;
6048 lphttpHdr->lpszValue[origlen] = ' ';
6049 origlen++;
6050 }
6051
6052 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
6053 lphttpHdr->lpszValue[len] = '\0';
Jacek Cabane9749652009-11-30 20:01:00 +01006054 res = ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006055 }
6056 else
6057 {
Jacek Caban55b27222011-04-22 12:35:05 +02006058 WARN("heap_realloc (%d bytes) failed\n",len+1);
Jacek Cabane9749652009-11-30 20:01:00 +01006059 res = ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006060 }
6061 }
Jacek Cabane9749652009-11-30 20:01:00 +01006062 TRACE("<-- %d\n", res);
6063 return res;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006064}
6065
Ulrich Czekallac2757242000-06-11 20:04:44 +00006066/***********************************************************************
6067 * HTTP_GetCustomHeaderIndex (internal)
6068 *
6069 * Return index of custom header from header array
6070 *
6071 */
Juan Langb49b2432011-03-01 10:59:39 -08006072static INT HTTP_GetCustomHeaderIndex(http_request_t *request, LPCWSTR lpszField,
Mike McCormack92ddc1c2006-03-30 18:20:04 +09006073 int requested_index, BOOL request_only)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006074{
Mike McCormack13b6ce6d2004-08-09 18:54:23 +00006075 DWORD index;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006076
Juan Lang3cd54552009-12-04 14:37:46 -08006077 TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006078
Juan Langb49b2432011-03-01 10:59:39 -08006079 for (index = 0; index < request->nCustHeaders; index++)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006080 {
Juan Lang20980062011-03-01 11:18:22 -08006081 if (strcmpiW(request->custHeaders[index].lpszField, lpszField))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09006082 continue;
6083
Juan Lang20980062011-03-01 11:18:22 -08006084 if (request_only && !(request->custHeaders[index].wFlags & HDR_ISREQUEST))
Mike McCormack92ddc1c2006-03-30 18:20:04 +09006085 continue;
6086
Juan Lang20980062011-03-01 11:18:22 -08006087 if (!request_only && (request->custHeaders[index].wFlags & HDR_ISREQUEST))
Aric Stewart1e946d32005-12-13 17:07:41 +01006088 continue;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006089
Aric Stewart1e946d32005-12-13 17:07:41 +01006090 if (requested_index == 0)
Mike McCormack92ddc1c2006-03-30 18:20:04 +09006091 break;
6092 requested_index --;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006093 }
6094
Juan Langb49b2432011-03-01 10:59:39 -08006095 if (index >= request->nCustHeaders)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006096 index = -1;
6097
Hans Leidekkercd2c4582006-10-05 13:18:56 +02006098 TRACE("Return: %d\n", index);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006099 return index;
6100}
6101
6102
6103/***********************************************************************
6104 * HTTP_InsertCustomHeader (internal)
6105 *
6106 * Insert header into array
6107 *
6108 */
Juan Langb49b2432011-03-01 10:59:39 -08006109static DWORD HTTP_InsertCustomHeader(http_request_t *request, LPHTTPHEADERW lpHdr)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006110{
6111 INT count;
Mike McCormacka4e902c2004-03-30 04:36:09 +00006112 LPHTTPHEADERW lph = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006113
Mike McCormacka4e902c2004-03-30 04:36:09 +00006114 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
Juan Langb49b2432011-03-01 10:59:39 -08006115 count = request->nCustHeaders + 1;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006116 if (count > 1)
Jacek Caban55b27222011-04-22 12:35:05 +02006117 lph = heap_realloc_zero(request->custHeaders, sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006118 else
Jacek Caban354a74e2011-04-21 13:39:03 +02006119 lph = heap_alloc_zero(sizeof(HTTPHEADERW) * count);
Ulrich Czekallac2757242000-06-11 20:04:44 +00006120
Jacek Cabane9749652009-11-30 20:01:00 +01006121 if (!lph)
6122 return ERROR_OUTOFMEMORY;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006123
Juan Lang20980062011-03-01 11:18:22 -08006124 request->custHeaders = lph;
6125 request->custHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
6126 request->custHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
6127 request->custHeaders[count-1].wFlags = lpHdr->wFlags;
6128 request->custHeaders[count-1].wCount= lpHdr->wCount;
Juan Langb49b2432011-03-01 10:59:39 -08006129 request->nCustHeaders++;
Jacek Cabane9749652009-11-30 20:01:00 +01006130
6131 return ERROR_SUCCESS;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006132}
6133
6134
6135/***********************************************************************
6136 * HTTP_DeleteCustomHeader (internal)
6137 *
6138 * Delete header from array
Mike McCormacka1c16d22003-07-22 03:17:52 +00006139 * If this function is called, the indexs may change.
Ulrich Czekallac2757242000-06-11 20:04:44 +00006140 */
Juan Langb49b2432011-03-01 10:59:39 -08006141static BOOL HTTP_DeleteCustomHeader(http_request_t *request, DWORD index)
Ulrich Czekallac2757242000-06-11 20:04:44 +00006142{
Juan Langb49b2432011-03-01 10:59:39 -08006143 if( request->nCustHeaders <= 0 )
Mike McCormacka1c16d22003-07-22 03:17:52 +00006144 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08006145 if( index >= request->nCustHeaders )
Mike McCormacka1c16d22003-07-22 03:17:52 +00006146 return FALSE;
Juan Langb49b2432011-03-01 10:59:39 -08006147 request->nCustHeaders--;
Mike McCormacka1c16d22003-07-22 03:17:52 +00006148
Hans Leidekker9acd1ef2011-06-01 11:50:53 +02006149 heap_free(request->custHeaders[index].lpszField);
6150 heap_free(request->custHeaders[index].lpszValue);
Rob Shearman62e0a8c2008-06-20 10:14:38 +01006151
Juan Lang20980062011-03-01 11:18:22 -08006152 memmove( &request->custHeaders[index], &request->custHeaders[index+1],
Juan Langb49b2432011-03-01 10:59:39 -08006153 (request->nCustHeaders - index)* sizeof(HTTPHEADERW) );
Juan Lang20980062011-03-01 11:18:22 -08006154 memset( &request->custHeaders[request->nCustHeaders], 0, sizeof(HTTPHEADERW) );
Mike McCormacka1c16d22003-07-22 03:17:52 +00006155
6156 return TRUE;
Ulrich Czekallac2757242000-06-11 20:04:44 +00006157}
Alberto Massarib09eef22002-11-13 04:08:26 +00006158
Aric Stewartc8dfc022007-07-26 08:59:00 -05006159
6160/***********************************************************************
6161 * HTTP_VerifyValidHeader (internal)
6162 *
6163 * Verify the given header is not invalid for the given http request
6164 *
6165 */
Juan Langb49b2432011-03-01 10:59:39 -08006166static BOOL HTTP_VerifyValidHeader(http_request_t *request, LPCWSTR field)
Aric Stewartc8dfc022007-07-26 08:59:00 -05006167{
Aric Stewartc8dfc022007-07-26 08:59:00 -05006168 /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
Juan Lang20980062011-03-01 11:18:22 -08006169 if (!strcmpW(request->version, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
Jacek Cabane9749652009-11-30 20:01:00 +01006170 return ERROR_HTTP_INVALID_HEADER;
Aric Stewartc8dfc022007-07-26 08:59:00 -05006171
Jacek Cabane9749652009-11-30 20:01:00 +01006172 return ERROR_SUCCESS;
Aric Stewartc8dfc022007-07-26 08:59:00 -05006173}
6174
Alberto Massarib09eef22002-11-13 04:08:26 +00006175/***********************************************************************
6176 * IsHostInProxyBypassList (@)
6177 *
6178 * Undocumented
6179 *
6180 */
6181BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
6182{
Hans Leidekkercd2c4582006-10-05 13:18:56 +02006183 FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
Alberto Massarib09eef22002-11-13 04:08:26 +00006184 return FALSE;
6185}
Austin English1c7d3492010-11-25 06:59:25 -08006186
6187/***********************************************************************
6188 * InternetShowSecurityInfoByURLA (@)
6189 */
6190BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window)
6191{
6192 FIXME("stub: %s %p\n", url, window);
6193 return FALSE;
6194}
6195
6196/***********************************************************************
6197 * InternetShowSecurityInfoByURLW (@)
6198 */
6199BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window)
6200{
6201 FIXME("stub: %s %p\n", debugstr_w(url), window);
6202 return FALSE;
6203}
André Hentscheladea3c52011-10-29 15:08:08 +02006204
6205/***********************************************************************
6206 * ShowX509EncodedCertificate (@)
6207 */
6208DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len)
6209{
Juan Lang044f6452011-10-31 12:55:15 -07006210 PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING,
6211 cert, len);
6212 DWORD ret;
6213
6214 if (certContext)
6215 {
6216 CRYPTUI_VIEWCERTIFICATE_STRUCTW view;
6217
6218 memset(&view, 0, sizeof(view));
6219 view.hwndParent = parent;
6220 view.pCertContext = certContext;
6221 if (CryptUIDlgViewCertificateW(&view, NULL))
6222 ret = ERROR_SUCCESS;
6223 else
6224 ret = GetLastError();
6225 CertFreeCertificateContext(certContext);
6226 }
6227 else
6228 ret = GetLastError();
6229 return ret;
André Hentscheladea3c52011-10-29 15:08:08 +02006230}