1 /*
2 * Wininet - Http Implementation
3 *
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 TransGaming Technologies Inc.
7 * Copyright 2004 Mike McCormack for CodeWeavers
8 * Copyright 2005 Aric Stewart for CodeWeavers
9 * Copyright 2006 Robert Shearman for CodeWeavers
10 *
11 * Ulrich Czekalla
12 * David Hammerton
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #if defined(__MINGW32__) || defined (_MSC_VER)
33 #include <ws2tcpip.h>
34 #endif
35
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 # include <arpa/inet.h>
42 #endif
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49 #include <time.h>
50 #include <assert.h>
51 #ifdef HAVE_ZLIB
52 # include <zlib.h>
53 #endif
54
55 #include "windef.h"
56 #include "winbase.h"
57 #include "wininet.h"
58 #include "winerror.h"
59 #define NO_SHLWAPI_STREAM
60 #define NO_SHLWAPI_REG
61 #define NO_SHLWAPI_STRFCNS
62 #define NO_SHLWAPI_GDI
63 #include "shlwapi.h"
64 #include "sspi.h"
65 #include "wincrypt.h"
66
67 #include "internet.h"
68 #include "wine/debug.h"
69 #include "wine/exception.h"
70 #include "wine/unicode.h"
71
72 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
73
74 static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','',0};
75 static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
76 static const WCHAR hostW[] = { 'H','o','s','t',0 };
77 static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
78 static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
79 static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
80 static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
81 static const WCHAR szGET[] = { 'G','E','T', 0 };
82 static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
83 static const WCHAR szCrLf[] = {'\r','\n', 0};
84
85 static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
86 static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
87 static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
88 static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
89 static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
90 static const WCHAR szAge[] = { 'A','g','e',0 };
91 static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
92 static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
93 static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
94 static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
95 static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
96 static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
97 static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
98 static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
99 static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
100 static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
101 static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
102 static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
103 static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
104 static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
105 static const WCHAR szDate[] = { 'D','a','t','e',0 };
106 static const WCHAR szFrom[] = { 'F','r','o','m',0 };
107 static const WCHAR szETag[] = { 'E','T','a','g',0 };
108 static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
109 static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
110 static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
111 static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
112 static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
113 static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
114 static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
115 static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
116 static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
117 static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
118 static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
119 static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
120 static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
121 static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
122 static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
123 static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
124 static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
125 static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
126 static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
127 static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
128 static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
129 static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
130 static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
131 static const WCHAR szURI[] = { 'U','R','I',0 };
132 static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
133 static const WCHAR szVary[] = { 'V','a','r','y',0 };
134 static const WCHAR szVia[] = { 'V','i','a',0 };
135 static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
136 static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
137
138 #define MAXHOSTNAME 100
139 #define MAX_FIELD_VALUE_LEN 256
140 #define MAX_FIELD_LEN 256
141
142 #define HTTP_REFERER szReferer
143 #define HTTP_ACCEPT szAccept
144 #define HTTP_USERAGENT szUser_Agent
145
146 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
147 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
148 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
149 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
150 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
151 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
152 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
153
154 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
155
156 struct HttpAuthInfo
157 {
158 LPWSTR scheme;
159 CredHandle cred;
160 CtxtHandle ctx;
161 TimeStamp exp;
162 ULONG attr;
163 ULONG max_token;
164 void *auth_data;
165 unsigned int auth_data_len;
166 BOOL finished; /* finished authenticating */
167 };
168
169
170 struct gzip_stream_t {
171 #ifdef HAVE_ZLIB
172 z_stream zstream;
173 #endif
174 BYTE buf[8192];
175 DWORD buf_size;
176 DWORD buf_pos;
177 BOOL end_of_data;
178 };
179
180 static BOOL HTTP_OpenConnection(http_request_t *req);
181 static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
182 static BOOL HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
183 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
184 static BOOL HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
185 static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
186 static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
187 static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
188 static BOOL HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
189 static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
190 static BOOL HTTP_HandleRedirect(http_request_t *req, LPCWSTR lpszUrl);
191 static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
192 static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
193 static void HTTP_DrainContent(http_request_t *req);
194 static BOOL HTTP_FinishedReading(http_request_t *req);
195
196 static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
197 {
198 int HeaderIndex = 0;
199 HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
200 if (HeaderIndex == -1)
201 return NULL;
202 else
203 return &req->pCustHeaders[HeaderIndex];
204 }
205
206 #ifdef HAVE_ZLIB
207
208 static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
209 {
210 return HeapAlloc(GetProcessHeap(), 0, items*size);
211 }
212
213 static void wininet_zfree(voidpf opaque, voidpf address)
214 {
215 HeapFree(GetProcessHeap(), 0, address);
216 }
217
218 static void init_gzip_stream(http_request_t *req)
219 {
220 gzip_stream_t *gzip_stream;
221 int index, zres;
222
223 gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
224 gzip_stream->zstream.zalloc = wininet_zalloc;
225 gzip_stream->zstream.zfree = wininet_zfree;
226 gzip_stream->zstream.opaque = NULL;
227 gzip_stream->zstream.next_in = NULL;
228 gzip_stream->zstream.avail_in = 0;
229 gzip_stream->zstream.next_out = NULL;
230 gzip_stream->zstream.avail_out = 0;
231 gzip_stream->buf_pos = 0;
232 gzip_stream->buf_size = 0;
233 gzip_stream->end_of_data = FALSE;
234
235 zres = inflateInit2(&gzip_stream->zstream, 0x1f);
236 if(zres != Z_OK) {
237 ERR("inflateInit failed: %d\n", zres);
238 HeapFree(GetProcessHeap(), 0, gzip_stream);
239 return;
240 }
241
242 req->gzip_stream = gzip_stream;
243
244 index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
245 if(index != -1)
246 HTTP_DeleteCustomHeader(req, index);
247 }
248
249 #else
250
251 static void init_gzip_stream(http_request_t *req)
252 {
253 ERR("gzip stream not supported, missing zlib.\n");
254 }
255
256 #endif
257
258 /* set the request content length based on the headers */
259 static DWORD set_content_length( http_request_t *lpwhr )
260 {
261 static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
262 WCHAR encoding[20];
263 DWORD size;
264
265 size = sizeof(lpwhr->dwContentLength);
266 if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
267 &lpwhr->dwContentLength, &size, NULL))
268 lpwhr->dwContentLength = ~0u;
269
270 size = sizeof(encoding);
271 if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
272 !strcmpiW(encoding, szChunked))
273 {
274 lpwhr->dwContentLength = ~0u;
275 lpwhr->read_chunked = TRUE;
276 }
277
278 if(lpwhr->decoding) {
279 int encoding_idx;
280
281 static const WCHAR gzipW[] = {'g','z','i','p',0};
282
283 encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
284 if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
285 init_gzip_stream(lpwhr);
286 }
287
288 return lpwhr->dwContentLength;
289 }
290
291 /***********************************************************************
292 * HTTP_Tokenize (internal)
293 *
294 * Tokenize a string, allocating memory for the tokens.
295 */
296 static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
297 {
298 LPWSTR * token_array;
299 int tokens = 0;
300 int i;
301 LPCWSTR next_token;
302
303 if (string)
304 {
305 /* empty string has no tokens */
306 if (*string)
307 tokens++;
308 /* count tokens */
309 for (i = 0; string[i]; i++)
310 {
311 if (!strncmpW(string+i, token_string, strlenW(token_string)))
312 {
313 DWORD j;
314 tokens++;
315 /* we want to skip over separators, but not the null terminator */
316 for (j = 0; j < strlenW(token_string) - 1; j++)
317 if (!string[i+j])
318 break;
319 i += j;
320 }
321 }
322 }
323
324 /* add 1 for terminating NULL */
325 token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
326 token_array[tokens] = NULL;
327 if (!tokens)
328 return token_array;
329 for (i = 0; i < tokens; i++)
330 {
331 int len;
332 next_token = strstrW(string, token_string);
333 if (!next_token) next_token = string+strlenW(string);
334 len = next_token - string;
335 token_array[i] = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
336 memcpy(token_array[i], string, len*sizeof(WCHAR));
337 token_array[i][len] = '\0';
338 string = next_token+strlenW(token_string);
339 }
340 return token_array;
341 }
342
343 /***********************************************************************
344 * HTTP_FreeTokens (internal)
345 *
346 * Frees memory returned from HTTP_Tokenize.
347 */
348 static void HTTP_FreeTokens(LPWSTR * token_array)
349 {
350 int i;
351 for (i = 0; token_array[i]; i++)
352 HeapFree(GetProcessHeap(), 0, token_array[i]);
353 HeapFree(GetProcessHeap(), 0, token_array);
354 }
355
356 /* **********************************************************************
357 *
358 * Helper functions for the HttpSendRequest(Ex) functions
359 *
360 */
361 static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
362 {
363 struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
364 http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
365
366 TRACE("%p\n", lpwhr);
367
368 HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
369 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
370 req->dwContentLength, req->bEndRequest);
371
372 HeapFree(GetProcessHeap(), 0, req->lpszHeader);
373 }
374
375 static void HTTP_FixURL(http_request_t *lpwhr)
376 {
377 static const WCHAR szSlash[] = { '/',0 };
378 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
379
380 /* If we don't have a path we set it to root */
381 if (NULL == lpwhr->lpszPath)
382 lpwhr->lpszPath = heap_strdupW(szSlash);
383 else /* remove \r and \n*/
384 {
385 int nLen = strlenW(lpwhr->lpszPath);
386 while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
387 {
388 nLen--;
389 lpwhr->lpszPath[nLen]='\0';
390 }
391 /* Replace '\' with '/' */
392 while (nLen>0) {
393 nLen--;
394 if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
395 }
396 }
397
398 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
399 lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
400 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
401 {
402 WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
403 (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
404 *fixurl = '/';
405 strcpyW(fixurl + 1, lpwhr->lpszPath);
406 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
407 lpwhr->lpszPath = fixurl;
408 }
409 }
410
411 static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
412 {
413 LPWSTR requestString;
414 DWORD len, n;
415 LPCWSTR *req;
416 UINT i;
417 LPWSTR p;
418
419 static const WCHAR szSpace[] = { ' ',0 };
420 static const WCHAR szColon[] = { ':',' ',0 };
421 static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
422
423 /* allocate space for an array of all the string pointers to be added */
424 len = (lpwhr->nCustHeaders)*4 + 10;
425 req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
426
427 /* add the verb, path and HTTP version string */
428 n = 0;
429 req[n++] = verb;
430 req[n++] = szSpace;
431 req[n++] = path;
432 req[n++] = szSpace;
433 req[n++] = version;
434
435 /* Append custom request headers */
436 for (i = 0; i < lpwhr->nCustHeaders; i++)
437 {
438 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
439 {
440 req[n++] = szCrLf;
441 req[n++] = lpwhr->pCustHeaders[i].lpszField;
442 req[n++] = szColon;
443 req[n++] = lpwhr->pCustHeaders[i].lpszValue;
444
445 TRACE("Adding custom header %s (%s)\n",
446 debugstr_w(lpwhr->pCustHeaders[i].lpszField),
447 debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
448 }
449 }
450
451 if( n >= len )
452 ERR("oops. buffer overrun\n");
453
454 req[n] = NULL;
455 requestString = HTTP_build_req( req, 4 );
456 HeapFree( GetProcessHeap(), 0, req );
457
458 /*
459 * Set (header) termination string for request
460 * Make sure there's exactly two new lines at the end of the request
461 */
462 p = &requestString[strlenW(requestString)-1];
463 while ( (*p == '\n') || (*p == '\r') )
464 p--;
465 strcpyW( p+1, sztwocrlf );
466
467 return requestString;
468 }
469
470 static void HTTP_ProcessCookies( http_request_t *lpwhr )
471 {
472 int HeaderIndex;
473 int numCookies = 0;
474 LPHTTPHEADERW setCookieHeader;
475
476 while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
477 {
478 setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
479
480 if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
481 {
482 int len;
483 static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
484 LPWSTR buf_url;
485 LPHTTPHEADERW Host;
486
487 Host = HTTP_GetHeader(lpwhr, hostW);
488 len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath);
489 buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
490 sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath);
491 InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
492
493 HeapFree(GetProcessHeap(), 0, buf_url);
494 }
495 numCookies++;
496 }
497 }
498
499 static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
500 {
501 static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
502 return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
503 ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
504 }
505
506 static void destroy_authinfo( struct HttpAuthInfo *authinfo )
507 {
508 if (!authinfo) return;
509
510 if (SecIsValidHandle(&authinfo->ctx))
511 DeleteSecurityContext(&authinfo->ctx);
512 if (SecIsValidHandle(&authinfo->cred))
513 FreeCredentialsHandle(&authinfo->cred);
514
515 HeapFree(GetProcessHeap(), 0, authinfo->auth_data);
516 HeapFree(GetProcessHeap(), 0, authinfo->scheme);
517 HeapFree(GetProcessHeap(), 0, authinfo);
518 }
519
520 static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
521 struct HttpAuthInfo **ppAuthInfo,
522 LPWSTR domain_and_username, LPWSTR password )
523 {
524 SECURITY_STATUS sec_status;
525 struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
526 BOOL first = FALSE;
527
528 TRACE("%s\n", debugstr_w(pszAuthValue));
529
530 if (!pAuthInfo)
531 {
532 TimeStamp exp;
533
534 first = TRUE;
535 pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
536 if (!pAuthInfo)
537 return FALSE;
538
539 SecInvalidateHandle(&pAuthInfo->cred);
540 SecInvalidateHandle(&pAuthInfo->ctx);
541 memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
542 pAuthInfo->attr = 0;
543 pAuthInfo->auth_data = NULL;
544 pAuthInfo->auth_data_len = 0;
545 pAuthInfo->finished = FALSE;
546
547 if (is_basic_auth_value(pszAuthValue))
548 {
549 static const WCHAR szBasic[] = {'B','a','s','i','c',0};
550 pAuthInfo->scheme = heap_strdupW(szBasic);
551 if (!pAuthInfo->scheme)
552 {
553 HeapFree(GetProcessHeap(), 0, pAuthInfo);
554 return FALSE;
555 }
556 }
557 else
558 {
559 PVOID pAuthData;
560 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
561
562 pAuthInfo->scheme = heap_strdupW(pszAuthValue);
563 if (!pAuthInfo->scheme)
564 {
565 HeapFree(GetProcessHeap(), 0, pAuthInfo);
566 return FALSE;
567 }
568
569 if (domain_and_username)
570 {
571 WCHAR *user = strchrW(domain_and_username, '\\');
572 WCHAR *domain = domain_and_username;
573
574 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
575
576 pAuthData = &nt_auth_identity;
577
578 if (user) user++;
579 else
580 {
581 user = domain_and_username;
582 domain = NULL;
583 }
584
585 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
586 nt_auth_identity.User = user;
587 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
588 nt_auth_identity.Domain = domain;
589 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
590 nt_auth_identity.Password = password;
591 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
592 }
593 else
594 /* use default credentials */
595 pAuthData = NULL;
596
597 sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
598 SECPKG_CRED_OUTBOUND, NULL,
599 pAuthData, NULL,
600 NULL, &pAuthInfo->cred,
601 &exp);
602 if (sec_status == SEC_E_OK)
603 {
604 PSecPkgInfoW sec_pkg_info;
605 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
606 if (sec_status == SEC_E_OK)
607 {
608 pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
609 FreeContextBuffer(sec_pkg_info);
610 }
611 }
612 if (sec_status != SEC_E_OK)
613 {
614 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
615 debugstr_w(pAuthInfo->scheme), sec_status);
616 HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
617 HeapFree(GetProcessHeap(), 0, pAuthInfo);
618 return FALSE;
619 }
620 }
621 *ppAuthInfo = pAuthInfo;
622 }
623 else if (pAuthInfo->finished)
624 return FALSE;
625
626 if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
627 strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
628 {
629 ERR("authentication scheme changed from %s to %s\n",
630 debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
631 return FALSE;
632 }
633
634 if (is_basic_auth_value(pszAuthValue))
635 {
636 int userlen;
637 int passlen;
638 char *auth_data;
639
640 TRACE("basic authentication\n");
641
642 /* we don't cache credentials for basic authentication, so we can't
643 * retrieve them if the application didn't pass us any credentials */
644 if (!domain_and_username) return FALSE;
645
646 userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
647 passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
648
649 /* length includes a nul terminator, which will be re-used for the ':' */
650 auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
651 if (!auth_data)
652 return FALSE;
653
654 WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
655 auth_data[userlen] = ':';
656 WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
657
658 pAuthInfo->auth_data = auth_data;
659 pAuthInfo->auth_data_len = userlen + 1 + passlen;
660 pAuthInfo->finished = TRUE;
661
662 return TRUE;
663 }
664 else
665 {
666 LPCWSTR pszAuthData;
667 SecBufferDesc out_desc, in_desc;
668 SecBuffer out, in;
669 unsigned char *buffer;
670 ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
671 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
672
673 in.BufferType = SECBUFFER_TOKEN;
674 in.cbBuffer = 0;
675 in.pvBuffer = NULL;
676
677 in_desc.ulVersion = 0;
678 in_desc.cBuffers = 1;
679 in_desc.pBuffers = ∈
680
681 pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
682 if (*pszAuthData == ' ')
683 {
684 pszAuthData++;
685 in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
686 in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
687 HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
688 }
689
690 buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
691
692 out.BufferType = SECBUFFER_TOKEN;
693 out.cbBuffer = pAuthInfo->max_token;
694 out.pvBuffer = buffer;
695
696 out_desc.ulVersion = 0;
697 out_desc.cBuffers = 1;
698 out_desc.pBuffers = &out;
699
700 sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
701 first ? NULL : &pAuthInfo->ctx,
702 first ? lpwhr->lpHttpSession->lpszServerName : NULL,
703 context_req, 0, SECURITY_NETWORK_DREP,
704 in.pvBuffer ? &in_desc : NULL,
705 0, &pAuthInfo->ctx, &out_desc,
706 &pAuthInfo->attr, &pAuthInfo->exp);
707 if (sec_status == SEC_E_OK)
708 {
709 pAuthInfo->finished = TRUE;
710 pAuthInfo->auth_data = out.pvBuffer;
711 pAuthInfo->auth_data_len = out.cbBuffer;
712 TRACE("sending last auth packet\n");
713 }
714 else if (sec_status == SEC_I_CONTINUE_NEEDED)
715 {
716 pAuthInfo->auth_data = out.pvBuffer;
717 pAuthInfo->auth_data_len = out.cbBuffer;
718 TRACE("sending next auth packet\n");
719 }
720 else
721 {
722 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
723 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
724 destroy_authinfo(pAuthInfo);
725 *ppAuthInfo = NULL;
726 return FALSE;
727 }
728 }
729
730 return TRUE;
731 }
732
733 /***********************************************************************
734 * HTTP_HttpAddRequestHeadersW (internal)
735 */
736 static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
737 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
738 {
739 LPWSTR lpszStart;
740 LPWSTR lpszEnd;
741 LPWSTR buffer;
742 BOOL bSuccess = FALSE;
743 DWORD len;
744
745 TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
746
747 if( dwHeaderLength == ~0U )
748 len = strlenW(lpszHeader);
749 else
750 len = dwHeaderLength;
751 buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1) );
752 lstrcpynW( buffer, lpszHeader, len + 1);
753
754 lpszStart = buffer;
755
756 do
757 {
758 LPWSTR * pFieldAndValue;
759
760 lpszEnd = lpszStart;
761
762 while (*lpszEnd != '\0')
763 {
764 if (*lpszEnd == '\r' || *lpszEnd == '\n')
765 break;
766 lpszEnd++;
767 }
768
769 if (*lpszStart == '\0')
770 break;
771
772 if (*lpszEnd == '\r' || *lpszEnd == '\n')
773 {
774 *lpszEnd = '\0';
775 lpszEnd++; /* Jump over newline */
776 }
777 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
778 if (*lpszStart == '\0')
779 {
780 /* Skip 0-length headers */
781 lpszStart = lpszEnd;
782 bSuccess = TRUE;
783 continue;
784 }
785 pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
786 if (pFieldAndValue)
787 {
788 bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
789 if (bSuccess)
790 bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
791 pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
792 HTTP_FreeTokens(pFieldAndValue);
793 }
794
795 lpszStart = lpszEnd;
796 } while (bSuccess);
797
798 HeapFree(GetProcessHeap(), 0, buffer);
799
800 return bSuccess;
801 }
802
803 /***********************************************************************
804 * HttpAddRequestHeadersW (WININET.@)
805 *
806 * Adds one or more HTTP header to the request handler
807 *
808 * NOTE
809 * On Windows if dwHeaderLength includes the trailing '\0', then
810 * HttpAddRequestHeadersW() adds it too. However this results in an
811 * invalid Http header which is rejected by some servers so we probably
812 * don't need to match Windows on that point.
813 *
814 * RETURNS
815 * TRUE on success
816 * FALSE on failure
817 *
818 */
819 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
820 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
821 {
822 BOOL bSuccess = FALSE;
823 http_request_t *lpwhr;
824
825 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
826
827 if (!lpszHeader)
828 return TRUE;
829
830 lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
831 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
832 {
833 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
834 goto lend;
835 }
836 bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
837 lend:
838 if( lpwhr )
839 WININET_Release( &lpwhr->hdr );
840
841 return bSuccess;
842 }
843
844 /***********************************************************************
845 * HttpAddRequestHeadersA (WININET.@)
846 *
847 * Adds one or more HTTP header to the request handler
848 *
849 * RETURNS
850 * TRUE on success
851 * FALSE on failure
852 *
853 */
854 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
855 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
856 {
857 DWORD len;
858 LPWSTR hdr;
859 BOOL r;
860
861 TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
862
863 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
864 hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
865 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
866 if( dwHeaderLength != ~0U )
867 dwHeaderLength = len;
868
869 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
870
871 HeapFree( GetProcessHeap(), 0, hdr );
872
873 return r;
874 }
875
876 /***********************************************************************
877 * HttpEndRequestA (WININET.@)
878 *
879 * Ends an HTTP request that was started by HttpSendRequestEx
880 *
881 * RETURNS
882 * TRUE if successful
883 * FALSE on failure
884 *
885 */
886 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
887 LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
888 {
889 TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
890
891 if (lpBuffersOut)
892 {
893 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
894 return FALSE;
895 }
896
897 return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
898 }
899
900 static BOOL HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
901 {
902 BOOL rc = FALSE;
903 INT responseLen;
904 DWORD dwBufferSize;
905 INTERNET_ASYNC_RESULT iar;
906
907 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
908 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
909
910 responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
911 if (responseLen)
912 rc = TRUE;
913
914 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
915 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
916
917 /* process cookies here. Is this right? */
918 HTTP_ProcessCookies(lpwhr);
919
920 if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
921
922 if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
923 {
924 DWORD dwCode,dwCodeLength = sizeof(DWORD);
925 if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
926 (dwCode == 302 || dwCode == 301 || dwCode == 303))
927 {
928 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
929 dwBufferSize=sizeof(szNewLocation);
930 if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
931 {
932 if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
933 {
934 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
935 lpwhr->lpszVerb = heap_strdupW(szGET);
936 }
937 HTTP_DrainContent(lpwhr);
938 if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
939 {
940 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
941 new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
942 rc = HTTP_HandleRedirect(lpwhr, new_url);
943 if (rc)
944 rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
945 HeapFree( GetProcessHeap(), 0, new_url );
946 }
947 }
948 }
949 }
950
951 iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
952 iar.dwError = rc ? 0 : INTERNET_GetLastError();
953
954 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
955 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
956 sizeof(INTERNET_ASYNC_RESULT));
957 return rc;
958 }
959
960 static void AsyncHttpEndRequestProc(WORKREQUEST *work)
961 {
962 struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
963 http_request_t *lpwhr = (http_request_t*)work->hdr;
964
965 TRACE("%p\n", lpwhr);
966
967 HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
968 }
969
970 /***********************************************************************
971 * HttpEndRequestW (WININET.@)
972 *
973 * Ends an HTTP request that was started by HttpSendRequestEx
974 *
975 * RETURNS
976 * TRUE if successful
977 * FALSE on failure
978 *
979 */
980 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
981 LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
982 {
983 BOOL rc = FALSE;
984 http_request_t *lpwhr;
985
986 TRACE("-->\n");
987
988 if (lpBuffersOut)
989 {
990 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
991 return FALSE;
992 }
993
994 lpwhr = (http_request_t*) WININET_GetObject( hRequest );
995
996 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
997 {
998 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
999 if (lpwhr)
1000 WININET_Release( &lpwhr->hdr );
1001 return FALSE;
1002 }
1003 lpwhr->hdr.dwFlags |= dwFlags;
1004
1005 if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1006 {
1007 WORKREQUEST work;
1008 struct WORKREQ_HTTPENDREQUESTW *request;
1009
1010 work.asyncproc = AsyncHttpEndRequestProc;
1011 work.hdr = WININET_AddRef( &lpwhr->hdr );
1012
1013 request = &work.u.HttpEndRequestW;
1014 request->dwFlags = dwFlags;
1015 request->dwContext = dwContext;
1016
1017 INTERNET_AsyncCall(&work);
1018 INTERNET_SetLastError(ERROR_IO_PENDING);
1019 }
1020 else
1021 rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
1022
1023 WININET_Release( &lpwhr->hdr );
1024 TRACE("%i <--\n",rc);
1025 return rc;
1026 }
1027
1028 /***********************************************************************
1029 * HttpOpenRequestW (WININET.@)
1030 *
1031 * Open a HTTP request handle
1032 *
1033 * RETURNS
1034 * HINTERNET a HTTP request handle on success
1035 * NULL on failure
1036 *
1037 */
1038 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
1039 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
1040 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
1041 DWORD dwFlags, DWORD_PTR dwContext)
1042 {
1043 http_session_t *lpwhs;
1044 HINTERNET handle = NULL;
1045
1046 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1047 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
1048 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
1049 dwFlags, dwContext);
1050 if(lpszAcceptTypes!=NULL)
1051 {
1052 int i;
1053 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
1054 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
1055 }
1056
1057 lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
1058 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1059 {
1060 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1061 goto lend;
1062 }
1063
1064 /*
1065 * My tests seem to show that the windows version does not
1066 * become asynchronous until after this point. And anyhow
1067 * if this call was asynchronous then how would you get the
1068 * necessary HINTERNET pointer returned by this function.
1069 *
1070 */
1071 handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
1072 lpszVersion, lpszReferrer, lpszAcceptTypes,
1073 dwFlags, dwContext);
1074 lend:
1075 if( lpwhs )
1076 WININET_Release( &lpwhs->hdr );
1077 TRACE("returning %p\n", handle);
1078 return handle;
1079 }
1080
1081
1082 /***********************************************************************
1083 * HttpOpenRequestA (WININET.@)
1084 *
1085 * Open a HTTP request handle
1086 *
1087 * RETURNS
1088 * HINTERNET a HTTP request handle on success
1089 * NULL on failure
1090 *
1091 */
1092 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
1093 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1094 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
1095 DWORD dwFlags, DWORD_PTR dwContext)
1096 {
1097 LPWSTR szVerb = NULL, szObjectName = NULL;
1098 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
1099 INT acceptTypesCount;
1100 HINTERNET rc = FALSE;
1101 LPCSTR *types;
1102
1103 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1104 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1105 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
1106 dwFlags, dwContext);
1107
1108 if (lpszVerb)
1109 {
1110 szVerb = heap_strdupAtoW(lpszVerb);
1111 if ( !szVerb )
1112 goto end;
1113 }
1114
1115 if (lpszObjectName)
1116 {
1117 szObjectName = heap_strdupAtoW(lpszObjectName);
1118 if ( !szObjectName )
1119 goto end;
1120 }
1121
1122 if (lpszVersion)
1123 {
1124 szVersion = heap_strdupAtoW(lpszVersion);
1125 if ( !szVersion )
1126 goto end;
1127 }
1128
1129 if (lpszReferrer)
1130 {
1131 szReferrer = heap_strdupAtoW(lpszReferrer);
1132 if ( !szReferrer )
1133 goto end;
1134 }
1135
1136 if (lpszAcceptTypes)
1137 {
1138 acceptTypesCount = 0;
1139 types = lpszAcceptTypes;
1140 while (*types)
1141 {
1142 __TRY
1143 {
1144 /* find out how many there are */
1145 if (*types && **types)
1146 {
1147 TRACE("accept type: %s\n", debugstr_a(*types));
1148 acceptTypesCount++;
1149 }
1150 }
1151 __EXCEPT_PAGE_FAULT
1152 {
1153 WARN("invalid accept type pointer\n");
1154 }
1155 __ENDTRY;
1156 types++;
1157 }
1158 szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
1159 if (!szAcceptTypes) goto end;
1160
1161 acceptTypesCount = 0;
1162 types = lpszAcceptTypes;
1163 while (*types)
1164 {
1165 __TRY
1166 {
1167 if (*types && **types)
1168 szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
1169 }
1170 __EXCEPT_PAGE_FAULT
1171 {
1172 /* ignore invalid pointer */
1173 }
1174 __ENDTRY;
1175 types++;
1176 }
1177 szAcceptTypes[acceptTypesCount] = NULL;
1178 }
1179
1180 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
1181 szVersion, szReferrer,
1182 (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
1183
1184 end:
1185 if (szAcceptTypes)
1186 {
1187 acceptTypesCount = 0;
1188 while (szAcceptTypes[acceptTypesCount])
1189 {
1190 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
1191 acceptTypesCount++;
1192 }
1193 HeapFree(GetProcessHeap(), 0, szAcceptTypes);
1194 }
1195 HeapFree(GetProcessHeap(), 0, szReferrer);
1196 HeapFree(GetProcessHeap(), 0, szVersion);
1197 HeapFree(GetProcessHeap(), 0, szObjectName);
1198 HeapFree(GetProcessHeap(), 0, szVerb);
1199
1200 return rc;
1201 }
1202
1203 /***********************************************************************
1204 * HTTP_EncodeBase64
1205 */
1206 static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
1207 {
1208 UINT n = 0, x;
1209 static const CHAR HTTP_Base64Enc[] =
1210 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1211
1212 while( len > 0 )
1213 {
1214 /* first 6 bits, all from bin[0] */
1215 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1216 x = (bin[0] & 3) << 4;
1217
1218 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1219 if( len == 1 )
1220 {
1221 base64[n++] = HTTP_Base64Enc[x];
1222 base64[n++] = '=';
1223 base64[n++] = '=';
1224 break;
1225 }
1226 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1227 x = ( bin[1] & 0x0f ) << 2;
1228
1229 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1230 if( len == 2 )
1231 {
1232 base64[n++] = HTTP_Base64Enc[x];
1233 base64[n++] = '=';
1234 break;
1235 }
1236 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1237
1238 /* last 6 bits, all from bin [2] */
1239 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1240 bin += 3;
1241 len -= 3;
1242 }
1243 base64[n] = 0;
1244 return n;
1245 }
1246
1247 #define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1248 ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1249 ((x) >= '' && (x) <= '9') ? (x) - '' + 52 : \
1250 ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1251 static const signed char HTTP_Base64Dec[256] =
1252 {
1253 CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1254 CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1255 CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1256 CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1257 CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1258 CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1259 CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1260 CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1261 CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1262 CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1263 CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1264 CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1265 CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1266 CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1267 CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1268 CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1269 CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1270 CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1271 CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1272 CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1273 CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1274 CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1275 CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1276 CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1277 CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1278 CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1279 };
1280 #undef CH
1281
1282 /***********************************************************************
1283 * HTTP_DecodeBase64
1284 */
1285 static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
1286 {
1287 unsigned int n = 0;
1288
1289 while(*base64)
1290 {
1291 signed char in[4];
1292
1293 if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
1294 ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
1295 base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
1296 ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1297 {
1298 WARN("invalid base64: %s\n", debugstr_w(base64));
1299 return 0;
1300 }
1301 if (bin)
1302 bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1303 n++;
1304
1305 if ((base64[2] == '=') && (base64[3] == '='))
1306 break;
1307 if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) ||
1308 ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1309 {
1310 WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1311 return 0;
1312 }
1313 if (bin)
1314 bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1315 n++;
1316
1317 if (base64[3] == '=')
1318 break;
1319 if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) ||
1320 ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1321 {
1322 WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1323 return 0;
1324 }
1325 if (bin)
1326 bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1327 n++;
1328
1329 base64 += 4;
1330 }
1331
1332 return n;
1333 }
1334
1335 /***********************************************************************
1336 * HTTP_InsertAuthorization
1337 *
1338 * Insert or delete the authorization field in the request header.
1339 */
1340 static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
1341 {
1342 if (pAuthInfo)
1343 {
1344 static const WCHAR wszSpace[] = {' ',0};
1345 static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
1346 unsigned int len;
1347 WCHAR *authorization = NULL;
1348
1349 if (pAuthInfo->auth_data_len)
1350 {
1351 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1352 len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
1353 authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
1354 if (!authorization)
1355 return FALSE;
1356
1357 strcpyW(authorization, pAuthInfo->scheme);
1358 strcatW(authorization, wszSpace);
1359 HTTP_EncodeBase64(pAuthInfo->auth_data,
1360 pAuthInfo->auth_data_len,
1361 authorization+strlenW(authorization));
1362
1363 /* clear the data as it isn't valid now that it has been sent to the
1364 * server, unless it's Basic authentication which doesn't do
1365 * connection tracking */
1366 if (strcmpiW(pAuthInfo->scheme, wszBasic))
1367 {
1368 HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
1369 pAuthInfo->auth_data = NULL;
1370 pAuthInfo->auth_data_len = 0;
1371 }
1372 }
1373
1374 TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1375
1376 HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
1377
1378 HeapFree(GetProcessHeap(), 0, authorization);
1379 }
1380 return TRUE;
1381 }
1382
1383 static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
1384 {
1385 WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
1386 DWORD size;
1387
1388 size = sizeof(new_location);
1389 if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
1390 {
1391 if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
1392 strcpyW( url, new_location );
1393 }
1394 else
1395 {
1396 static const WCHAR slash[] = { '/',0 };
1397 static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
1398 static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
1399 http_session_t *session = req->lpHttpSession;
1400
1401 size = 16; /* "https://" + sizeof(port#) + ":/\0" */
1402 size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
1403
1404 if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
1405
1406 if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1407 sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
1408 else
1409 sprintfW( url, format, session->lpszHostName, session->nHostPort );
1410 if (req->lpszPath[0] != '/') strcatW( url, slash );
1411 strcatW( url, req->lpszPath );
1412 }
1413 TRACE("url=%s\n", debugstr_w(url));
1414 return url;
1415 }
1416
1417 /***********************************************************************
1418 * HTTP_DealWithProxy
1419 */
1420 static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
1421 {
1422 WCHAR buf[MAXHOSTNAME];
1423 WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
1424 static WCHAR szNul[] = { 0 };
1425 URL_COMPONENTSW UrlComponents;
1426 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1427 static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
1428
1429 memset( &UrlComponents, 0, sizeof UrlComponents );
1430 UrlComponents.dwStructSize = sizeof UrlComponents;
1431 UrlComponents.lpszHostName = buf;
1432 UrlComponents.dwHostNameLength = MAXHOSTNAME;
1433
1434 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1435 hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1436 sprintfW(proxy, szFormat, hIC->lpszProxy);
1437 else
1438 strcpyW(proxy, hIC->lpszProxy);
1439 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
1440 return FALSE;
1441 if( UrlComponents.dwHostNameLength == 0 )
1442 return FALSE;
1443
1444 if( !lpwhr->lpszPath )
1445 lpwhr->lpszPath = szNul;
1446
1447 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1448 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1449
1450 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1451 lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName);
1452 lpwhs->nServerPort = UrlComponents.nPort;
1453
1454 TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
1455 return TRUE;
1456 }
1457
1458 #ifndef INET6_ADDRSTRLEN
1459 #define INET6_ADDRSTRLEN 46
1460 #endif
1461
1462 static BOOL HTTP_ResolveName(http_request_t *lpwhr)
1463 {
1464 char szaddr[INET6_ADDRSTRLEN];
1465 http_session_t *lpwhs = lpwhr->lpHttpSession;
1466 const void *addr;
1467
1468 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1469 INTERNET_STATUS_RESOLVING_NAME,
1470 lpwhs->lpszServerName,
1471 strlenW(lpwhs->lpszServerName)+1);
1472
1473 lpwhs->sa_len = sizeof(lpwhs->socketAddress);
1474 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1475 (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
1476 {
1477 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1478 return FALSE;
1479 }
1480
1481 switch (lpwhs->socketAddress.ss_family)
1482 {
1483 case AF_INET:
1484 addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
1485 break;
1486 case AF_INET6:
1487 addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
1488 break;
1489 default:
1490 WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
1491 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1492 return FALSE;
1493 }
1494 inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
1495 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1496 INTERNET_STATUS_NAME_RESOLVED,
1497 szaddr, strlen(szaddr)+1);
1498
1499 TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
1500 return TRUE;
1501 }
1502
1503
1504 /***********************************************************************
1505 * HTTPREQ_Destroy (internal)
1506 *
1507 * Deallocate request handle
1508 *
1509 */
1510 static void HTTPREQ_Destroy(object_header_t *hdr)
1511 {
1512 http_request_t *lpwhr = (http_request_t*) hdr;
1513 DWORD i;
1514
1515 TRACE("\n");
1516
1517 if(lpwhr->hCacheFile)
1518 CloseHandle(lpwhr->hCacheFile);
1519
1520 HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
1521
1522 DeleteCriticalSection( &lpwhr->read_section );
1523 WININET_Release(&lpwhr->lpHttpSession->hdr);
1524
1525 destroy_authinfo(lpwhr->pAuthInfo);
1526 destroy_authinfo(lpwhr->pProxyAuthInfo);
1527
1528 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1529 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1530 HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
1531 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
1532 HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
1533
1534 for (i = 0; i < lpwhr->nCustHeaders; i++)
1535 {
1536 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1537 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1538 }
1539
1540 #ifdef HAVE_ZLIB
1541 if(lpwhr->gzip_stream) {
1542 if(!lpwhr->gzip_stream->end_of_data)
1543 inflateEnd(&lpwhr->gzip_stream->zstream);
1544 HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
1545 }
1546 #endif
1547
1548 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1549 HeapFree(GetProcessHeap(), 0, lpwhr);
1550 }
1551
1552 static void HTTPREQ_CloseConnection(object_header_t *hdr)
1553 {
1554 http_request_t *lpwhr = (http_request_t*) hdr;
1555
1556 TRACE("%p\n",lpwhr);
1557
1558 if (!NETCON_connected(&lpwhr->netConnection))
1559 return;
1560
1561 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1562 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1563
1564 NETCON_close(&lpwhr->netConnection);
1565
1566 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1567 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1568 }
1569
1570 static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1571 {
1572 LPHTTPHEADERW host_header;
1573
1574 static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1575
1576 host_header = HTTP_GetHeader(req, hostW);
1577 if(!host_header)
1578 return FALSE;
1579
1580 sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
1581 return TRUE;
1582 }
1583
1584 static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
1585 {
1586 WCHAR szVersion[10];
1587 WCHAR szConnectionResponse[20];
1588 DWORD dwBufferSize = sizeof(szVersion);
1589 BOOL keepalive = FALSE;
1590
1591 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1592 * the connection is keep-alive by default */
1593 if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion,
1594 &dwBufferSize, NULL) &&
1595 !strcmpiW(szVersion, g_szHttp1_1))
1596 {
1597 keepalive = TRUE;
1598 }
1599
1600 dwBufferSize = sizeof(szConnectionResponse);
1601 if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
1602 HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
1603 {
1604 keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1605 }
1606
1607 return keepalive;
1608 }
1609
1610 static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
1611 {
1612 http_request_t *req = (http_request_t*)hdr;
1613
1614 switch(option) {
1615 case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1616 {
1617 http_session_t *lpwhs = req->lpHttpSession;
1618 INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1619
1620 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1621
1622 if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1623 return ERROR_INSUFFICIENT_BUFFER;
1624 *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1625 /* FIXME: can't get a SOCKET from our connection since we don't use
1626 * winsock
1627 */
1628 info->Socket = 0;
1629 /* FIXME: get source port from req->netConnection */
1630 info->SourcePort = 0;
1631 info->DestPort = lpwhs->nHostPort;
1632 info->Flags = 0;
1633 if (HTTP_KeepAlive(req))
1634 info->Flags |= IDSI_FLAG_KEEP_ALIVE;
1635 if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0)
1636 info->Flags |= IDSI_FLAG_PROXY;
1637 if (req->netConnection.useSSL)
1638 info->Flags |= IDSI_FLAG_SECURE;
1639
1640 return ERROR_SUCCESS;
1641 }
1642
1643 case INTERNET_OPTION_SECURITY_FLAGS:
1644 {
1645 http_session_t *lpwhs;
1646 lpwhs = req->lpHttpSession;
1647
1648 if (*size < sizeof(ULONG))
1649 return ERROR_INSUFFICIENT_BUFFER;
1650
1651 *size = sizeof(DWORD);
1652 if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
1653 *(DWORD*)buffer = SECURITY_FLAG_SECURE;
1654 else
1655 *(DWORD*)buffer = 0;
1656 FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
1657 return ERROR_SUCCESS;
1658 }
1659
1660 case INTERNET_OPTION_HANDLE_TYPE:
1661 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1662
1663 if (*size < sizeof(ULONG))
1664 return ERROR_INSUFFICIENT_BUFFER;
1665
1666 *size = sizeof(DWORD);
1667 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
1668 return ERROR_SUCCESS;
1669
1670 case INTERNET_OPTION_URL: {
1671 WCHAR url[INTERNET_MAX_URL_LENGTH];
1672 HTTPHEADERW *host;
1673 DWORD len;
1674 WCHAR *pch;
1675
1676 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1677
1678 TRACE("INTERNET_OPTION_URL\n");
1679
1680 host = HTTP_GetHeader(req, hostW);
1681 strcpyW(url, httpW);
1682 strcatW(url, host->lpszValue);
1683 if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
1684 *pch = 0;
1685 strcatW(url, req->lpszPath);
1686
1687 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1688
1689 if(unicode) {
1690 len = (strlenW(url)+1) * sizeof(WCHAR);
1691 if(*size < len)
1692 return ERROR_INSUFFICIENT_BUFFER;
1693
1694 *size = len;
1695 strcpyW(buffer, url);
1696 return ERROR_SUCCESS;
1697 }else {
1698 len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
1699 if(len > *size)
1700 return ERROR_INSUFFICIENT_BUFFER;
1701
1702 *size = len;
1703 return ERROR_SUCCESS;
1704 }
1705 }
1706
1707 case INTERNET_OPTION_CACHE_TIMESTAMPS: {
1708 INTERNET_CACHE_ENTRY_INFOW *info;
1709 INTERNET_CACHE_TIMESTAMPS *ts = buffer;
1710 WCHAR url[INTERNET_MAX_URL_LENGTH];
1711 DWORD nbytes, error;
1712 BOOL ret;
1713
1714 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
1715
1716 if (*size < sizeof(*ts))
1717 {
1718 *size = sizeof(*ts);
1719 return ERROR_INSUFFICIENT_BUFFER;
1720 }
1721 nbytes = 0;
1722 HTTP_GetRequestURL(req, url);
1723 ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
1724 error = GetLastError();
1725 if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
1726 {
1727 if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes)))
1728 return ERROR_OUTOFMEMORY;
1729
1730 GetUrlCacheEntryInfoW(url, info, &nbytes);
1731
1732 ts->ftExpires = info->ExpireTime;
1733 ts->ftLastModified = info->LastModifiedTime;
1734
1735 HeapFree(GetProcessHeap(), 0, info);
1736 *size = sizeof(*ts);
1737 return ERROR_SUCCESS;
1738 }
1739 return error;
1740 }
1741
1742 case INTERNET_OPTION_DATAFILE_NAME: {
1743 DWORD req_size;
1744
1745 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1746
1747 if(!req->lpszCacheFile) {
1748 *size = 0;
1749 return ERROR_INTERNET_ITEM_NOT_FOUND;
1750 }
1751
1752 if(unicode) {
1753 req_size = (lstrlenW(req->lpszCacheFile)+1) * sizeof(WCHAR);
1754 if(*size < req_size)
1755 return ERROR_INSUFFICIENT_BUFFER;
1756
1757 *size = req_size;
1758 memcpy(buffer, req->lpszCacheFile, *size);
1759 return ERROR_SUCCESS;
1760 }else {
1761 req_size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile, -1, NULL, 0, NULL, NULL);
1762 if (req_size > *size)
1763 return ERROR_INSUFFICIENT_BUFFER;
1764
1765 *size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile,
1766 -1, buffer, *size, NULL, NULL);
1767 return ERROR_SUCCESS;
1768 }
1769 }
1770
1771 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
1772 PCCERT_CONTEXT context;
1773
1774 if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
1775 *size = sizeof(INTERNET_CERTIFICATE_INFOW);
1776 return ERROR_INSUFFICIENT_BUFFER;
1777 }
1778
1779 context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
1780 if(context) {
1781 INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
1782 DWORD len;
1783
1784 memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
1785 info->ftExpiry = context->pCertInfo->NotAfter;
1786 info->ftStart = context->pCertInfo->NotBefore;
1787 if(unicode) {
1788 len = CertNameToStrW(context->dwCertEncodingType,
1789 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1790 info->lpszSubjectInfo = LocalAlloc(0, len*sizeof(WCHAR));
1791 if(info->lpszSubjectInfo)
1792 CertNameToStrW(context->dwCertEncodingType,
1793 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1794 info->lpszSubjectInfo, len);
1795 len = CertNameToStrW(context->dwCertEncodingType,
1796 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1797 info->lpszIssuerInfo = LocalAlloc(0, len*sizeof(WCHAR));
1798 if (info->lpszIssuerInfo)
1799 CertNameToStrW(context->dwCertEncodingType,
1800 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1801 info->lpszIssuerInfo, len);
1802 }else {
1803 INTERNET_CERTIFICATE_INFOA *infoA = (INTERNET_CERTIFICATE_INFOA*)info;
1804
1805 len = CertNameToStrA(context->dwCertEncodingType,
1806 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1807 infoA->lpszSubjectInfo = LocalAlloc(0, len);
1808 if(infoA->lpszSubjectInfo)
1809 CertNameToStrA(context->dwCertEncodingType,
1810 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1811 infoA->lpszSubjectInfo, len);
1812 len = CertNameToStrA(context->dwCertEncodingType,
1813 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1814 infoA->lpszIssuerInfo = LocalAlloc(0, len);
1815 if(infoA->lpszIssuerInfo)
1816 CertNameToStrA(context->dwCertEncodingType,
1817 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1818 infoA->lpszIssuerInfo, len);
1819 }
1820
1821 /*
1822 * Contrary to MSDN, these do not appear to be set.
1823 * lpszProtocolName
1824 * lpszSignatureAlgName
1825 * lpszEncryptionAlgName
1826 * dwKeySize
1827 */
1828 CertFreeCertificateContext(context);
1829 return ERROR_SUCCESS;
1830 }
1831 }
1832 }
1833
1834 return INET_QueryOption(option, buffer, size, unicode);
1835 }
1836
1837 static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
1838 {
1839 http_request_t *req = (http_request_t*)hdr;
1840
1841 switch(option) {
1842 case INTERNET_OPTION_SEND_TIMEOUT:
1843 case INTERNET_OPTION_RECEIVE_TIMEOUT:
1844 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
1845
1846 if (size != sizeof(DWORD))
1847 return ERROR_INVALID_PARAMETER;
1848
1849 return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT,
1850 *(DWORD*)buffer);
1851
1852 case INTERNET_OPTION_USERNAME:
1853 HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName);
1854 if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
1855 return ERROR_SUCCESS;
1856
1857 case INTERNET_OPTION_PASSWORD:
1858 HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
1859 if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
1860 return ERROR_SUCCESS;
1861 case INTERNET_OPTION_HTTP_DECODING:
1862 if(size != sizeof(BOOL))
1863 return ERROR_INVALID_PARAMETER;
1864 req->decoding = *(BOOL*)buffer;
1865 return ERROR_SUCCESS;
1866 }
1867
1868 return ERROR_INTERNET_INVALID_OPTION;
1869 }
1870
1871 /* read some more data into the read buffer (the read section must be held) */
1872 static BOOL read_more_data( http_request_t *req, int maxlen )
1873 {
1874 int len;
1875
1876 if (req->read_pos)
1877 {
1878 /* move existing data to the start of the buffer */
1879 if(req->read_size)
1880 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
1881 req->read_pos = 0;
1882 }
1883
1884 if (maxlen == -1) maxlen = sizeof(req->read_buf);
1885
1886 if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
1887 maxlen - req->read_size, 0, &len ))
1888 return FALSE;
1889
1890 req->read_size += len;
1891 return TRUE;
1892 }
1893
1894 /* remove some amount of data from the read buffer (the read section must be held) */
1895 static void remove_data( http_request_t *req, int count )
1896 {
1897 if (!(req->read_size -= count)) req->read_pos = 0;
1898 else req->read_pos += count;
1899 }
1900
1901 static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
1902 {
1903 int count, bytes_read, pos = 0;
1904
1905 EnterCriticalSection( &req->read_section );
1906 for (;;)
1907 {
1908 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
1909
1910 if (eol)
1911 {
1912 count = eol - (req->read_buf + req->read_pos);
1913 bytes_read = count + 1;
1914 }
1915 else count = bytes_read = req->read_size;
1916
1917 count = min( count, *len - pos );
1918 memcpy( buffer + pos, req->read_buf + req->read_pos, count );
1919 pos += count;
1920 remove_data( req, bytes_read );
1921 if (eol) break;
1922
1923 if (!read_more_data( req, -1 ) || !req->read_size)
1924 {
1925 *len = 0;
1926 TRACE( "returning empty string\n" );
1927 LeaveCriticalSection( &req->read_section );
1928 return FALSE;
1929 }
1930 }
1931 LeaveCriticalSection( &req->read_section );
1932
1933 if (pos < *len)
1934 {
1935 if (pos && buffer[pos - 1] == '\r') pos--;
1936 *len = pos + 1;
1937 }
1938 buffer[*len - 1] = 0;
1939 TRACE( "returning %s\n", debugstr_a(buffer));
1940 return TRUE;
1941 }
1942
1943 /* discard data contents until we reach end of line (the read section must be held) */
1944 static BOOL discard_eol( http_request_t *req )
1945 {
1946 do
1947 {
1948 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
1949 if (eol)
1950 {
1951 remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) );
1952 break;
1953 }
1954 req->read_pos = req->read_size = 0; /* discard everything */
1955 if (!read_more_data( req, -1 )) return FALSE;
1956 } while (req->read_size);
1957 return TRUE;
1958 }
1959
1960 /* read the size of the next chunk (the read section must be held) */
1961 static BOOL start_next_chunk( http_request_t *req )
1962 {
1963 DWORD chunk_size = 0;
1964
1965 if (!req->dwContentLength) return TRUE;
1966 if (req->dwContentLength == req->dwContentRead)
1967 {
1968 /* read terminator for the previous chunk */
1969 if (!discard_eol( req )) return FALSE;
1970 req->dwContentLength = ~0u;
1971 req->dwContentRead = 0;
1972 }
1973 for (;;)
1974 {
1975 while (req->read_size)
1976 {
1977 char ch = req->read_buf[req->read_pos];
1978 if (ch >= '' && ch <= '9') chunk_size = chunk_size * 16 + ch - '';
1979 else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
1980 else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
1981 else if (ch == ';' || ch == '\r' || ch == '\n')
1982 {
1983 TRACE( "reading %u byte chunk\n", chunk_size );
1984 req->dwContentLength = chunk_size;
1985 req->dwContentRead = 0;
1986 if (!discard_eol( req )) return FALSE;
1987 return TRUE;
1988 }
1989 remove_data( req, 1 );
1990 }
1991 if (!read_more_data( req, -1 )) return FALSE;
1992 if (!req->read_size)
1993 {
1994 req->dwContentLength = req->dwContentRead = 0;
1995 return TRUE;
1996 }
1997 }
1998 }
1999
2000 /* check if we have reached the end of the data to read (the read section must be held) */
2001 static BOOL end_of_read_data( http_request_t *req )
2002 {
2003 if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2004 if (req->read_chunked) return (req->dwContentLength == 0);
2005 if (req->dwContentLength == ~0u) return FALSE;
2006 return (req->dwContentLength == req->dwContentRead);
2007 }
2008
2009 /* fetch some more data into the read buffer (the read section must be held) */
2010 static BOOL refill_buffer( http_request_t *req )
2011 {
2012 int len = sizeof(req->read_buf);
2013
2014 if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2015 {
2016 if (!start_next_chunk( req )) return FALSE;
2017 }
2018
2019 if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
2020 if (len <= req->read_size) return TRUE;
2021
2022 if (!read_more_data( req, len )) return FALSE;
2023 if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
2024 return TRUE;
2025 }
2026
2027 static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
2028 {
2029 DWORD ret = ERROR_SUCCESS;
2030 int read = 0;
2031
2032 #ifdef HAVE_ZLIB
2033 z_stream *zstream = &req->gzip_stream->zstream;
2034 int zres;
2035
2036 while(read < size && !req->gzip_stream->end_of_data) {
2037 if(!req->read_size) {
2038 if(!sync || !refill_buffer(req))
2039 break;
2040 }
2041
2042 zstream->next_in = req->read_buf+req->read_pos;
2043 zstream->avail_in = req->read_size;
2044 zstream->next_out = buf+read;
2045 zstream->avail_out = size-read;
2046 zres = inflate(zstream, Z_FULL_FLUSH);
2047 read = size - zstream->avail_out;
2048 remove_data(req, req->read_size-zstream->avail_in);
2049 if(zres == Z_STREAM_END) {
2050 TRACE("end of data\n");
2051 req->gzip_stream->end_of_data = TRUE;
2052 inflateEnd(&req->gzip_stream->zstream);
2053 }else if(zres != Z_OK) {
2054 WARN("inflate failed %d\n", zres);
2055 if(!read)
2056 ret = ERROR_INTERNET_DECODING_FAILED;
2057 break;
2058 }
2059 }
2060 #endif
2061
2062 *read_ret = read;
2063 return ret;
2064 }
2065
2066 static void refill_gzip_buffer(http_request_t *req)
2067 {
2068 DWORD res;
2069 int len;
2070
2071 if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
2072 return;
2073
2074 if(req->gzip_stream->buf_pos) {
2075 if(req->gzip_stream->buf_size)
2076 memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
2077 req->gzip_stream->buf_pos = 0;
2078 }
2079
2080 res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
2081 sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
2082 if(res == ERROR_SUCCESS)
2083 req->gzip_stream->buf_size += len;
2084 }
2085
2086 /* return the size of data available to be read immediately (the read section must be held) */
2087 static DWORD get_avail_data( http_request_t *req )
2088 {
2089 if (req->gzip_stream) {
2090 refill_gzip_buffer(req);
2091 return req->gzip_stream->buf_size;
2092 }
2093 if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2094 return 0;
2095 return min( req->read_size, req->dwContentLength - req->dwContentRead );
2096 }
2097
2098 static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2099 {
2100 INTERNET_ASYNC_RESULT iar;
2101
2102 TRACE("%p\n", req);
2103
2104 EnterCriticalSection( &req->read_section );
2105 if (refill_buffer( req )) {
2106 iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
2107 iar.dwError = first_notif ? 0 : get_avail_data(req);
2108 }else {
2109 iar.dwResult = 0;
2110 iar.dwError = INTERNET_GetLastError();
2111 }
2112 LeaveCriticalSection( &req->read_section );
2113
2114 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2115 sizeof(INTERNET_ASYNC_RESULT));
2116 }
2117
2118 /* read data from the http connection (the read section must be held) */
2119 static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
2120 {
2121 BOOL finished_reading = FALSE;
2122 int len, bytes_read = 0;
2123 DWORD ret = ERROR_SUCCESS;
2124
2125 EnterCriticalSection( &req->read_section );
2126
2127 if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2128 {
2129 if (!start_next_chunk( req )) goto done;
2130 }
2131
2132 if(req->gzip_stream) {
2133 if(req->gzip_stream->buf_size) {
2134 bytes_read = min(req->gzip_stream->buf_size, size);
2135 memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
2136 req->gzip_stream->buf_pos += bytes_read;
2137 req->gzip_stream->buf_size -= bytes_read;
2138 }else if(!req->read_size && !req->gzip_stream->end_of_data) {
2139 refill_buffer(req);
2140 }
2141
2142 if(size > bytes_read) {
2143 ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
2144 if(ret == ERROR_SUCCESS)
2145 bytes_read += len;
2146 }
2147
2148 finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2149 }else {
2150 if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
2151
2152 if (req->read_size) {
2153 bytes_read = min( req->read_size, size );
2154 memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
2155 remove_data( req, bytes_read );
2156 }
2157
2158 if (size > bytes_read && (!bytes_read || sync)) {
2159 if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
2160 sync ? MSG_WAITALL : 0, &len))
2161 bytes_read += len;
2162 /* always return success, even if the network layer returns an error */
2163 }
2164
2165 finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
2166 }
2167 done:
2168 req->dwContentRead += bytes_read;
2169 *read = bytes_read;
2170
2171 TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
2172 LeaveCriticalSection( &req->read_section );
2173
2174 if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
2175 BOOL res;
2176 DWORD dwBytesWritten;
2177
2178 res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
2179 if(!res)
2180 WARN("WriteFile failed: %u\n", GetLastError());
2181 }
2182
2183 if(finished_reading)
2184 HTTP_FinishedReading(req);
2185
2186 return ret;
2187 }
2188
2189
2190 static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
2191 {
2192 http_request_t *req = (http_request_t*)hdr;
2193 return HTTPREQ_Read(req, buffer, size, read, TRUE);
2194 }
2195
2196 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
2197 {
2198 struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
2199 http_request_t *req = (http_request_t*)workRequest->hdr;
2200 INTERNET_ASYNC_RESULT iar;
2201 DWORD res;
2202
2203 TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2204
2205 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2206 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2207
2208 iar.dwResult = res == ERROR_SUCCESS;
2209 iar.dwError = res;
2210
2211 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2212 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2213 sizeof(INTERNET_ASYNC_RESULT));
2214 }
2215
2216 static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
2217 DWORD flags, DWORD_PTR context)
2218 {
2219 http_request_t *req = (http_request_t*)hdr;
2220 DWORD res;
2221
2222 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2223 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2224
2225 if (buffers->dwStructSize != sizeof(*buffers))
2226 return ERROR_INVALID_PARAMETER;
2227
2228 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2229
2230 if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req))
2231 {
2232 WORKREQUEST workRequest;
2233
2234 if (TryEnterCriticalSection( &req->read_section ))
2235 {
2236 if (get_avail_data(req))
2237 {
2238 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2239 &buffers->dwBufferLength, FALSE);
2240 LeaveCriticalSection( &req->read_section );
2241 goto done;
2242 }
2243 LeaveCriticalSection( &req->read_section );
2244 }
2245
2246 workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2247 workRequest.hdr = WININET_AddRef(&req->hdr);
2248 workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
2249
2250 INTERNET_AsyncCall(&workRequest);
2251
2252 return ERROR_IO_PENDING;
2253 }
2254
2255 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2256 !(flags & IRF_NO_WAIT));
2257
2258 done:
2259 if (res == ERROR_SUCCESS) {
2260 DWORD size = buffers->dwBufferLength;
2261 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2262 &size, sizeof(size));
2263 }
2264
2265 return res;
2266 }
2267
2268 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2269 {
2270 struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
2271 http_request_t *req = (http_request_t*)workRequest->hdr;
2272 INTERNET_ASYNC_RESULT iar;
2273 DWORD res;
2274
2275 TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2276
2277 res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2278 data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2279
2280 iar.dwResult = res == ERROR_SUCCESS;
2281 iar.dwError = res;
2282
2283 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2284 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2285 sizeof(INTERNET_ASYNC_RESULT));
2286 }
2287
2288 static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
2289 DWORD flags, DWORD_PTR context)
2290 {
2291
2292 http_request_t *req = (http_request_t*)hdr;
2293 DWORD res;
2294
2295 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2296 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2297
2298 if (buffers->dwStructSize != sizeof(*buffers))
2299 return ERROR_INVALID_PARAMETER;
2300
2301 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2302
2303 if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
2304 {
2305 WORKREQUEST workRequest;
2306
2307 if (TryEnterCriticalSection( &req->read_section ))
2308 {
2309 if (get_avail_data(req))
2310 {
2311 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2312 &buffers->dwBufferLength, FALSE);
2313 LeaveCriticalSection( &req->read_section );
2314 goto done;
2315 }
2316 LeaveCriticalSection( &req->read_section );
2317 }
2318
2319 workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2320 workRequest.hdr = WININET_AddRef(&req->hdr);
2321 workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
2322
2323 INTERNET_AsyncCall(&workRequest);
2324
2325 return ERROR_IO_PENDING;
2326 }
2327
2328 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2329 !(flags & IRF_NO_WAIT));
2330
2331 done:
2332 if (res == ERROR_SUCCESS) {
2333 DWORD size = buffers->dwBufferLength;
2334 INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2335 &size, sizeof(size));
2336 }
2337
2338 return res;
2339 }
2340
2341 static BOOL HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
2342 {
2343 BOOL ret;
2344 http_request_t *lpwhr = (http_request_t*)hdr;
2345
2346 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2347
2348 *written = 0;
2349 if ((ret = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written)))
2350 lpwhr->dwBytesWritten += *written;
2351
2352 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
2353 return ret;
2354 }
2355
2356 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
2357 {
2358 http_request_t *req = (http_request_t*)workRequest->hdr;
2359
2360 HTTP_ReceiveRequestData(req, FALSE);
2361 }
2362
2363 static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
2364 {
2365 http_request_t *req = (http_request_t*)hdr;
2366
2367 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
2368
2369 if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2370 {
2371 WORKREQUEST workRequest;
2372
2373 /* never wait, if we can't enter the section we queue an async request right away */
2374 if (TryEnterCriticalSection( &req->read_section ))
2375 {
2376 if ((*available = get_avail_data( req ))) goto done;
2377 if (end_of_read_data( req )) goto done;
2378 LeaveCriticalSection( &req->read_section );
2379 }
2380
2381 workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
2382 workRequest.hdr = WININET_AddRef( &req->hdr );
2383
2384 INTERNET_AsyncCall(&workRequest);
2385
2386 return ERROR_IO_PENDING;
2387 }
2388
2389 EnterCriticalSection( &req->read_section );
2390
2391 if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
2392 {
2393 refill_buffer( req );
2394 *available = get_avail_data( req );
2395 }
2396
2397 done:
2398 if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */
2399 {
2400 DWORD extra;
2401 if (NETCON_query_data_available(&req->netConnection, &extra))
2402 *available = min( *available + extra, req->dwContentLength - req->dwContentRead );
2403 }
2404 LeaveCriticalSection( &req->read_section );
2405
2406 TRACE( "returning %u\n", *available );
2407 return ERROR_SUCCESS;
2408 }
2409
2410 static const object_vtbl_t HTTPREQVtbl = {
2411 HTTPREQ_Destroy,
2412 HTTPREQ_CloseConnection,
2413 HTTPREQ_QueryOption,
2414 HTTPREQ_SetOption,
2415 HTTPREQ_ReadFile,
2416 HTTPREQ_ReadFileExA,
2417 HTTPREQ_ReadFileExW,
2418 HTTPREQ_WriteFile,
2419 HTTPREQ_QueryDataAvailable,
2420 NULL
2421 };
2422
2423 /***********************************************************************
2424 * HTTP_HttpOpenRequestW (internal)
2425 *
2426 * Open a HTTP request handle
2427 *
2428 * RETURNS
2429 * HINTERNET a HTTP request handle on success
2430 * NULL on failure
2431 *
2432 */
2433 HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
2434 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
2435 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
2436 DWORD dwFlags, DWORD_PTR dwContext)
2437 {
2438 appinfo_t *hIC = NULL;
2439 http_request_t *lpwhr;
2440 LPWSTR lpszHostName = NULL;
2441 HINTERNET handle = NULL;
2442 static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
2443 DWORD len;
2444
2445 TRACE("-->\n");
2446
2447 assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
2448 hIC = lpwhs->lpAppInfo;
2449
2450 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
2451 if (NULL == lpwhr)
2452 {
2453 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2454 goto lend;
2455 }
2456 lpwhr->hdr.htype = WH_HHTTPREQ;
2457 lpwhr->hdr.vtbl = &HTTPREQVtbl;
2458 lpwhr->hdr.dwFlags = dwFlags;
2459 lpwhr->hdr.dwContext = dwContext;
2460 lpwhr->hdr.refs = 1;
2461 lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
2462 lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
2463 lpwhr->dwContentLength = ~0u;
2464 InitializeCriticalSection( &lpwhr->read_section );
2465
2466 WININET_AddRef( &lpwhs->hdr );
2467 lpwhr->lpHttpSession = lpwhs;
2468 list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
2469
2470 lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
2471 (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
2472 if (NULL == lpszHostName)
2473 {
2474 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2475 goto lend;
2476 }
2477
2478 handle = WININET_AllocHandle( &lpwhr->hdr );
2479 if (NULL == handle)
2480 {
2481 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2482 goto lend;
2483 }
2484
2485 if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
2486 {
2487 InternetCloseHandle( handle );
2488 handle = NULL;
2489 goto lend;
2490 }
2491
2492 if (lpszObjectName && *lpszObjectName) {
2493 HRESULT rc;
2494
2495 len = 0;
2496 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
2497 if (rc != E_POINTER)
2498 len = strlenW(lpszObjectName)+1;
2499 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
2500 rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
2501 URL_ESCAPE_SPACES_ONLY);
2502 if (rc != S_OK)
2503 {
2504 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
2505 strcpyW(lpwhr->lpszPath,lpszObjectName);
2506 }
2507 }else {
2508 static const WCHAR slashW[] = {'/',0};
2509
2510 lpwhr->lpszPath = heap_strdupW(slashW);
2511 }
2512
2513 if (lpszReferrer && *lpszReferrer)
2514 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2515
2516 if (lpszAcceptTypes)
2517 {
2518 int i;
2519 for (i = 0; lpszAcceptTypes[i]; i++)
2520 {
2521 if (!*lpszAcceptTypes[i]) continue;
2522 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
2523 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
2524 HTTP_ADDHDR_FLAG_REQ |
2525 (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
2526 }
2527 }
2528
2529 lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
2530 lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
2531
2532 if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
2533 lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
2534 lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
2535 {
2536 sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
2537 HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
2538 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2539 }
2540 else
2541 HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
2542 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2543
2544 if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
2545 lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
2546 INTERNET_DEFAULT_HTTPS_PORT :
2547 INTERNET_DEFAULT_HTTP_PORT);
2548
2549 if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
2550 lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
2551 INTERNET_DEFAULT_HTTPS_PORT :
2552 INTERNET_DEFAULT_HTTP_PORT);
2553
2554 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
2555 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
2556
2557 INTERNET_SendCallback(&lpwhs->hdr, dwContext,
2558 INTERNET_STATUS_HANDLE_CREATED, &handle,
2559 sizeof(handle));
2560
2561 lend:
2562 HeapFree(GetProcessHeap(), 0, lpszHostName);
2563 if( lpwhr )
2564 WININET_Release( &lpwhr->hdr );
2565
2566 TRACE("<-- %p (%p)\n", handle, lpwhr);
2567 return handle;
2568 }
2569
2570 /* read any content returned by the server so that the connection can be
2571 * reused */
2572 static void HTTP_DrainContent(http_request_t *req)
2573 {
2574 DWORD bytes_read;
2575
2576 if (!NETCON_connected(&req->netConnection)) return;
2577
2578 if (req->dwContentLength == -1)
2579 {
2580 NETCON_close(&req->netConnection);
2581 return;
2582 }
2583 if (!strcmpW(req->lpszVerb, szHEAD)) return;
2584
2585 do
2586 {
2587 char buffer[2048];
2588 if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
2589 return;
2590 } while (bytes_read);
2591 }
2592
2593 static const LPCWSTR header_lookup[] = {
2594 szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
2595 szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
2596 szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
2597 szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
2598 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
2599 szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
2600 szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
2601 szAllow, /* HTTP_QUERY_ALLOW = 7 */
2602 szPublic, /* HTTP_QUERY_PUBLIC = 8 */
2603 szDate, /* HTTP_QUERY_DATE = 9 */
2604 szExpires, /* HTTP_QUERY_EXPIRES = 10 */
2605 szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
2606 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
2607 szURI, /* HTTP_QUERY_URI = 13 */
2608 szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
2609 NULL, /* HTTP_QUERY_COST = 15 */
2610 NULL, /* HTTP_QUERY_LINK = 16 */
2611 szPragma, /* HTTP_QUERY_PRAGMA = 17 */
2612 NULL, /* HTTP_QUERY_VERSION = 18 */
2613 szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
2614 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
2615 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
2616 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
2617 szConnection, /* HTTP_QUERY_CONNECTION = 23 */
2618 szAccept, /* HTTP_QUERY_ACCEPT = 24 */
2619 szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
2620 szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
2621 szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
2622 szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
2623 szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
2624 NULL, /* HTTP_QUERY_FORWARDED = 30 */
2625 NULL, /* HTTP_QUERY_FROM = 31 */
2626 szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
2627 szLocation, /* HTTP_QUERY_LOCATION = 33 */
2628 NULL, /* HTTP_QUERY_ORIG_URI = 34 */
2629 szReferer, /* HTTP_QUERY_REFERER = 35 */
2630 szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
2631 szServer, /* HTTP_QUERY_SERVER = 37 */
2632 NULL, /* HTTP_TITLE = 38 */
2633 szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
2634 szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
2635 szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
2636 szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
2637 szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
2638 szCookie, /* HTTP_QUERY_COOKIE = 44 */
2639 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
2640 NULL, /* HTTP_QUERY_REFRESH = 46 */
2641 NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
2642 szAge, /* HTTP_QUERY_AGE = 48 */
2643 szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
2644 szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
2645 szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
2646 szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
2647 szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
2648 szETag, /* HTTP_QUERY_ETAG = 54 */
2649 hostW, /* HTTP_QUERY_HOST = 55 */
2650 szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
2651 szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
2652 szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
2653 szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
2654 szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
2655 szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
2656 szRange, /* HTTP_QUERY_RANGE = 62 */
2657 szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
2658 szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
2659 szVary, /* HTTP_QUERY_VARY = 65 */
2660 szVia, /* HTTP_QUERY_VIA = 66 */
2661 szWarning, /* HTTP_QUERY_WARNING = 67 */
2662 szExpect, /* HTTP_QUERY_EXPECT = 68 */
2663 szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
2664 szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
2665 };
2666
2667 #define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
2668
2669 /***********************************************************************
2670 * HTTP_HttpQueryInfoW (internal)
2671 */
2672 static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
2673 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
2674 {
2675 LPHTTPHEADERW lphttpHdr = NULL;
2676 BOOL bSuccess = FALSE;
2677 BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
2678 INT requested_index = lpdwIndex ? *lpdwIndex : 0;
2679 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
2680 INT index = -1;
2681
2682 /* Find requested header structure */
2683 switch (level)
2684 {
2685 case HTTP_QUERY_CUSTOM:
2686 if (!lpBuffer) return FALSE;
2687 index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
2688 break;
2689 case HTTP_QUERY_RAW_HEADERS_CRLF:
2690 {
2691 LPWSTR headers;
2692 DWORD len = 0;
2693 BOOL ret = FALSE;
2694
2695 if (request_only)
2696 headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
2697 else
2698 headers = lpwhr->lpszRawHeaders;
2699
2700 if (headers)
2701 len = strlenW(headers) * sizeof(WCHAR);
2702
2703 if (len + sizeof(WCHAR) > *lpdwBufferLength)
2704 {
2705 len += sizeof(WCHAR);
2706 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2707 ret = FALSE;
2708 }
2709 else if (lpBuffer)
2710 {
2711 if (headers)
2712 memcpy(lpBuffer, headers, len + sizeof(WCHAR));
2713 else
2714 {
2715 len = strlenW(szCrLf) * sizeof(WCHAR);
2716 memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
2717 }
2718 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
2719 ret = TRUE;
2720 }
2721 *lpdwBufferLength = len;
2722
2723 if (request_only)
2724 HeapFree(GetProcessHeap(), 0, headers);
2725 return ret;
2726 }
2727 case HTTP_QUERY_RAW_HEADERS:
2728 {
2729 LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
2730 DWORD i, size = 0;
2731 LPWSTR pszString = lpBuffer;
2732
2733 for (i = 0; ppszRawHeaderLines[i]; i++)
2734 size += strlenW(ppszRawHeaderLines[i]) + 1;
2735
2736 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
2737 {
2738 HTTP_FreeTokens(ppszRawHeaderLines);
2739 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
2740 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2741 return FALSE;
2742 }
2743 if (pszString)
2744 {
2745 for (i = 0; ppszRawHeaderLines[i]; i++)
2746 {
2747 DWORD len = strlenW(ppszRawHeaderLines[i]);
2748 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
2749 pszString += len+1;
2750 }
2751 *pszString = '\0';
2752 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
2753 }
2754 *lpdwBufferLength = size * sizeof(WCHAR);
2755 HTTP_FreeTokens(ppszRawHeaderLines);
2756
2757 return TRUE;
2758 }
2759 case HTTP_QUERY_STATUS_TEXT:
2760 if (lpwhr->lpszStatusText)
2761 {
2762 DWORD len = strlenW(lpwhr->lpszStatusText);
2763 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2764 {
2765 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2766 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2767 return FALSE;
2768 }
2769 if (lpBuffer)
2770 {
2771 memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
2772 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2773 }
2774 *lpdwBufferLength = len * sizeof(WCHAR);
2775 return TRUE;
2776 }
2777 break;
2778 case HTTP_QUERY_VERSION:
2779 if (lpwhr->lpszVersion)
2780 {
2781 DWORD len = strlenW(lpwhr->lpszVersion);
2782 if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2783 {
2784 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2785 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2786 return FALSE;
2787 }
2788 if (lpBuffer)
2789 {
2790 memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
2791 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2792 }
2793 *lpdwBufferLength = len * sizeof(WCHAR);
2794 return TRUE;
2795 }
2796 break;
2797 case HTTP_QUERY_CONTENT_ENCODING:
2798 index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
2799 requested_index,request_only);
2800 break;
2801 default:
2802 assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
2803
2804 if (level < LAST_TABLE_HEADER && header_lookup[level])
2805 index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
2806 requested_index,request_only);
2807 }
2808
2809 if (index >= 0)
2810 lphttpHdr = &lpwhr->pCustHeaders[index];
2811
2812 /* Ensure header satisfies requested attributes */
2813 if (!lphttpHdr ||
2814 ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
2815 (~lphttpHdr->wFlags & HDR_ISREQUEST)))
2816 {
2817 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
2818 return bSuccess;
2819 }
2820
2821 if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
2822
2823 /* coalesce value to requested type */
2824 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
2825 {
2826 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
2827 TRACE(" returning number: %d\n", *(int *)lpBuffer);
2828 bSuccess = TRUE;
2829 }
2830 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
2831 {
2832 time_t tmpTime;
2833 struct tm tmpTM;
2834 SYSTEMTIME *STHook;
2835
2836 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
2837
2838 tmpTM = *gmtime(&tmpTime);
2839 STHook = (SYSTEMTIME *)lpBuffer;
2840 STHook->wDay = tmpTM.tm_mday;
2841 STHook->wHour = tmpTM.tm_hour;
2842 STHook->wMilliseconds = 0;
2843 STHook->wMinute = tmpTM.tm_min;
2844 STHook->wDayOfWeek = tmpTM.tm_wday;
2845 STHook->wMonth = tmpTM.tm_mon + 1;
2846 STHook->wSecond = tmpTM.tm_sec;
2847 STHook->wYear = tmpTM.tm_year;
2848 bSuccess = TRUE;
2849
2850 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
2851 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
2852 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
2853 }
2854 else if (lphttpHdr->lpszValue)
2855 {
2856 DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
2857
2858 if (len > *lpdwBufferLength)
2859 {
2860 *lpdwBufferLength = len;
2861 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2862 return bSuccess;
2863 }
2864 if (lpBuffer)
2865 {
2866 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
2867 TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
2868 }
2869 *lpdwBufferLength = len - sizeof(WCHAR);
2870 bSuccess = TRUE;
2871 }
2872 return bSuccess;
2873 }
2874
2875 /***********************************************************************
2876 * HttpQueryInfoW (WININET.@)
2877 *
2878 * Queries for information about an HTTP request
2879 *
2880 * RETURNS
2881 * TRUE on success
2882 * FALSE on failure
2883 *
2884 */
2885 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
2886 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
2887 {
2888 BOOL bSuccess = FALSE;
2889 http_request_t *lpwhr;
2890
2891 if (TRACE_ON(wininet)) {
2892 #define FE(x) { x, #x }
2893 static const wininet_flag_info query_flags[] = {
2894 FE(HTTP_QUERY_MIME_VERSION),
2895 FE(HTTP_QUERY_CONTENT_TYPE),
2896 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
2897 FE(HTTP_QUERY_CONTENT_ID),
2898 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
2899 FE(HTTP_QUERY_CONTENT_LENGTH),
2900 FE(HTTP_QUERY_CONTENT_LANGUAGE),
2901 FE(HTTP_QUERY_ALLOW),
2902 FE(HTTP_QUERY_PUBLIC),
2903 FE(HTTP_QUERY_DATE),
2904 FE(HTTP_QUERY_EXPIRES),
2905 FE(HTTP_QUERY_LAST_MODIFIED),
2906 FE(HTTP_QUERY_MESSAGE_ID),
2907 FE(HTTP_QUERY_URI),
2908 FE(HTTP_QUERY_DERIVED_FROM),
2909 FE(HTTP_QUERY_COST),
2910 FE(HTTP_QUERY_LINK),
2911 FE(HTTP_QUERY_PRAGMA),
2912 FE(HTTP_QUERY_VERSION),
2913 FE(HTTP_QUERY_STATUS_CODE),
2914 FE(HTTP_QUERY_STATUS_TEXT),
2915 FE(HTTP_QUERY_RAW_HEADERS),
2916 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
2917 FE(HTTP_QUERY_CONNECTION),
2918 FE(HTTP_QUERY_ACCEPT),
2919 FE(HTTP_QUERY_ACCEPT_CHARSET),
2920 FE(HTTP_QUERY_ACCEPT_ENCODING),
2921 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
2922 FE(HTTP_QUERY_AUTHORIZATION),
2923 FE(HTTP_QUERY_CONTENT_ENCODING),
2924 FE(HTTP_QUERY_FORWARDED),
2925 FE(HTTP_QUERY_FROM),
2926 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
2927 FE(HTTP_QUERY_LOCATION),
2928 FE(HTTP_QUERY_ORIG_URI),
2929 FE(HTTP_QUERY_REFERER),
2930 FE(HTTP_QUERY_RETRY_AFTER),
2931 FE(HTTP_QUERY_SERVER),
2932 FE(HTTP_QUERY_TITLE),
2933 FE(HTTP_QUERY_USER_AGENT),
2934 FE(HTTP_QUERY_WWW_AUTHENTICATE),
2935 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
2936 FE(HTTP_QUERY_ACCEPT_RANGES),
2937 FE(HTTP_QUERY_SET_COOKIE),
2938 FE(HTTP_QUERY_COOKIE),
2939 FE(HTTP_QUERY_REQUEST_METHOD),
2940 FE(HTTP_QUERY_REFRESH),
2941 FE(HTTP_QUERY_CONTENT_DISPOSITION),
2942 FE(HTTP_QUERY_AGE),
2943 FE(HTTP_QUERY_CACHE_CONTROL),
2944 FE(HTTP_QUERY_CONTENT_BASE),
2945 FE(HTTP_QUERY_CONTENT_LOCATION),
2946 FE(HTTP_QUERY_CONTENT_MD5),
2947 FE(HTTP_QUERY_CONTENT_RANGE),
2948 FE(HTTP_QUERY_ETAG),
2949 FE(HTTP_QUERY_HOST),
2950 FE(HTTP_QUERY_IF_MATCH),
2951 FE(HTTP_QUERY_IF_NONE_MATCH),
2952 FE(HTTP_QUERY_IF_RANGE),
2953 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
2954 FE(HTTP_QUERY_MAX_FORWARDS),
2955 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
2956 FE(HTTP_QUERY_RANGE),
2957 FE(HTTP_QUERY_TRANSFER_ENCODING),
2958 FE(HTTP_QUERY_UPGRADE),
2959 FE(HTTP_QUERY_VARY),
2960 FE(HTTP_QUERY_VIA),
2961 FE(HTTP_QUERY_WARNING),
2962 FE(HTTP_QUERY_CUSTOM)
2963 };
2964 static const wininet_flag_info modifier_flags[] = {
2965 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
2966 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
2967 FE(HTTP_QUERY_FLAG_NUMBER),
2968 FE(HTTP_QUERY_FLAG_COALESCE)
2969 };
2970 #undef FE
2971 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
2972 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
2973 DWORD i;
2974
2975 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
2976 TRACE(" Attribute:");
2977 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
2978 if (query_flags[i].val == info) {
2979 TRACE(" %s", query_flags[i].name);
2980 break;
2981 }
2982 }
2983 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
2984 TRACE(" Unknown (%08x)", info);
2985 }
2986
2987 TRACE(" Modifier:");
2988 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
2989 if (modifier_flags[i].val & info_mod) {
2990 TRACE(" %s", modifier_flags[i].name);
2991 info_mod &= ~ modifier_flags[i].val;
2992 }
2993 }
2994
2995 if (info_mod) {
2996 TRACE(" Unknown (%08x)", info_mod);
2997 }
2998 TRACE("\n");
2999 }
3000
3001 lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3002 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3003 {
3004 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3005 goto lend;
3006 }
3007
3008 if (lpBuffer == NULL)
3009 *lpdwBufferLength = 0;
3010 bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
3011 lpBuffer, lpdwBufferLength, lpdwIndex);
3012
3013 lend:
3014 if( lpwhr )
3015 WININET_Release( &lpwhr->hdr );
3016
3017 TRACE("%d <--\n", bSuccess);
3018 return bSuccess;
3019 }
3020
3021 /***********************************************************************
3022 * HttpQueryInfoA (WININET.@)
3023 *
3024 * Queries for information about an HTTP request
3025 *
3026 * RETURNS
3027 * TRUE on success
3028 * FALSE on failure
3029 *
3030 */
3031 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
3032 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3033 {
3034 BOOL result;
3035 DWORD len;
3036 WCHAR* bufferW;
3037
3038 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3039 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3040 {
3041 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3042 lpdwBufferLength, lpdwIndex );
3043 }
3044
3045 if (lpBuffer)
3046 {
3047 DWORD alloclen;
3048 len = (*lpdwBufferLength)*sizeof(WCHAR);
3049 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3050 {
3051 alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3052 if (alloclen < len)
3053 alloclen = len;
3054 }
3055 else
3056 alloclen = len;
3057 bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
3058 /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3059 if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3060 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
3061 } else
3062 {
3063 bufferW = NULL;
3064 len = 0;
3065 }
3066
3067 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3068 &len, lpdwIndex );
3069 if( result )
3070 {
3071 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
3072 lpBuffer, *lpdwBufferLength, NULL, NULL );
3073 *lpdwBufferLength = len - 1;
3074
3075 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
3076 }
3077 else
3078 /* since the strings being returned from HttpQueryInfoW should be
3079 * only ASCII characters, it is reasonable to assume that all of
3080 * the Unicode characters can be reduced to a single byte */
3081 *lpdwBufferLength = len / sizeof(WCHAR);
3082
3083 HeapFree(GetProcessHeap(), 0, bufferW );
3084
3085 return result;
3086 }
3087
3088 /***********************************************************************
3089 * HttpSendRequestExA (WININET.@)
3090 *
3091 * Sends the specified request to the HTTP server and allows chunked
3092 * transfers.
3093 *
3094 * RETURNS
3095 * Success: TRUE
3096 * Failure: FALSE, call GetLastError() for more information.
3097 */
3098 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
3099 LPINTERNET_BUFFERSA lpBuffersIn,
3100 LPINTERNET_BUFFERSA lpBuffersOut,
3101 DWORD dwFlags, DWORD_PTR dwContext)
3102 {
3103 INTERNET_BUFFERSW BuffersInW;
3104 BOOL rc = FALSE;
3105 DWORD headerlen;
3106 LPWSTR header = NULL;
3107
3108 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3109 lpBuffersOut, dwFlags, dwContext);
3110
3111 if (lpBuffersIn)
3112 {
3113 BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
3114 if (lpBuffersIn->lpcszHeader)
3115 {
3116 headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
3117 lpBuffersIn->dwHeadersLength,0,0);
3118 header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
3119 if (!(BuffersInW.lpcszHeader = header))
3120 {
3121 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3122 return FALSE;
3123 }
3124 BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
3125 lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3126 header, headerlen);
3127 }
3128 else
3129 BuffersInW.lpcszHeader = NULL;
3130 BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
3131 BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
3132 BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
3133 BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
3134 BuffersInW.Next = NULL;
3135 }
3136
3137 rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
3138
3139 HeapFree(GetProcessHeap(),0,header);
3140
3141 return rc;
3142 }
3143
3144 /***********************************************************************
3145 * HttpSendRequestExW (WININET.@)
3146 *
3147 * Sends the specified request to the HTTP server and allows chunked
3148 * transfers
3149 *
3150 * RETURNS
3151 * Success: TRUE
3152 * Failure: FALSE, call GetLastError() for more information.
3153 */
3154 BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
3155 LPINTERNET_BUFFERSW lpBuffersIn,
3156 LPINTERNET_BUFFERSW lpBuffersOut,
3157 DWORD dwFlags, DWORD_PTR dwContext)
3158 {
3159 BOOL ret = FALSE;
3160 http_request_t *lpwhr;
3161 http_session_t *lpwhs;
3162 appinfo_t *hIC;
3163
3164 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3165 lpBuffersOut, dwFlags, dwContext);
3166
3167 lpwhr = (http_request_t*) WININET_GetObject( hRequest );
3168
3169 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3170 {
3171 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3172 goto lend;
3173 }
3174
3175 lpwhs = lpwhr->lpHttpSession;
3176 assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
3177 hIC = lpwhs->lpAppInfo;
3178 assert(hIC->hdr.htype == WH_HINIT);
3179
3180 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3181 {
3182 WORKREQUEST workRequest;
3183 struct WORKREQ_HTTPSENDREQUESTW *req;
3184
3185 workRequest.asyncproc = AsyncHttpSendRequestProc;
3186 workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3187 req = &workRequest.u.HttpSendRequestW;
3188 if (lpBuffersIn)
3189 {
3190 /* FIXME: this should use dwHeadersLength or may not be necessary at all */
3191 req->lpszHeader = heap_strdupW(lpBuffersIn->lpcszHeader);
3192 req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
3193 req->lpOptional = lpBuffersIn->lpvBuffer;
3194 req->dwOptionalLength = lpBuffersIn->dwBufferLength;
3195 req->dwContentLength = lpBuffersIn->dwBufferTotal;
3196 }
3197 else
3198 {
3199 req->lpszHeader = NULL;
3200 req->dwHeaderLength = 0;
3201 req->lpOptional = NULL;
3202 req->dwOptionalLength = 0;
3203 req->dwContentLength = 0;
3204 }
3205
3206 req->bEndRequest = FALSE;
3207
3208 INTERNET_AsyncCall(&workRequest);
3209 /*
3210 * This is from windows.
3211 */
3212 INTERNET_SetLastError(ERROR_IO_PENDING);
3213 }
3214 else
3215 {
3216 if (lpBuffersIn)
3217 ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3218 lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
3219 lpBuffersIn->dwBufferTotal, FALSE);
3220 else
3221 ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
3222 }
3223
3224 lend:
3225 if ( lpwhr )
3226 WININET_Release( &lpwhr->hdr );
3227
3228 TRACE("<---\n");
3229 return ret;
3230 }
3231
3232 /***********************************************************************
3233 * HttpSendRequestW (WININET.@)
3234 *
3235 * Sends the specified request to the HTTP server
3236 *
3237 * RETURNS
3238 * TRUE on success
3239 * FALSE on failure
3240 *
3241 */
3242 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
3243 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
3244 {
3245 http_request_t *lpwhr;
3246 http_session_t *lpwhs = NULL;
3247 appinfo_t *hIC = NULL;
3248 BOOL r;
3249
3250 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
3251 debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
3252
3253 lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3254 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3255 {
3256 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3257 r = FALSE;
3258 goto lend;
3259 }
3260
3261 lpwhs = lpwhr->lpHttpSession;
3262 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
3263 {
3264 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3265 r = FALSE;
3266 goto lend;
3267 }
3268
3269 hIC = lpwhs->lpAppInfo;
3270 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
3271 {
3272 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3273 r = FALSE;
3274 goto lend;
3275 }
3276
3277 if (hIC->hdr.dwFlags &