Commit | Line | Data |
---|---|---|
9a624916 | 1 | /* |
c275724c UC |
2 | * Wininet - Http Implementation |
3 | * | |
4 | * Copyright 1999 Corel Corporation | |
ff9b9d4e | 5 | * Copyright 2002 CodeWeavers Inc. |
852c7ae4 | 6 | * Copyright 2002 TransGaming Technologies Inc. |
ad5ff7ce | 7 | * Copyright 2004 Mike McCormack for CodeWeavers |
c275724c UC |
8 | * |
9 | * Ulrich Czekalla | |
ff9b9d4e | 10 | * Aric Stewart |
852c7ae4 | 11 | * David Hammerton |
c275724c | 12 | * |
0799c1a7 AJ |
13 | * This library is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU Lesser General Public | |
15 | * License as published by the Free Software Foundation; either | |
16 | * version 2.1 of the License, or (at your option) any later version. | |
17 | * | |
18 | * This library is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 | * Lesser General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU Lesser General Public | |
24 | * License along with this library; if not, write to the Free Software | |
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
c275724c UC |
26 | */ |
27 | ||
4710be20 PS |
28 | #include "config.h" |
29 | ||
c275724c | 30 | #include <sys/types.h> |
4710be20 PS |
31 | #ifdef HAVE_SYS_SOCKET_H |
32 | # include <sys/socket.h> | |
33 | #endif | |
e37c6e18 | 34 | #include <stdarg.h> |
c275724c UC |
35 | #include <stdio.h> |
36 | #include <stdlib.h> | |
d016f819 PS |
37 | #ifdef HAVE_UNISTD_H |
38 | # include <unistd.h> | |
39 | #endif | |
c275724c | 40 | #include <errno.h> |
4ab1558d | 41 | #include <string.h> |
b9807b40 | 42 | #include <time.h> |
3a1391b8 | 43 | #include <assert.h> |
c275724c | 44 | |
aafec988 GA |
45 | #include "windef.h" |
46 | #include "winbase.h" | |
47 | #include "wininet.h" | |
48 | #include "winreg.h" | |
49 | #include "winerror.h" | |
603f20fc | 50 | #define NO_SHLWAPI_STREAM |
aafec988 GA |
51 | #include "shlwapi.h" |
52 | ||
c275724c | 53 | #include "internet.h" |
0799c1a7 | 54 | #include "wine/debug.h" |
d476a5ad | 55 | #include "wine/unicode.h" |
c275724c | 56 | |
0799c1a7 | 57 | WINE_DEFAULT_DEBUG_CHANNEL(wininet); |
c275724c | 58 | |
6a6c85c6 FG |
59 | static const WCHAR g_szHttp[] = {' ','H','T','T','P','/','1','.','0',0 }; |
60 | static const WCHAR g_szHost[] = {'\r','\n','H','o','s','t',':',' ',0 }; | |
61 | static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0}; | |
62 | static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0}; | |
63 | static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0}; | |
a4e902cb MM |
64 | |
65 | ||
66 | #define HTTPHEADER g_szHttp | |
67 | #define HTTPHOSTHEADER g_szHost | |
c275724c UC |
68 | #define MAXHOSTNAME 100 |
69 | #define MAX_FIELD_VALUE_LEN 256 | |
70 | #define MAX_FIELD_LEN 256 | |
71 | ||
a4e902cb MM |
72 | #define HTTP_REFERER g_szReferer |
73 | #define HTTP_ACCEPT g_szAccept | |
74 | #define HTTP_USERAGENT g_szUserAgent | |
c275724c UC |
75 | |
76 | #define HTTP_ADDHDR_FLAG_ADD 0x20000000 | |
77 | #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000 | |
78 | #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000 | |
79 | #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000 | |
80 | #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000 | |
81 | #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000 | |
82 | #define HTTP_ADDHDR_FLAG_REQ 0x02000000 | |
83 | ||
84 | ||
3a1391b8 MM |
85 | static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr); |
86 | static void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr); | |
a4e902cb MM |
87 | BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr); |
88 | int HTTP_WriteDataToStream(LPWININETHTTPREQW lpwhr, | |
c275724c | 89 | void *Buffer, int BytesToWrite); |
a4e902cb | 90 | int HTTP_ReadDataFromStream(LPWININETHTTPREQW lpwhr, |
c275724c | 91 | void *Buffer, int BytesToRead); |
a4e902cb MM |
92 | BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr); |
93 | BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier); | |
48243e32 | 94 | BOOL HTTP_ReplaceHeaderValue( LPHTTPHEADERW lphttpHdr, LPCWSTR lpsztmp ); |
a4e902cb MM |
95 | void HTTP_CloseConnection(LPWININETHTTPREQW lpwhr); |
96 | BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen); | |
97 | INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField); | |
98 | BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr); | |
99 | INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField); | |
13b6ce6d | 100 | BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index); |
c275724c | 101 | |
dee8751c RS |
102 | /*********************************************************************** |
103 | * HTTP_Tokenize (internal) | |
104 | * | |
105 | * Tokenize a string, allocating memory for the tokens. | |
106 | */ | |
107 | static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) | |
108 | { | |
109 | LPWSTR * token_array; | |
110 | int tokens = 0; | |
111 | int i; | |
112 | LPCWSTR next_token; | |
113 | ||
114 | /* empty string has no tokens */ | |
115 | if (*string) | |
116 | tokens++; | |
117 | /* count tokens */ | |
118 | for (i = 0; string[i]; i++) | |
119 | if (!strncmpW(string+i, token_string, strlenW(token_string))) | |
120 | { | |
13b6ce6d | 121 | DWORD j; |
dee8751c RS |
122 | tokens++; |
123 | /* we want to skip over separators, but not the null terminator */ | |
124 | for (j = 0; j < strlenW(token_string) - 1; j++) | |
125 | if (!string[i+j]) | |
126 | break; | |
127 | i += j; | |
128 | } | |
129 | ||
130 | /* add 1 for terminating NULL */ | |
131 | token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array)); | |
132 | token_array[tokens] = NULL; | |
133 | if (!tokens) | |
134 | return token_array; | |
135 | for (i = 0; i < tokens; i++) | |
136 | { | |
137 | int len; | |
138 | next_token = strstrW(string, token_string); | |
139 | if (!next_token) next_token = string+strlenW(string); | |
140 | len = next_token - string; | |
141 | token_array[i] = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); | |
142 | memcpy(token_array[i], string, len*sizeof(WCHAR)); | |
143 | token_array[i][len] = '\0'; | |
144 | string = next_token+strlenW(token_string); | |
145 | } | |
146 | return token_array; | |
147 | } | |
148 | ||
149 | /*********************************************************************** | |
150 | * HTTP_FreeTokens (internal) | |
151 | * | |
152 | * Frees memory returned from HTTP_Tokenize. | |
153 | */ | |
154 | static void HTTP_FreeTokens(LPWSTR * token_array) | |
155 | { | |
156 | int i; | |
157 | for (i = 0; token_array[i]; i++) | |
158 | HeapFree(GetProcessHeap(), 0, token_array[i]); | |
159 | HeapFree(GetProcessHeap(), 0, token_array); | |
160 | } | |
161 | ||
c275724c | 162 | /*********************************************************************** |
b288f71e | 163 | * HTTP_HttpAddRequestHeadersW (internal) |
c275724c | 164 | */ |
b288f71e | 165 | static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, |
a4e902cb | 166 | LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) |
c275724c | 167 | { |
a4e902cb MM |
168 | LPWSTR lpszStart; |
169 | LPWSTR lpszEnd; | |
170 | LPWSTR buffer; | |
171 | WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN]; | |
c275724c | 172 | BOOL bSuccess = FALSE; |
08c6c698 | 173 | DWORD len; |
852c7ae4 | 174 | |
a4e902cb | 175 | TRACE("copying header: %s\n", debugstr_w(lpszHeader)); |
08c6c698 MM |
176 | |
177 | if( dwHeaderLength == ~0UL ) | |
178 | len = strlenW(lpszHeader); | |
179 | else | |
180 | len = dwHeaderLength; | |
181 | buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1) ); | |
182 | strncpyW( buffer, lpszHeader, len ); | |
183 | buffer[len]=0; | |
184 | ||
c275724c UC |
185 | lpszStart = buffer; |
186 | ||
187 | do | |
188 | { | |
189 | lpszEnd = lpszStart; | |
190 | ||
191 | while (*lpszEnd != '\0') | |
192 | { | |
193 | if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n') | |
194 | break; | |
195 | lpszEnd++; | |
196 | } | |
197 | ||
4cd38b48 | 198 | if (*lpszStart == '\0') |
c275724c UC |
199 | break; |
200 | ||
4cd38b48 RS |
201 | if (*lpszEnd == '\r') |
202 | { | |
203 | *lpszEnd = '\0'; | |
204 | lpszEnd += 2; /* Jump over \r\n */ | |
205 | } | |
a4e902cb | 206 | TRACE("interpreting header %s\n", debugstr_w(lpszStart)); |
c275724c UC |
207 | if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN)) |
208 | bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ); | |
209 | ||
4cd38b48 | 210 | lpszStart = lpszEnd; |
c275724c UC |
211 | |
212 | } while (bSuccess); | |
213 | ||
214 | HeapFree(GetProcessHeap(), 0, buffer); | |
b288f71e MM |
215 | |
216 | return bSuccess; | |
217 | } | |
218 | ||
219 | /*********************************************************************** | |
220 | * HttpAddRequestHeadersW (WININET.@) | |
221 | * | |
222 | * Adds one or more HTTP header to the request handler | |
223 | * | |
224 | * RETURNS | |
225 | * TRUE on success | |
226 | * FALSE on failure | |
227 | * | |
228 | */ | |
229 | BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest, | |
230 | LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) | |
231 | { | |
232 | BOOL bSuccess = FALSE; | |
233 | LPWININETHTTPREQW lpwhr; | |
234 | ||
235 | TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_w(lpszHeader), dwHeaderLength, | |
236 | dwModifier); | |
237 | ||
238 | if (!lpszHeader) | |
239 | return TRUE; | |
240 | ||
241 | lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); | |
242 | if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) | |
243 | { | |
244 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 | 245 | goto lend; |
b288f71e MM |
246 | } |
247 | bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); | |
3a1391b8 MM |
248 | lend: |
249 | if( lpwhr ) | |
250 | WININET_Release( &lpwhr->hdr ); | |
b288f71e | 251 | |
c275724c UC |
252 | return bSuccess; |
253 | } | |
254 | ||
a4e902cb MM |
255 | /*********************************************************************** |
256 | * HttpAddRequestHeadersA (WININET.@) | |
257 | * | |
258 | * Adds one or more HTTP header to the request handler | |
259 | * | |
260 | * RETURNS | |
261 | * TRUE on success | |
262 | * FALSE on failure | |
263 | * | |
264 | */ | |
265 | BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, | |
266 | LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) | |
267 | { | |
268 | DWORD len; | |
269 | LPWSTR hdr; | |
270 | BOOL r; | |
271 | ||
272 | TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_a(lpszHeader), dwHeaderLength, | |
273 | dwModifier); | |
274 | ||
275 | len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 ); | |
276 | hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); | |
277 | MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len ); | |
13b6ce6d | 278 | if( dwHeaderLength != ~0UL ) |
a4e902cb MM |
279 | dwHeaderLength = len; |
280 | ||
281 | r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier ); | |
282 | ||
283 | HeapFree( GetProcessHeap(), 0, hdr ); | |
284 | ||
285 | return r; | |
286 | } | |
287 | ||
a8b32166 CM |
288 | /*********************************************************************** |
289 | * HttpEndRequestA (WININET.@) | |
290 | * | |
291 | * Ends an HTTP request that was started by HttpSendRequestEx | |
292 | * | |
293 | * RETURNS | |
294 | * TRUE if successful | |
295 | * FALSE on failure | |
296 | * | |
297 | */ | |
298 | BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut, | |
299 | DWORD dwFlags, DWORD dwContext) | |
300 | { | |
301 | FIXME("stub\n"); | |
302 | return FALSE; | |
303 | } | |
304 | ||
305 | /*********************************************************************** | |
306 | * HttpEndRequestW (WININET.@) | |
307 | * | |
308 | * Ends an HTTP request that was started by HttpSendRequestEx | |
309 | * | |
310 | * RETURNS | |
311 | * TRUE if successful | |
312 | * FALSE on failure | |
313 | * | |
314 | */ | |
315 | BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut, | |
316 | DWORD dwFlags, DWORD dwContext) | |
317 | { | |
318 | FIXME("stub\n"); | |
319 | return FALSE; | |
320 | } | |
c275724c UC |
321 | |
322 | /*********************************************************************** | |
a4e902cb | 323 | * HttpOpenRequestW (WININET.@) |
c275724c UC |
324 | * |
325 | * Open a HTTP request handle | |
326 | * | |
327 | * RETURNS | |
328 | * HINTERNET a HTTP request handle on success | |
329 | * NULL on failure | |
330 | * | |
331 | */ | |
a4e902cb MM |
332 | HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, |
333 | LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, | |
334 | LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, | |
c275724c UC |
335 | DWORD dwFlags, DWORD dwContext) |
336 | { | |
a4e902cb | 337 | LPWININETHTTPSESSIONW lpwhs; |
09d2d477 | 338 | LPWININETAPPINFOW hIC = NULL; |
7cc70c0a | 339 | HINTERNET handle = NULL; |
c275724c | 340 | |
852c7ae4 | 341 | TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession, |
a4e902cb MM |
342 | debugstr_w(lpszVerb), debugstr_w(lpszObjectName), |
343 | debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, | |
852c7ae4 | 344 | dwFlags, dwContext); |
bc8bd722 AM |
345 | if(lpszAcceptTypes!=NULL) |
346 | { | |
347 | int i; | |
348 | for(i=0;lpszAcceptTypes[i]!=NULL;i++) | |
a4e902cb | 349 | TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); |
bc8bd722 | 350 | } |
c275724c | 351 | |
a4e902cb | 352 | lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession ); |
c275724c UC |
353 | if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) |
354 | { | |
355 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 | 356 | goto lend; |
c275724c | 357 | } |
09d2d477 | 358 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
c275724c | 359 | |
ff9b9d4e AS |
360 | /* |
361 | * My tests seem to show that the windows version does not | |
362 | * become asynchronous until after this point. And anyhow | |
363 | * if this call was asynchronous then how would you get the | |
364 | * necessary HINTERNET pointer returned by this function. | |
365 | * | |
ff9b9d4e | 366 | */ |
3a1391b8 MM |
367 | handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, |
368 | lpszVersion, lpszReferrer, lpszAcceptTypes, | |
369 | dwFlags, dwContext); | |
370 | lend: | |
371 | if( lpwhs ) | |
372 | WININET_Release( &lpwhs->hdr ); | |
7cc70c0a MM |
373 | TRACE("returning %p\n", handle); |
374 | return handle; | |
c275724c UC |
375 | } |
376 | ||
852c7ae4 | 377 | |
d476a5ad | 378 | /*********************************************************************** |
a4e902cb | 379 | * HttpOpenRequestA (WININET.@) |
d476a5ad AM |
380 | * |
381 | * Open a HTTP request handle | |
382 | * | |
383 | * RETURNS | |
384 | * HINTERNET a HTTP request handle on success | |
385 | * NULL on failure | |
386 | * | |
387 | */ | |
a4e902cb MM |
388 | HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, |
389 | LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion, | |
390 | LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes, | |
d476a5ad AM |
391 | DWORD dwFlags, DWORD dwContext) |
392 | { | |
a4e902cb MM |
393 | LPWSTR szVerb = NULL, szObjectName = NULL; |
394 | LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; | |
852c7ae4 DH |
395 | INT len; |
396 | INT acceptTypesCount; | |
397 | HINTERNET rc = FALSE; | |
398 | TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession, | |
a4e902cb MM |
399 | debugstr_a(lpszVerb), debugstr_a(lpszObjectName), |
400 | debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes, | |
852c7ae4 DH |
401 | dwFlags, dwContext); |
402 | ||
403 | if (lpszVerb) | |
404 | { | |
a4e902cb MM |
405 | len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 ); |
406 | szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); | |
43629c9b | 407 | if ( !szVerb ) |
852c7ae4 | 408 | goto end; |
a4e902cb | 409 | MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len); |
852c7ae4 | 410 | } |
bc8bd722 | 411 | |
852c7ae4 DH |
412 | if (lpszObjectName) |
413 | { | |
a4e902cb MM |
414 | len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 ); |
415 | szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); | |
43629c9b | 416 | if ( !szObjectName ) |
852c7ae4 | 417 | goto end; |
a4e902cb | 418 | MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len ); |
852c7ae4 DH |
419 | } |
420 | ||
421 | if (lpszVersion) | |
422 | { | |
a4e902cb MM |
423 | len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 ); |
424 | szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | |
43629c9b | 425 | if ( !szVersion ) |
852c7ae4 | 426 | goto end; |
a4e902cb | 427 | MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len ); |
852c7ae4 DH |
428 | } |
429 | ||
430 | if (lpszReferrer) | |
431 | { | |
a4e902cb MM |
432 | len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 ); |
433 | szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | |
43629c9b | 434 | if ( !szReferrer ) |
852c7ae4 | 435 | goto end; |
a4e902cb | 436 | MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len ); |
852c7ae4 DH |
437 | } |
438 | ||
439 | acceptTypesCount = 0; | |
440 | if (lpszAcceptTypes) | |
441 | { | |
a4e902cb MM |
442 | /* find out how many there are */ |
443 | while (lpszAcceptTypes[acceptTypesCount]) | |
444 | acceptTypesCount++; | |
445 | szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1)); | |
852c7ae4 DH |
446 | acceptTypesCount = 0; |
447 | while (lpszAcceptTypes[acceptTypesCount]) | |
448 | { | |
a4e902cb MM |
449 | len = MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount], |
450 | -1, NULL, 0 ); | |
451 | szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | |
43629c9b | 452 | if (!szAcceptTypes[acceptTypesCount] ) |
852c7ae4 | 453 | goto end; |
a4e902cb MM |
454 | MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount], |
455 | -1, szAcceptTypes[acceptTypesCount], len ); | |
852c7ae4 DH |
456 | acceptTypesCount++; |
457 | } | |
a4e902cb | 458 | szAcceptTypes[acceptTypesCount] = NULL; |
852c7ae4 DH |
459 | } |
460 | else szAcceptTypes = 0; | |
461 | ||
a4e902cb MM |
462 | rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, |
463 | szVersion, szReferrer, | |
464 | (LPCWSTR*)szAcceptTypes, dwFlags, dwContext); | |
852c7ae4 DH |
465 | |
466 | end: | |
467 | if (szAcceptTypes) | |
468 | { | |
469 | acceptTypesCount = 0; | |
470 | while (szAcceptTypes[acceptTypesCount]) | |
471 | { | |
472 | HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]); | |
473 | acceptTypesCount++; | |
474 | } | |
475 | HeapFree(GetProcessHeap(), 0, szAcceptTypes); | |
476 | } | |
477 | if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer); | |
478 | if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion); | |
479 | if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName); | |
480 | if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb); | |
481 | ||
482 | return rc; | |
d476a5ad | 483 | } |
c275724c | 484 | |
a1c16d28 MM |
485 | /*********************************************************************** |
486 | * HTTP_Base64 | |
487 | */ | |
09d2d477 | 488 | static UINT HTTP_Base64( LPCWSTR bin, LPWSTR base64 ) |
a1c16d28 MM |
489 | { |
490 | UINT n = 0, x; | |
491 | static LPSTR HTTP_Base64Enc = | |
492 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
493 | ||
494 | while( bin[0] ) | |
495 | { | |
496 | /* first 6 bits, all from bin[0] */ | |
497 | base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2]; | |
498 | x = (bin[0] & 3) << 4; | |
499 | ||
500 | /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ | |
501 | if( !bin[1] ) | |
502 | { | |
503 | base64[n++] = HTTP_Base64Enc[x]; | |
504 | base64[n++] = '='; | |
505 | base64[n++] = '='; | |
506 | break; | |
507 | } | |
508 | base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ]; | |
509 | x = ( bin[1] & 0x0f ) << 2; | |
510 | ||
511 | /* next 6 bits 4 from bin[1] and 2 from bin[2] */ | |
512 | if( !bin[2] ) | |
513 | { | |
514 | base64[n++] = HTTP_Base64Enc[x]; | |
515 | base64[n++] = '='; | |
516 | break; | |
517 | } | |
518 | base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ]; | |
519 | ||
520 | /* last 6 bits, all from bin [2] */ | |
521 | base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ]; | |
522 | bin += 3; | |
523 | } | |
524 | base64[n] = 0; | |
525 | return n; | |
526 | } | |
527 | ||
528 | /*********************************************************************** | |
529 | * HTTP_EncodeBasicAuth | |
530 | * | |
531 | * Encode the basic authentication string for HTTP 1.1 | |
532 | */ | |
09d2d477 | 533 | static LPWSTR HTTP_EncodeBasicAuth( LPCWSTR username, LPCWSTR password) |
a1c16d28 MM |
534 | { |
535 | UINT len; | |
09d2d477 | 536 | LPWSTR in, out; |
6a6c85c6 FG |
537 | static const WCHAR szBasic[] = {'B','a','s','i','c',' ',0}; |
538 | static const WCHAR szColon[] = {':',0}; | |
a1c16d28 | 539 | |
09d2d477 MM |
540 | len = lstrlenW( username ) + 1 + lstrlenW ( password ) + 1; |
541 | in = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); | |
a1c16d28 MM |
542 | if( !in ) |
543 | return NULL; | |
544 | ||
09d2d477 MM |
545 | len = lstrlenW(szBasic) + |
546 | (lstrlenW( username ) + 1 + lstrlenW ( password ))*2 + 1 + 1; | |
a4e902cb | 547 | out = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); |
a1c16d28 MM |
548 | if( out ) |
549 | { | |
09d2d477 MM |
550 | lstrcpyW( in, username ); |
551 | lstrcatW( in, szColon ); | |
552 | lstrcatW( in, password ); | |
553 | lstrcpyW( out, szBasic ); | |
554 | HTTP_Base64( in, &out[strlenW(out)] ); | |
a1c16d28 MM |
555 | } |
556 | HeapFree( GetProcessHeap(), 0, in ); | |
557 | ||
558 | return out; | |
559 | } | |
560 | ||
561 | /*********************************************************************** | |
562 | * HTTP_InsertProxyAuthorization | |
563 | * | |
564 | * Insert the basic authorization field in the request header | |
565 | */ | |
a4e902cb | 566 | BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr, |
09d2d477 | 567 | LPCWSTR username, LPCWSTR password ) |
a1c16d28 | 568 | { |
a4e902cb MM |
569 | HTTPHEADERW hdr; |
570 | INT index; | |
6a6c85c6 | 571 | static const WCHAR szProxyAuthorization[] = { |
a4e902cb | 572 | 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; |
a1c16d28 | 573 | |
a4e902cb | 574 | hdr.lpszValue = HTTP_EncodeBasicAuth( username, password ); |
286fe0af | 575 | hdr.lpszField = (WCHAR *)szProxyAuthorization; |
a1c16d28 MM |
576 | hdr.wFlags = HDR_ISREQUEST; |
577 | hdr.wCount = 0; | |
578 | if( !hdr.lpszValue ) | |
579 | return FALSE; | |
580 | ||
581 | TRACE("Inserting %s = %s\n", | |
a4e902cb | 582 | debugstr_w( hdr.lpszField ), debugstr_w( hdr.lpszValue ) ); |
a1c16d28 MM |
583 | |
584 | /* remove the old proxy authorization header */ | |
585 | index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField ); | |
586 | if( index >=0 ) | |
587 | HTTP_DeleteCustomHeader( lpwhr, index ); | |
588 | ||
589 | HTTP_InsertCustomHeader(lpwhr, &hdr); | |
590 | HeapFree( GetProcessHeap(), 0, hdr.lpszValue ); | |
591 | ||
592 | return TRUE; | |
593 | } | |
594 | ||
595 | /*********************************************************************** | |
596 | * HTTP_DealWithProxy | |
597 | */ | |
09d2d477 | 598 | static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, |
a4e902cb | 599 | LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr) |
a1c16d28 | 600 | { |
a4e902cb MM |
601 | WCHAR buf[MAXHOSTNAME]; |
602 | WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ | |
8fc374d8 FG |
603 | WCHAR* url; |
604 | static const WCHAR szNul[] = { 0 }; | |
a4e902cb | 605 | URL_COMPONENTSW UrlComponents; |
8fc374d8 | 606 | static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }, szSlash[] = { '/',0 } ; |
a9b405cf | 607 | static const WCHAR szFormat1[] = { 'h','t','t','p',':','/','/','%','s',0 }; |
8fc374d8 | 608 | static const WCHAR szFormat2[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 }; |
a4e902cb | 609 | int len; |
a1c16d28 MM |
610 | |
611 | memset( &UrlComponents, 0, sizeof UrlComponents ); | |
612 | UrlComponents.dwStructSize = sizeof UrlComponents; | |
613 | UrlComponents.lpszHostName = buf; | |
614 | UrlComponents.dwHostNameLength = MAXHOSTNAME; | |
615 | ||
a4e902cb MM |
616 | if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, |
617 | buf,strlenW(szHttp),szHttp,strlenW(szHttp)) ) | |
618 | sprintfW(proxy, szFormat1, hIC->lpszProxy); | |
599c4522 | 619 | else |
a4e902cb MM |
620 | strcpyW(proxy,buf); |
621 | if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) ) | |
a1c16d28 MM |
622 | return FALSE; |
623 | if( UrlComponents.dwHostNameLength == 0 ) | |
624 | return FALSE; | |
625 | ||
626 | if( !lpwhr->lpszPath ) | |
8fc374d8 | 627 | lpwhr->lpszPath = (LPWSTR)szNul; |
a1c16d28 | 628 | TRACE("server='%s' path='%s'\n", |
a4e902cb | 629 | debugstr_w(lpwhs->lpszServerName), debugstr_w(lpwhr->lpszPath)); |
a1c16d28 | 630 | /* for constant 15 see above */ |
a4e902cb MM |
631 | len = strlenW(lpwhs->lpszServerName) + strlenW(lpwhr->lpszPath) + 15; |
632 | url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | |
a1c16d28 MM |
633 | |
634 | if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) | |
635 | UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; | |
636 | ||
a4e902cb MM |
637 | sprintfW(url, szFormat2, lpwhs->lpszServerName, lpwhs->nServerPort); |
638 | ||
a1c16d28 | 639 | if( lpwhr->lpszPath[0] != '/' ) |
a4e902cb MM |
640 | strcatW( url, szSlash ); |
641 | strcatW(url, lpwhr->lpszPath); | |
a1c16d28 MM |
642 | if(lpwhr->lpszPath != szNul) |
643 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); | |
644 | lpwhr->lpszPath = url; | |
645 | /* FIXME: Do I have to free lpwhs->lpszServerName here ? */ | |
a4e902cb | 646 | lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName); |
a1c16d28 MM |
647 | lpwhs->nServerPort = UrlComponents.nPort; |
648 | ||
649 | return TRUE; | |
650 | } | |
651 | ||
c275724c | 652 | /*********************************************************************** |
a4e902cb | 653 | * HTTP_HttpOpenRequestW (internal) |
c275724c UC |
654 | * |
655 | * Open a HTTP request handle | |
656 | * | |
657 | * RETURNS | |
658 | * HINTERNET a HTTP request handle on success | |
659 | * NULL on failure | |
660 | * | |
661 | */ | |
3a1391b8 | 662 | HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, |
a4e902cb MM |
663 | LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, |
664 | LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, | |
c275724c UC |
665 | DWORD dwFlags, DWORD dwContext) |
666 | { | |
09d2d477 | 667 | LPWININETAPPINFOW hIC = NULL; |
a4e902cb MM |
668 | LPWININETHTTPREQW lpwhr; |
669 | LPWSTR lpszCookies; | |
670 | LPWSTR lpszUrl = NULL; | |
852c7ae4 | 671 | DWORD nCookieSize; |
3a1391b8 | 672 | HINTERNET handle = NULL; |
6a6c85c6 | 673 | static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0}; |
a4e902cb | 674 | DWORD len; |
c275724c | 675 | |
ff9b9d4e | 676 | TRACE("--> \n"); |
c275724c | 677 | |
3a1391b8 | 678 | assert( lpwhs->hdr.htype == WH_HHTTPSESSION ); |
09d2d477 | 679 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
c275724c | 680 | |
a4e902cb | 681 | lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW)); |
c275724c UC |
682 | if (NULL == lpwhr) |
683 | { | |
684 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
3a1391b8 | 685 | goto lend; |
7cc70c0a | 686 | } |
3a1391b8 MM |
687 | lpwhr->hdr.htype = WH_HHTTPREQ; |
688 | lpwhr->hdr.lpwhparent = WININET_AddRef( &lpwhs->hdr ); | |
689 | lpwhr->hdr.dwFlags = dwFlags; | |
690 | lpwhr->hdr.dwContext = dwContext; | |
691 | lpwhr->hdr.dwRefCount = 1; | |
692 | lpwhr->hdr.destroy = HTTP_CloseHTTPRequestHandle; | |
693 | ||
7cc70c0a MM |
694 | handle = WININET_AllocHandle( &lpwhr->hdr ); |
695 | if (NULL == handle) | |
696 | { | |
697 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
3a1391b8 | 698 | goto lend; |
c275724c UC |
699 | } |
700 | ||
852c7ae4 | 701 | NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE); |
c275724c | 702 | |
a4e902cb | 703 | if (NULL != lpszObjectName && strlenW(lpszObjectName)) { |
ff9b9d4e | 704 | HRESULT rc; |
a4e902cb MM |
705 | |
706 | len = 0; | |
707 | rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY); | |
ff9b9d4e | 708 | if (rc != E_POINTER) |
a4e902cb MM |
709 | len = strlenW(lpszObjectName)+1; |
710 | lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | |
711 | rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len, | |
0aebee98 | 712 | URL_ESCAPE_SPACES_ONLY); |
ff9b9d4e AS |
713 | if (rc) |
714 | { | |
a4e902cb MM |
715 | ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(lpszObjectName),rc); |
716 | strcpyW(lpwhr->lpszPath,lpszObjectName); | |
ff9b9d4e | 717 | } |
0aebee98 | 718 | } |
c275724c | 719 | |
a4e902cb | 720 | if (NULL != lpszReferrer && strlenW(lpszReferrer)) |
852c7ae4 | 721 | HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE); |
c275724c | 722 | |
bc8bd722 AM |
723 | if(lpszAcceptTypes!=NULL) |
724 | { | |
725 | int i; | |
726 | for(i=0;lpszAcceptTypes[i]!=NULL;i++) | |
727 | HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW); | |
728 | } | |
c275724c UC |
729 | |
730 | if (NULL == lpszVerb) | |
a4e902cb | 731 | { |
6a6c85c6 | 732 | static const WCHAR szGet[] = {'G','E','T',0}; |
a4e902cb MM |
733 | lpwhr->lpszVerb = WININET_strdupW(szGet); |
734 | } | |
735 | else if (strlenW(lpszVerb)) | |
736 | lpwhr->lpszVerb = WININET_strdupW(lpszVerb); | |
c275724c | 737 | |
a4e902cb | 738 | if (NULL != lpszReferrer && strlenW(lpszReferrer)) |
c275724c | 739 | { |
a4e902cb MM |
740 | WCHAR buf[MAXHOSTNAME]; |
741 | URL_COMPONENTSW UrlComponents; | |
c275724c | 742 | |
a1c16d28 MM |
743 | memset( &UrlComponents, 0, sizeof UrlComponents ); |
744 | UrlComponents.dwStructSize = sizeof UrlComponents; | |
c275724c UC |
745 | UrlComponents.lpszHostName = buf; |
746 | UrlComponents.dwHostNameLength = MAXHOSTNAME; | |
747 | ||
a4e902cb MM |
748 | InternetCrackUrlW(lpszReferrer, 0, 0, &UrlComponents); |
749 | if (strlenW(UrlComponents.lpszHostName)) | |
750 | lpwhr->lpszHostName = WININET_strdupW(UrlComponents.lpszHostName); | |
34965563 | 751 | } else { |
a4e902cb | 752 | lpwhr->lpszHostName = WININET_strdupW(lpwhs->lpszServerName); |
c275724c | 753 | } |
a1c16d28 MM |
754 | if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) |
755 | HTTP_DealWithProxy( hIC, lpwhs, lpwhr ); | |
c275724c | 756 | |
852c7ae4 DH |
757 | if (hIC->lpszAgent) |
758 | { | |
a4e902cb | 759 | WCHAR *agent_header; |
6a6c85c6 | 760 | static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0 }; |
09d2d477 | 761 | |
a4e902cb MM |
762 | len = strlenW(hIC->lpszAgent) + strlenW(user_agent); |
763 | agent_header = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); | |
764 | sprintfW(agent_header, user_agent, hIC->lpszAgent ); | |
09d2d477 | 765 | |
b288f71e | 766 | HTTP_HttpAddRequestHeadersW(lpwhr, agent_header, strlenW(agent_header), |
852c7ae4 DH |
767 | HTTP_ADDREQ_FLAG_ADD); |
768 | HeapFree(GetProcessHeap(), 0, agent_header); | |
769 | } | |
770 | ||
a4e902cb MM |
771 | len = strlenW(lpwhr->lpszHostName) + strlenW(szUrlForm); |
772 | lpszUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | |
773 | sprintfW( lpszUrl, szUrlForm, lpwhr->lpszHostName ); | |
774 | ||
d6315926 RS |
775 | if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && |
776 | InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize)) | |
852c7ae4 DH |
777 | { |
778 | int cnt = 0; | |
6a6c85c6 FG |
779 | static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0}; |
780 | static const WCHAR szcrlf[] = {'\r','\n',0}; | |
852c7ae4 | 781 | |
a4e902cb | 782 | lpszCookies = HeapAlloc(GetProcessHeap(), 0, (nCookieSize + 1 + 8)*sizeof(WCHAR)); |
852c7ae4 | 783 | |
a4e902cb MM |
784 | cnt += sprintfW(lpszCookies, szCookie); |
785 | InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize); | |
786 | strcatW(lpszCookies, szcrlf); | |
852c7ae4 | 787 | |
b288f71e | 788 | HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), |
852c7ae4 DH |
789 | HTTP_ADDREQ_FLAG_ADD); |
790 | HeapFree(GetProcessHeap(), 0, lpszCookies); | |
791 | } | |
792 | HeapFree(GetProcessHeap(), 0, lpszUrl); | |
793 | ||
794 | ||
795 | ||
c275724c UC |
796 | if (hIC->lpfnStatusCB) |
797 | { | |
798 | INTERNET_ASYNC_RESULT iar; | |
799 | ||
a29b4c7c | 800 | iar.dwResult = (DWORD)handle; |
c275724c UC |
801 | iar.dwError = ERROR_SUCCESS; |
802 | ||
3a1391b8 | 803 | SendAsyncCallback(hIC, &lpwhs->hdr, dwContext, |
ff9b9d4e AS |
804 | INTERNET_STATUS_HANDLE_CREATED, &iar, |
805 | sizeof(INTERNET_ASYNC_RESULT)); | |
c275724c UC |
806 | } |
807 | ||
ff9b9d4e AS |
808 | /* |
809 | * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows | |
810 | */ | |
9a624916 | 811 | |
ff9b9d4e AS |
812 | /* |
813 | * According to my tests. The name is not resolved until a request is Opened | |
814 | */ | |
3a1391b8 | 815 | SendAsyncCallback(hIC, &lpwhs->hdr, dwContext, |
ff9b9d4e AS |
816 | INTERNET_STATUS_RESOLVING_NAME, |
817 | lpwhs->lpszServerName, | |
a4e902cb | 818 | strlenW(lpwhs->lpszServerName)+1); |
ff9b9d4e AS |
819 | if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, |
820 | &lpwhs->phostent, &lpwhs->socketAddress)) | |
821 | { | |
822 | INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); | |
3a1391b8 MM |
823 | InternetCloseHandle( handle ); |
824 | handle = NULL; | |
825 | goto lend; | |
c275724c UC |
826 | } |
827 | ||
3a1391b8 | 828 | SendAsyncCallback(hIC, &lpwhs->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e AS |
829 | INTERNET_STATUS_NAME_RESOLVED, |
830 | &(lpwhs->socketAddress), | |
831 | sizeof(struct sockaddr_in)); | |
832 | ||
3a1391b8 MM |
833 | lend: |
834 | if( lpwhr ) | |
835 | WININET_Release( &lpwhr->hdr ); | |
836 | ||
837 | TRACE("<-- %p (%p)\n", handle, lpwhr); | |
7cc70c0a | 838 | return handle; |
c275724c UC |
839 | } |
840 | ||
c275724c | 841 | /*********************************************************************** |
b288f71e | 842 | * HTTP_HttpQueryInfoW (internal) |
c275724c | 843 | */ |
b288f71e | 844 | BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, |
c275724c UC |
845 | LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) |
846 | { | |
a4e902cb | 847 | LPHTTPHEADERW lphttpHdr = NULL; |
c275724c | 848 | BOOL bSuccess = FALSE; |
9a624916 | 849 | |
c275724c UC |
850 | /* Find requested header structure */ |
851 | if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM) | |
852 | { | |
a4e902cb | 853 | INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPWSTR)lpBuffer); |
c275724c UC |
854 | |
855 | if (index < 0) | |
b288f71e | 856 | return bSuccess; |
c275724c UC |
857 | |
858 | lphttpHdr = &lpwhr->pCustHeaders[index]; | |
859 | } | |
860 | else | |
861 | { | |
862 | INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK; | |
863 | ||
48243e32 | 864 | if (index == HTTP_QUERY_RAW_HEADERS_CRLF) |
dee8751c | 865 | { |
13b6ce6d | 866 | DWORD len = strlenW(lpwhr->lpszRawHeaders); |
dee8751c RS |
867 | if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) |
868 | { | |
869 | *lpdwBufferLength = (len + 1) * sizeof(WCHAR); | |
870 | INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); | |
871 | return FALSE; | |
872 | } | |
873 | memcpy(lpBuffer, lpwhr->lpszRawHeaders, (len+1)*sizeof(WCHAR)); | |
4385d305 RS |
874 | *lpdwBufferLength = len * sizeof(WCHAR); |
875 | ||
876 | TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); | |
877 | ||
dee8751c RS |
878 | return TRUE; |
879 | } | |
880 | else if (index == HTTP_QUERY_RAW_HEADERS) | |
881 | { | |
882 | static const WCHAR szCrLf[] = {'\r','\n',0}; | |
883 | LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf); | |
13b6ce6d | 884 | DWORD i, size = 0; |
dee8751c RS |
885 | LPWSTR pszString = (WCHAR*)lpBuffer; |
886 | ||
887 | for (i = 0; ppszRawHeaderLines[i]; i++) | |
888 | size += strlenW(ppszRawHeaderLines[i]) + 1; | |
889 | ||
890 | if (size + 1 > *lpdwBufferLength/sizeof(WCHAR)) | |
891 | { | |
892 | HTTP_FreeTokens(ppszRawHeaderLines); | |
893 | *lpdwBufferLength = (size + 1) * sizeof(WCHAR); | |
894 | INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); | |
895 | return FALSE; | |
896 | } | |
897 | ||
898 | for (i = 0; ppszRawHeaderLines[i]; i++) | |
899 | { | |
13b6ce6d | 900 | DWORD len = strlenW(ppszRawHeaderLines[i]); |
dee8751c RS |
901 | memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); |
902 | pszString += len+1; | |
903 | } | |
904 | *pszString = '\0'; | |
905 | ||
906 | TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size)); | |
907 | ||
4385d305 | 908 | *lpdwBufferLength = size * sizeof(WCHAR); |
dee8751c RS |
909 | HTTP_FreeTokens(ppszRawHeaderLines); |
910 | ||
911 | return TRUE; | |
912 | } | |
c275724c | 913 | else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue) |
9a624916 | 914 | { |
c275724c UC |
915 | lphttpHdr = &lpwhr->StdHeaders[index]; |
916 | } | |
917 | else | |
48243e32 AJ |
918 | { |
919 | SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); | |
b288f71e | 920 | return bSuccess; |
48243e32 | 921 | } |
c275724c UC |
922 | } |
923 | ||
924 | /* Ensure header satisifies requested attributes */ | |
9a624916 | 925 | if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && |
c275724c | 926 | (~lphttpHdr->wFlags & HDR_ISREQUEST)) |
48243e32 AJ |
927 | { |
928 | SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); | |
b288f71e | 929 | return bSuccess; |
48243e32 | 930 | } |
9a624916 | 931 | |
c275724c UC |
932 | /* coalesce value to reuqested type */ |
933 | if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) | |
934 | { | |
a4e902cb | 935 | *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); |
1d5e6b67 LU |
936 | bSuccess = TRUE; |
937 | ||
938 | TRACE(" returning number : %d\n", *(int *)lpBuffer); | |
c275724c UC |
939 | } |
940 | else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME) | |
941 | { | |
942 | time_t tmpTime; | |
943 | struct tm tmpTM; | |
944 | SYSTEMTIME *STHook; | |
9a624916 | 945 | |
c275724c UC |
946 | tmpTime = ConvertTimeString(lphttpHdr->lpszValue); |
947 | ||
948 | tmpTM = *gmtime(&tmpTime); | |
949 | STHook = (SYSTEMTIME *) lpBuffer; | |
950 | if(STHook==NULL) | |
b288f71e | 951 | return bSuccess; |
c275724c | 952 | |
1d5e6b67 LU |
953 | STHook->wDay = tmpTM.tm_mday; |
954 | STHook->wHour = tmpTM.tm_hour; | |
955 | STHook->wMilliseconds = 0; | |
956 | STHook->wMinute = tmpTM.tm_min; | |
957 | STHook->wDayOfWeek = tmpTM.tm_wday; | |
958 | STHook->wMonth = tmpTM.tm_mon + 1; | |
959 | STHook->wSecond = tmpTM.tm_sec; | |
960 | STHook->wYear = tmpTM.tm_year; | |
961 | ||
962 | bSuccess = TRUE; | |
963 | ||
964 | TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", | |
965 | STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, | |
966 | STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); | |
c275724c UC |
967 | } |
968 | else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE) | |
969 | { | |
970 | if (*lpdwIndex >= lphttpHdr->wCount) | |
971 | { | |
972 | INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); | |
973 | } | |
974 | else | |
975 | { | |
a4e902cb | 976 | /* Copy strncpyW(lpBuffer, lphttpHdr[*lpdwIndex], len); */ |
c275724c UC |
977 | (*lpdwIndex)++; |
978 | } | |
979 | } | |
980 | else | |
981 | { | |
13b6ce6d | 982 | DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR); |
c275724c | 983 | |
a2bf4d00 | 984 | if (len > *lpdwBufferLength) |
c275724c | 985 | { |
a2bf4d00 | 986 | *lpdwBufferLength = len; |
c275724c | 987 | INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); |
b288f71e | 988 | return bSuccess; |
c275724c UC |
989 | } |
990 | ||
a2bf4d00 AJ |
991 | memcpy(lpBuffer, lphttpHdr->lpszValue, len); |
992 | *lpdwBufferLength = len - sizeof(WCHAR); | |
9a624916 | 993 | bSuccess = TRUE; |
1d5e6b67 | 994 | |
a4e902cb | 995 | TRACE(" returning string : '%s'\n", debugstr_w(lpBuffer)); |
c275724c | 996 | } |
b288f71e MM |
997 | return bSuccess; |
998 | } | |
999 | ||
1000 | /*********************************************************************** | |
1001 | * HttpQueryInfoW (WININET.@) | |
1002 | * | |
1003 | * Queries for information about an HTTP request | |
1004 | * | |
1005 | * RETURNS | |
1006 | * TRUE on success | |
1007 | * FALSE on failure | |
1008 | * | |
1009 | */ | |
1010 | BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, | |
1011 | LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) | |
1012 | { | |
1013 | BOOL bSuccess = FALSE; | |
1014 | LPWININETHTTPREQW lpwhr; | |
1015 | ||
1016 | if (TRACE_ON(wininet)) { | |
1017 | #define FE(x) { x, #x } | |
1018 | static const wininet_flag_info query_flags[] = { | |
1019 | FE(HTTP_QUERY_MIME_VERSION), | |
1020 | FE(HTTP_QUERY_CONTENT_TYPE), | |
1021 | FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING), | |
1022 | FE(HTTP_QUERY_CONTENT_ID), | |
1023 | FE(HTTP_QUERY_CONTENT_DESCRIPTION), | |
1024 | FE(HTTP_QUERY_CONTENT_LENGTH), | |
1025 | FE(HTTP_QUERY_CONTENT_LANGUAGE), | |
1026 | FE(HTTP_QUERY_ALLOW), | |
1027 | FE(HTTP_QUERY_PUBLIC), | |
1028 | FE(HTTP_QUERY_DATE), | |
1029 | FE(HTTP_QUERY_EXPIRES), | |
1030 | FE(HTTP_QUERY_LAST_MODIFIED), | |
1031 | FE(HTTP_QUERY_MESSAGE_ID), | |
1032 | FE(HTTP_QUERY_URI), | |
1033 | FE(HTTP_QUERY_DERIVED_FROM), | |
1034 | FE(HTTP_QUERY_COST), | |
1035 | FE(HTTP_QUERY_LINK), | |
1036 | FE(HTTP_QUERY_PRAGMA), | |
1037 | FE(HTTP_QUERY_VERSION), | |
1038 | FE(HTTP_QUERY_STATUS_CODE), | |
1039 | FE(HTTP_QUERY_STATUS_TEXT), | |
1040 | FE(HTTP_QUERY_RAW_HEADERS), | |
1041 | FE(HTTP_QUERY_RAW_HEADERS_CRLF), | |
1042 | FE(HTTP_QUERY_CONNECTION), | |
1043 | FE(HTTP_QUERY_ACCEPT), | |
1044 | FE(HTTP_QUERY_ACCEPT_CHARSET), | |
1045 | FE(HTTP_QUERY_ACCEPT_ENCODING), | |
1046 | FE(HTTP_QUERY_ACCEPT_LANGUAGE), | |
1047 | FE(HTTP_QUERY_AUTHORIZATION), | |
1048 | FE(HTTP_QUERY_CONTENT_ENCODING), | |
1049 | FE(HTTP_QUERY_FORWARDED), | |
1050 | FE(HTTP_QUERY_FROM), | |
1051 | FE(HTTP_QUERY_IF_MODIFIED_SINCE), | |
1052 | FE(HTTP_QUERY_LOCATION), | |
1053 | FE(HTTP_QUERY_ORIG_URI), | |
1054 | FE(HTTP_QUERY_REFERER), | |
1055 | FE(HTTP_QUERY_RETRY_AFTER), | |
1056 | FE(HTTP_QUERY_SERVER), | |
1057 | FE(HTTP_QUERY_TITLE), | |
1058 | FE(HTTP_QUERY_USER_AGENT), | |
1059 | FE(HTTP_QUERY_WWW_AUTHENTICATE), | |
1060 | FE(HTTP_QUERY_PROXY_AUTHENTICATE), | |
1061 | FE(HTTP_QUERY_ACCEPT_RANGES), | |
1062 | FE(HTTP_QUERY_SET_COOKIE), | |
1063 | FE(HTTP_QUERY_COOKIE), | |
1064 | FE(HTTP_QUERY_REQUEST_METHOD), | |
1065 | FE(HTTP_QUERY_REFRESH), | |
1066 | FE(HTTP_QUERY_CONTENT_DISPOSITION), | |
1067 | FE(HTTP_QUERY_AGE), | |
1068 | FE(HTTP_QUERY_CACHE_CONTROL), | |
1069 | FE(HTTP_QUERY_CONTENT_BASE), | |
1070 | FE(HTTP_QUERY_CONTENT_LOCATION), | |
1071 | FE(HTTP_QUERY_CONTENT_MD5), | |
1072 | FE(HTTP_QUERY_CONTENT_RANGE), | |
1073 | FE(HTTP_QUERY_ETAG), | |
1074 | FE(HTTP_QUERY_HOST), | |
1075 | FE(HTTP_QUERY_IF_MATCH), | |
1076 | FE(HTTP_QUERY_IF_NONE_MATCH), | |
1077 | FE(HTTP_QUERY_IF_RANGE), | |
1078 | FE(HTTP_QUERY_IF_UNMODIFIED_SINCE), | |
1079 | FE(HTTP_QUERY_MAX_FORWARDS), | |
1080 | FE(HTTP_QUERY_PROXY_AUTHORIZATION), | |
1081 | FE(HTTP_QUERY_RANGE), | |
1082 | FE(HTTP_QUERY_TRANSFER_ENCODING), | |
1083 | FE(HTTP_QUERY_UPGRADE), | |
1084 | FE(HTTP_QUERY_VARY), | |
1085 | FE(HTTP_QUERY_VIA), | |
1086 | FE(HTTP_QUERY_WARNING), | |
1087 | FE(HTTP_QUERY_CUSTOM) | |
1088 | }; | |
1089 | static const wininet_flag_info modifier_flags[] = { | |
1090 | FE(HTTP_QUERY_FLAG_REQUEST_HEADERS), | |
1091 | FE(HTTP_QUERY_FLAG_SYSTEMTIME), | |
1092 | FE(HTTP_QUERY_FLAG_NUMBER), | |
1093 | FE(HTTP_QUERY_FLAG_COALESCE) | |
1094 | }; | |
1095 | #undef FE | |
1096 | DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK; | |
1097 | DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK; | |
13b6ce6d | 1098 | DWORD i; |
b288f71e MM |
1099 | |
1100 | TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel); | |
1101 | TRACE(" Attribute:"); | |
1102 | for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) { | |
1103 | if (query_flags[i].val == info) { | |
1104 | DPRINTF(" %s", query_flags[i].name); | |
1105 | break; | |
1106 | } | |
1107 | } | |
1108 | if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) { | |
1109 | DPRINTF(" Unknown (%08lx)", info); | |
1110 | } | |
1111 | ||
1112 | DPRINTF(" Modifier:"); | |
1113 | for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) { | |
1114 | if (modifier_flags[i].val & info_mod) { | |
1115 | DPRINTF(" %s", modifier_flags[i].name); | |
1116 | info_mod &= ~ modifier_flags[i].val; | |
1117 | } | |
1118 | } | |
1119 | ||
1120 | if (info_mod) { | |
1121 | DPRINTF(" Unknown (%08lx)", info_mod); | |
1122 | } | |
1123 | DPRINTF("\n"); | |
1124 | } | |
1125 | ||
1126 | lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); | |
1127 | if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) | |
1128 | { | |
1129 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 | 1130 | goto lend; |
b288f71e MM |
1131 | } |
1132 | ||
1133 | bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, | |
1134 | lpBuffer, lpdwBufferLength, lpdwIndex); | |
c275724c | 1135 | |
3a1391b8 MM |
1136 | lend: |
1137 | if( lpwhr ) | |
1138 | WININET_Release( &lpwhr->hdr ); | |
1139 | ||
c275724c UC |
1140 | TRACE("%d <--\n", bSuccess); |
1141 | return bSuccess; | |
1142 | } | |
1143 | ||
d476a5ad | 1144 | /*********************************************************************** |
a4e902cb | 1145 | * HttpQueryInfoA (WININET.@) |
d476a5ad AM |
1146 | * |
1147 | * Queries for information about an HTTP request | |
1148 | * | |
1149 | * RETURNS | |
1150 | * TRUE on success | |
1151 | * FALSE on failure | |
1152 | * | |
1153 | */ | |
a4e902cb | 1154 | BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, |
d476a5ad AM |
1155 | LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) |
1156 | { | |
1157 | BOOL result; | |
1baf39f9 MM |
1158 | DWORD len; |
1159 | WCHAR* bufferW; | |
1160 | ||
d476a5ad AM |
1161 | if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) || |
1162 | (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)) | |
1163 | { | |
1baf39f9 MM |
1164 | return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer, |
1165 | lpdwBufferLength, lpdwIndex ); | |
d476a5ad | 1166 | } |
1baf39f9 MM |
1167 | |
1168 | len = (*lpdwBufferLength)*sizeof(WCHAR); | |
1169 | bufferW = HeapAlloc( GetProcessHeap(), 0, len ); | |
1170 | result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW, | |
1171 | &len, lpdwIndex ); | |
1172 | if( result ) | |
d476a5ad | 1173 | { |
4385d305 | 1174 | len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1, |
1baf39f9 | 1175 | lpBuffer, *lpdwBufferLength, NULL, NULL ); |
4385d305 RS |
1176 | *lpdwBufferLength = len - 1; |
1177 | ||
1178 | TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer)); | |
d476a5ad | 1179 | } |
907ac44a RS |
1180 | else |
1181 | /* since the strings being returned from HttpQueryInfoW should be | |
1182 | * only ASCII characters, it is reasonable to assume that all of | |
1183 | * the Unicode characters can be reduced to a single byte */ | |
1184 | *lpdwBufferLength = len / sizeof(WCHAR); | |
4385d305 | 1185 | |
1baf39f9 MM |
1186 | HeapFree(GetProcessHeap(), 0, bufferW ); |
1187 | ||
d476a5ad AM |
1188 | return result; |
1189 | } | |
f9b6d7bb HD |
1190 | |
1191 | /*********************************************************************** | |
3ca98239 | 1192 | * HttpSendRequestExA (WININET.@) |
f9b6d7bb HD |
1193 | * |
1194 | * Sends the specified request to the HTTP server and allows chunked | |
1195 | * transfers | |
1196 | */ | |
1197 | BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, | |
1198 | LPINTERNET_BUFFERSA lpBuffersIn, | |
1199 | LPINTERNET_BUFFERSA lpBuffersOut, | |
1200 | DWORD dwFlags, DWORD dwContext) | |
1201 | { | |
1202 | FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn, | |
1203 | lpBuffersOut, dwFlags, dwContext); | |
1204 | return FALSE; | |
1205 | } | |
1206 | ||
c275724c | 1207 | /*********************************************************************** |
f3b681a2 | 1208 | * HttpSendRequestW (WININET.@) |
c275724c UC |
1209 | * |
1210 | * Sends the specified request to the HTTP server | |
1211 | * | |
1212 | * RETURNS | |
1213 | * TRUE on success | |
1214 | * FALSE on failure | |
1215 | * | |
1216 | */ | |
a4e902cb | 1217 | BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, |
c275724c | 1218 | DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) |
9a624916 | 1219 | { |
a4e902cb MM |
1220 | LPWININETHTTPREQW lpwhr; |
1221 | LPWININETHTTPSESSIONW lpwhs = NULL; | |
09d2d477 | 1222 | LPWININETAPPINFOW hIC = NULL; |
3a1391b8 | 1223 | BOOL r; |
c275724c | 1224 | |
7cc70c0a | 1225 | TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest, |
a4e902cb | 1226 | lpszHeaders, debugstr_w(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength); |
c275724c | 1227 | |
a4e902cb | 1228 | lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); |
c275724c UC |
1229 | if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) |
1230 | { | |
1231 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 MM |
1232 | r = FALSE; |
1233 | goto lend; | |
c275724c UC |
1234 | } |
1235 | ||
a4e902cb | 1236 | lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent; |
c275724c UC |
1237 | if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) |
1238 | { | |
1239 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 MM |
1240 | r = FALSE; |
1241 | goto lend; | |
c275724c UC |
1242 | } |
1243 | ||
09d2d477 | 1244 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
c275724c UC |
1245 | if (NULL == hIC || hIC->hdr.htype != WH_HINIT) |
1246 | { | |
1247 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
3a1391b8 MM |
1248 | r = FALSE; |
1249 | goto lend; | |
c275724c UC |
1250 | } |
1251 | ||
1252 | if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
1253 | { | |
1254 | WORKREQUEST workRequest; | |
a4e902cb | 1255 | struct WORKREQ_HTTPSENDREQUESTW *req; |
c275724c | 1256 | |
a4e902cb | 1257 | workRequest.asyncall = HTTPSENDREQUESTW; |
3a1391b8 | 1258 | workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); |
a4e902cb | 1259 | req = &workRequest.u.HttpSendRequestW; |
ff9b9d4e | 1260 | if (lpszHeaders) |
a4e902cb | 1261 | req->lpszHeader = WININET_strdupW(lpszHeaders); |
ff9b9d4e | 1262 | else |
b8921a24 MM |
1263 | req->lpszHeader = 0; |
1264 | req->dwHeaderLength = dwHeaderLength; | |
1265 | req->lpOptional = lpOptional; | |
1266 | req->dwOptionalLength = dwOptionalLength; | |
ff9b9d4e AS |
1267 | |
1268 | INTERNET_AsyncCall(&workRequest); | |
1269 | /* | |
bc8bd722 | 1270 | * This is from windows. |
ff9b9d4e | 1271 | */ |
bc8bd722 | 1272 | SetLastError(ERROR_IO_PENDING); |
3a1391b8 | 1273 | r = FALSE; |
c275724c UC |
1274 | } |
1275 | else | |
1276 | { | |
3a1391b8 | 1277 | r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, |
c275724c UC |
1278 | dwHeaderLength, lpOptional, dwOptionalLength); |
1279 | } | |
3a1391b8 MM |
1280 | lend: |
1281 | if( lpwhr ) | |
1282 | WININET_Release( &lpwhr->hdr ); | |
1283 | return r; | |
c275724c UC |
1284 | } |
1285 | ||
d476a5ad | 1286 | /*********************************************************************** |
f3b681a2 | 1287 | * HttpSendRequestA (WININET.@) |
d476a5ad AM |
1288 | * |
1289 | * Sends the specified request to the HTTP server | |
1290 | * | |
1291 | * RETURNS | |
1292 | * TRUE on success | |
1293 | * FALSE on failure | |
1294 | * | |
1295 | */ | |
a4e902cb | 1296 | BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, |
d476a5ad AM |
1297 | DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) |
1298 | { | |
1299 | BOOL result; | |
a4e902cb | 1300 | LPWSTR szHeaders=NULL; |
d476a5ad AM |
1301 | DWORD nLen=dwHeaderLength; |
1302 | if(lpszHeaders!=NULL) | |
1303 | { | |
a4e902cb MM |
1304 | nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); |
1305 | szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); | |
1306 | MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); | |
d476a5ad | 1307 | } |
a4e902cb | 1308 | result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); |
d476a5ad | 1309 | if(szHeaders!=NULL) |
43629c9b | 1310 | HeapFree(GetProcessHeap(),0,szHeaders); |
d476a5ad AM |
1311 | return result; |
1312 | } | |
c275724c | 1313 | |
bc8bd722 AM |
1314 | /*********************************************************************** |
1315 | * HTTP_HandleRedirect (internal) | |
1316 | */ | |
a4e902cb | 1317 | static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, |
bc8bd722 AM |
1318 | DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength) |
1319 | { | |
a4e902cb | 1320 | LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent; |
09d2d477 | 1321 | LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
a4e902cb | 1322 | WCHAR path[2048]; |
7cc70c0a | 1323 | |
bc8bd722 AM |
1324 | if(lpszUrl[0]=='/') |
1325 | { | |
1326 | /* if it's an absolute path, keep the same session info */ | |
a4e902cb | 1327 | strcpyW(path,lpszUrl); |
bc8bd722 | 1328 | } |
a1c16d28 MM |
1329 | else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) |
1330 | { | |
1331 | TRACE("Redirect through proxy\n"); | |
a4e902cb | 1332 | strcpyW(path,lpszUrl); |
a1c16d28 | 1333 | } |
bc8bd722 AM |
1334 | else |
1335 | { | |
a4e902cb MM |
1336 | URL_COMPONENTSW urlComponents; |
1337 | WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; | |
1338 | WCHAR password[1024], extra[1024]; | |
1339 | urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); | |
bc8bd722 AM |
1340 | urlComponents.lpszScheme = protocol; |
1341 | urlComponents.dwSchemeLength = 32; | |
1342 | urlComponents.lpszHostName = hostName; | |
1343 | urlComponents.dwHostNameLength = MAXHOSTNAME; | |
1344 | urlComponents.lpszUserName = userName; | |
1345 | urlComponents.dwUserNameLength = 1024; | |
1346 | urlComponents.lpszPassword = password; | |
1347 | urlComponents.dwPasswordLength = 1024; | |
1348 | urlComponents.lpszUrlPath = path; | |
1349 | urlComponents.dwUrlPathLength = 2048; | |
1350 | urlComponents.lpszExtraInfo = extra; | |
1351 | urlComponents.dwExtraInfoLength = 1024; | |
a4e902cb | 1352 | if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) |
bc8bd722 AM |
1353 | return FALSE; |
1354 | ||
1355 | if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) | |
1356 | urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; | |
1357 | ||
a1c16d28 MM |
1358 | #if 0 |
1359 | /* | |
1360 | * This upsets redirects to binary files on sourceforge.net | |
1361 | * and gives an html page instead of the target file | |
1362 | * Examination of the HTTP request sent by native wininet.dll | |
1363 | * reveals that it doesn't send a referrer in that case. | |
1364 | * Maybe there's a flag that enables this, or maybe a referrer | |
1365 | * shouldn't be added in case of a redirect. | |
1366 | */ | |
1367 | ||
1368 | /* consider the current host as the referrer */ | |
a4e902cb | 1369 | if (NULL != lpwhs->lpszServerName && strlenW(lpwhs->lpszServerName)) |
a1c16d28 MM |
1370 | HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, |
1371 | HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE| | |
1372 | HTTP_ADDHDR_FLAG_ADD_IF_NEW); | |
1373 | #endif | |
bc8bd722 AM |
1374 | |
1375 | if (NULL != lpwhs->lpszServerName) | |
1376 | HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); | |
a4e902cb | 1377 | lpwhs->lpszServerName = WININET_strdupW(hostName); |
bc8bd722 AM |
1378 | if (NULL != lpwhs->lpszUserName) |
1379 | HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); | |
a4e902cb | 1380 | lpwhs->lpszUserName = WININET_strdupW(userName); |
bc8bd722 AM |
1381 | lpwhs->nServerPort = urlComponents.nPort; |
1382 | ||
1383 | if (NULL != lpwhr->lpszHostName) | |
1384 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName); | |
a4e902cb | 1385 | lpwhr->lpszHostName=WININET_strdupW(hostName); |
bc8bd722 | 1386 | |
3a1391b8 | 1387 | SendAsyncCallback(hIC, &lpwhs->hdr, lpwhr->hdr.dwContext, |
bc8bd722 AM |
1388 | INTERNET_STATUS_RESOLVING_NAME, |
1389 | lpwhs->lpszServerName, | |
a4e902cb | 1390 | strlenW(lpwhs->lpszServerName)+1); |
bc8bd722 AM |
1391 | |
1392 | if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, | |
1393 | &lpwhs->phostent, &lpwhs->socketAddress)) | |
1394 | { | |
1395 | INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); | |
1396 | return FALSE; | |
1397 | } | |
1398 | ||
3a1391b8 | 1399 | SendAsyncCallback(hIC, &lpwhs->hdr, lpwhr->hdr.dwContext, |
bc8bd722 AM |
1400 | INTERNET_STATUS_NAME_RESOLVED, |
1401 | &(lpwhs->socketAddress), | |
1402 | sizeof(struct sockaddr_in)); | |
1403 | ||
1404 | } | |
1405 | ||
1406 | if(lpwhr->lpszPath) | |
1407 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); | |
1408 | lpwhr->lpszPath=NULL; | |
a4e902cb | 1409 | if (strlenW(path)) |
bc8bd722 AM |
1410 | { |
1411 | DWORD needed = 0; | |
1412 | HRESULT rc; | |
a4e902cb MM |
1413 | |
1414 | rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY); | |
bc8bd722 | 1415 | if (rc != E_POINTER) |
a4e902cb MM |
1416 | needed = strlenW(path)+1; |
1417 | lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR)); | |
1418 | rc = UrlEscapeW(path, lpwhr->lpszPath, &needed, | |
bc8bd722 AM |
1419 | URL_ESCAPE_SPACES_ONLY); |
1420 | if (rc) | |
1421 | { | |
a4e902cb MM |
1422 | ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(path),rc); |
1423 | strcpyW(lpwhr->lpszPath,path); | |
bc8bd722 AM |
1424 | } |
1425 | } | |
1426 | ||
3a1391b8 | 1427 | return HTTP_HttpSendRequestW(lpwhr, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength); |
bc8bd722 AM |
1428 | } |
1429 | ||
a4969063 MM |
1430 | /*********************************************************************** |
1431 | * HTTP_build_req (internal) | |
1432 | * | |
1433 | * concatenate all the strings in the request together | |
1434 | */ | |
1435 | static LPWSTR HTTP_build_req( LPCWSTR *list, int len ) | |
1436 | { | |
1437 | LPCWSTR *t; | |
1438 | LPWSTR str; | |
1439 | ||
1440 | for( t = list; *t ; t++ ) | |
1441 | len += strlenW( *t ); | |
1442 | len++; | |
1443 | ||
1444 | str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); | |
1445 | *str = 0; | |
1446 | ||
1447 | for( t = list; *t ; t++ ) | |
1448 | strcatW( str, *t ); | |
1449 | ||
1450 | return str; | |
1451 | } | |
1452 | ||
c275724c | 1453 | /*********************************************************************** |
a4e902cb | 1454 | * HTTP_HttpSendRequestW (internal) |
c275724c UC |
1455 | * |
1456 | * Sends the specified request to the HTTP server | |
1457 | * | |
1458 | * RETURNS | |
1459 | * TRUE on success | |
1460 | * FALSE on failure | |
1461 | * | |
1462 | */ | |
3a1391b8 | 1463 | BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, |
c275724c UC |
1464 | DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) |
1465 | { | |
1466 | INT cnt; | |
13b6ce6d | 1467 | DWORD i; |
c275724c | 1468 | BOOL bSuccess = FALSE; |
a4e902cb | 1469 | LPWSTR requestString = NULL; |
ff9b9d4e | 1470 | INT responseLen; |
a4e902cb | 1471 | LPWININETHTTPSESSIONW lpwhs = NULL; |
09d2d477 | 1472 | LPWININETAPPINFOW hIC = NULL; |
852c7ae4 DH |
1473 | BOOL loop_next = FALSE; |
1474 | int CustHeaderIndex; | |
c275724c | 1475 | |
3a1391b8 | 1476 | TRACE("--> %p\n", lpwhr); |
c275724c | 1477 | |
3a1391b8 | 1478 | assert(lpwhr->hdr.htype == WH_HHTTPREQ); |
c275724c | 1479 | |
a4e902cb | 1480 | lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent; |
c275724c UC |
1481 | if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) |
1482 | { | |
1483 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
1484 | return FALSE; | |
1485 | } | |
1486 | ||
09d2d477 | 1487 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
c275724c UC |
1488 | if (NULL == hIC || hIC->hdr.htype != WH_HINIT) |
1489 | { | |
1490 | INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
1491 | return FALSE; | |
1492 | } | |
1493 | ||
1494 | /* Clear any error information */ | |
1495 | INTERNET_SetLastError(0); | |
1496 | ||
ff9b9d4e | 1497 | |
c275724c UC |
1498 | /* We must have a verb */ |
1499 | if (NULL == lpwhr->lpszVerb) | |
1500 | { | |
1501 | goto lend; | |
1502 | } | |
1503 | ||
6226f3f2 DH |
1504 | /* if we are using optional stuff, we must add the fixed header of that option length */ |
1505 | if (lpOptional && dwOptionalLength) | |
1506 | { | |
b288f71e MM |
1507 | static const WCHAR szContentLength[] = { |
1508 | 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0}; | |
1509 | WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \n\r */ + 20 /* int */ ]; | |
1510 | sprintfW(contentLengthStr, szContentLength, dwOptionalLength); | |
1511 | HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD); | |
6226f3f2 DH |
1512 | } |
1513 | ||
852c7ae4 | 1514 | do |
76598823 | 1515 | { |
6a6c85c6 FG |
1516 | static const WCHAR szSlash[] = { '/',0 }; |
1517 | static const WCHAR szSpace[] = { ' ',0 }; | |
1518 | static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 }; | |
1519 | static const WCHAR szcrlf[] = {'\r','\n', 0}; | |
1520 | static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; | |
1521 | static const WCHAR szSetCookie[] = {'S','e','t','-','C','o','o','k','i','e',0 }; | |
a4969063 MM |
1522 | static const WCHAR szColon[] = { ':',' ',0 }; |
1523 | LPCWSTR *req; | |
08c6c698 | 1524 | LPWSTR p; |
13b6ce6d | 1525 | DWORD len, n; |
a4969063 MM |
1526 | char *ascii_req; |
1527 | ||
a4e902cb | 1528 | TRACE("Going to url %s %s\n", debugstr_w(lpwhr->lpszHostName), debugstr_w(lpwhr->lpszPath)); |
852c7ae4 | 1529 | loop_next = FALSE; |
76598823 | 1530 | |
852c7ae4 DH |
1531 | /* If we don't have a path we set it to root */ |
1532 | if (NULL == lpwhr->lpszPath) | |
a4e902cb MM |
1533 | lpwhr->lpszPath = WININET_strdupW(szSlash); |
1534 | ||
1535 | if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, | |
1536 | lpwhr->lpszPath, strlenW(szHttp), szHttp, strlenW(szHttp) ) | |
852c7ae4 DH |
1537 | && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */ |
1538 | { | |
a4e902cb MM |
1539 | WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0, |
1540 | (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR)); | |
852c7ae4 | 1541 | *fixurl = '/'; |
a4e902cb | 1542 | strcpyW(fixurl + 1, lpwhr->lpszPath); |
852c7ae4 DH |
1543 | HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath ); |
1544 | lpwhr->lpszPath = fixurl; | |
1545 | } | |
c275724c | 1546 | |
f1d7b14b | 1547 | /* add the headers the caller supplied */ |
08c6c698 | 1548 | if( lpszHeaders && dwHeaderLength ) |
f1d7b14b | 1549 | { |
08c6c698 MM |
1550 | HTTP_HttpAddRequestHeadersW(lpwhr, lpszHeaders, dwHeaderLength, |
1551 | HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE); | |
f1d7b14b MM |
1552 | } |
1553 | ||
a4969063 | 1554 | /* allocate space for an array of all the string pointers to be added */ |
d7357a49 AJ |
1555 | len = (HTTP_QUERY_MAX + lpwhr->nCustHeaders)*4 + 9; |
1556 | req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) ); | |
c275724c | 1557 | |
a4969063 MM |
1558 | /* add the verb, path and HTTP/1.0 */ |
1559 | n = 0; | |
1560 | req[n++] = lpwhr->lpszVerb; | |
1561 | req[n++] = szSpace; | |
1562 | req[n++] = lpwhr->lpszPath; | |
1563 | req[n++] = HTTPHEADER; | |
c275724c | 1564 | |
852c7ae4 DH |
1565 | /* Append standard request headers */ |
1566 | for (i = 0; i <= HTTP_QUERY_MAX; i++) | |
1567 | { | |
1568 | if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) | |
1569 | { | |
a4969063 MM |
1570 | req[n++] = szcrlf; |
1571 | req[n++] = lpwhr->StdHeaders[i].lpszField; | |
1572 | req[n++] = szColon; | |
1573 | req[n++] = lpwhr->StdHeaders[i].lpszValue; | |
1574 | ||
a4e902cb MM |
1575 | TRACE("Adding header %s (%s)\n", |
1576 | debugstr_w(lpwhr->StdHeaders[i].lpszField), | |
1577 | debugstr_w(lpwhr->StdHeaders[i].lpszValue)); | |
852c7ae4 DH |
1578 | } |
1579 | } | |
1580 | ||
1581 | /* Append custom request heades */ | |
1582 | for (i = 0; i < lpwhr->nCustHeaders; i++) | |
1583 | { | |
1584 | if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) | |
1585 | { | |
a4969063 MM |
1586 | req[n++] = szcrlf; |
1587 | req[n++] = lpwhr->pCustHeaders[i].lpszField; | |
1588 | req[n++] = szColon; | |
1589 | req[n++] = lpwhr->pCustHeaders[i].lpszValue; | |
1590 | ||
a4e902cb MM |
1591 | TRACE("Adding custom header %s (%s)\n", |
1592 | debugstr_w(lpwhr->pCustHeaders[i].lpszField), | |
1593 | debugstr_w(lpwhr->pCustHeaders[i].lpszValue)); | |
852c7ae4 DH |
1594 | } |
1595 | } | |
c275724c | 1596 | |
852c7ae4 | 1597 | if (lpwhr->lpszHostName) |
a4e902cb | 1598 | { |
a4969063 MM |
1599 | req[n++] = HTTPHOSTHEADER; |
1600 | req[n++] = lpwhr->lpszHostName; | |
a4e902cb | 1601 | } |
c275724c | 1602 | |
d7357a49 | 1603 | if( n >= len ) |
a4969063 | 1604 | ERR("oops. buffer overrun\n"); |
c275724c | 1605 | |
f1d7b14b | 1606 | req[n] = NULL; |
a4969063 MM |
1607 | requestString = HTTP_build_req( req, 4 ); |
1608 | HeapFree( GetProcessHeap(), 0, req ); | |
6226f3f2 | 1609 | |
a4969063 MM |
1610 | /* |
1611 | * Set (header) termination string for request | |
1612 | * Make sure there's exactly two new lines at the end of the request | |
1613 | */ | |
1614 | p = &requestString[strlenW(requestString)-1]; | |
1615 | while ( (*p == '\n') || (*p == '\r') ) | |
1616 | p--; | |
1617 | strcpyW( p+1, sztwocrlf ); | |
1618 | ||
1619 | TRACE("Request header -> %s\n", debugstr_w(requestString) ); | |
ff9b9d4e | 1620 | |
852c7ae4 DH |
1621 | /* Send the request and store the results */ |
1622 | if (!HTTP_OpenConnection(lpwhr)) | |
1623 | goto lend; | |
1624 | ||
a4969063 MM |
1625 | /* send the request as ASCII, tack on the optional data */ |
1626 | if( !lpOptional ) | |
1627 | dwOptionalLength = 0; | |
1628 | len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, | |
1629 | NULL, 0, NULL, NULL ); | |
1630 | ascii_req = HeapAlloc( GetProcessHeap(), 0, len + dwOptionalLength ); | |
1631 | WideCharToMultiByte( CP_ACP, 0, requestString, -1, | |
1632 | ascii_req, len, NULL, NULL ); | |
1633 | if( lpOptional ) | |
f1d7b14b MM |
1634 | memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength ); |
1635 | len = (len + dwOptionalLength - 1); | |
1636 | ascii_req[len] = 0; | |
1637 | TRACE("full request -> %s\n", ascii_req ); | |
1638 | ||
1639 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, | |
1640 | INTERNET_STATUS_SENDING_REQUEST, NULL, 0); | |
1641 | ||
a4969063 MM |
1642 | NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); |
1643 | HeapFree( GetProcessHeap(), 0, ascii_req ); | |
c275724c | 1644 | |
3a1391b8 | 1645 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
852c7ae4 | 1646 | INTERNET_STATUS_REQUEST_SENT, |
a4969063 | 1647 | &len,sizeof(DWORD)); |
852c7ae4 | 1648 | |
3a1391b8 | 1649 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
852c7ae4 DH |
1650 | INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); |
1651 | ||
1652 | if (cnt < 0) | |
1653 | goto lend; | |
c275724c | 1654 | |
852c7ae4 DH |
1655 | responseLen = HTTP_GetResponseHeaders(lpwhr); |
1656 | if (responseLen) | |
c275724c UC |
1657 | bSuccess = TRUE; |
1658 | ||
3a1391b8 | 1659 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
852c7ae4 DH |
1660 | INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, |
1661 | sizeof(DWORD)); | |
1662 | ||
1663 | /* process headers here. Is this right? */ | |
a4e902cb | 1664 | CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSetCookie); |
d6315926 | 1665 | if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && (CustHeaderIndex >= 0)) |
852c7ae4 | 1666 | { |
a4e902cb MM |
1667 | LPHTTPHEADERW setCookieHeader; |
1668 | int nPosStart = 0, nPosEnd = 0, len; | |
6a6c85c6 | 1669 | static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0}; |
852c7ae4 DH |
1670 | |
1671 | setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex]; | |
1672 | ||
1673 | while (setCookieHeader->lpszValue[nPosEnd] != '\0') | |
1674 | { | |
a4e902cb MM |
1675 | LPWSTR buf_cookie, cookie_name, cookie_data; |
1676 | LPWSTR buf_url; | |
1677 | LPWSTR domain = NULL; | |
852c7ae4 DH |
1678 | int nEqualPos = 0; |
1679 | while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' && | |
1680 | setCookieHeader->lpszValue[nPosEnd] != '\0') | |
1681 | { | |
1682 | nPosEnd++; | |
1683 | } | |
1684 | if (setCookieHeader->lpszValue[nPosEnd] == ';') | |
1685 | { | |
1686 | /* fixme: not case sensitive, strcasestr is gnu only */ | |
1687 | int nDomainPosEnd = 0; | |
1688 | int nDomainPosStart = 0, nDomainLength = 0; | |
6a6c85c6 | 1689 | static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; |
a4e902cb | 1690 | LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain); |
852c7ae4 DH |
1691 | if (lpszDomain) |
1692 | { /* they have specified their own domain, lets use it */ | |
1693 | while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' && | |
1694 | lpszDomain[nDomainPosEnd] != '\0') | |
1695 | { | |
1696 | nDomainPosEnd++; | |
1697 | } | |
a4e902cb | 1698 | nDomainPosStart = strlenW(szDomain); |
852c7ae4 | 1699 | nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1; |
a4e902cb MM |
1700 | domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR)); |
1701 | strncpyW(domain, &lpszDomain[nDomainPosStart], nDomainLength); | |
852c7ae4 DH |
1702 | domain[nDomainLength] = '\0'; |
1703 | } | |
1704 | } | |
1705 | if (setCookieHeader->lpszValue[nPosEnd] == '\0') break; | |
a4e902cb MM |
1706 | buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR)); |
1707 | strncpyW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart)); | |
852c7ae4 | 1708 | buf_cookie[(nPosEnd - nPosStart)] = '\0'; |
a4e902cb | 1709 | TRACE("%s\n", debugstr_w(buf_cookie)); |
852c7ae4 DH |
1710 | while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0') |
1711 | { | |
1712 | nEqualPos++; | |
1713 | } | |
1714 | if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0') | |
1715 | { | |
1716 | HeapFree(GetProcessHeap(), 0, buf_cookie); | |
1717 | break; | |
1718 | } | |
1719 | ||
a4e902cb MM |
1720 | cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR)); |
1721 | strncpyW(cookie_name, buf_cookie, nEqualPos); | |
852c7ae4 DH |
1722 | cookie_name[nEqualPos] = '\0'; |
1723 | cookie_data = &buf_cookie[nEqualPos + 1]; | |
1724 | ||
1725 | ||
a4e902cb MM |
1726 | len = strlenW((domain ? domain : lpwhr->lpszHostName)) + strlenW(lpwhr->lpszPath) + 9; |
1727 | buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | |
1728 | sprintfW(buf_url, szFmt, (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */ | |
1729 | InternetSetCookieW(buf_url, cookie_name, cookie_data); | |
852c7ae4 DH |
1730 | |
1731 | HeapFree(GetProcessHeap(), 0, buf_url); | |
1732 | HeapFree(GetProcessHeap(), 0, buf_cookie); | |
1733 | HeapFree(GetProcessHeap(), 0, cookie_name); | |
1734 | if (domain) HeapFree(GetProcessHeap(), 0, domain); | |
1735 | nPosStart = nPosEnd; | |
1736 | } | |
1737 | } | |
852c7ae4 DH |
1738 | } |
1739 | while (loop_next); | |
ff9b9d4e | 1740 | |
c275724c UC |
1741 | lend: |
1742 | ||
1743 | if (requestString) | |
1744 | HeapFree(GetProcessHeap(), 0, requestString); | |
1745 | ||
bc8bd722 AM |
1746 | /* TODO: send notification for P3P header */ |
1747 | ||
1748 | if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) | |
1749 | { | |
1750 | DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0; | |
b288f71e | 1751 | if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) && |
bc8bd722 AM |
1752 | (dwCode==302 || dwCode==301)) |
1753 | { | |
a4e902cb | 1754 | WCHAR szNewLocation[2048]; |
bc8bd722 AM |
1755 | DWORD dwBufferSize=2048; |
1756 | dwIndex=0; | |
b288f71e | 1757 | if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex)) |
bc8bd722 | 1758 | { |
3a1391b8 | 1759 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
bc8bd722 AM |
1760 | INTERNET_STATUS_REDIRECT, szNewLocation, |
1761 | dwBufferSize); | |
1762 | return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders, | |
1763 | dwHeaderLength, lpOptional, dwOptionalLength); | |
1764 | } | |
1765 | } | |
1766 | } | |
ff9b9d4e AS |
1767 | |
1768 | if (hIC->lpfnStatusCB) | |
c275724c UC |
1769 | { |
1770 | INTERNET_ASYNC_RESULT iar; | |
9a624916 | 1771 | |
c275724c UC |
1772 | iar.dwResult = (DWORD)bSuccess; |
1773 | iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
ff9b9d4e | 1774 | |
3a1391b8 | 1775 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e AS |
1776 | INTERNET_STATUS_REQUEST_COMPLETE, &iar, |
1777 | sizeof(INTERNET_ASYNC_RESULT)); | |
c275724c UC |
1778 | } |
1779 | ||
1780 | TRACE("<--\n"); | |
1781 | return bSuccess; | |
1782 | } | |
1783 | ||
1784 | ||
1785 | /*********************************************************************** | |
1786 | * HTTP_Connect (internal) | |
1787 | * | |
1788 | * Create http session handle | |
1789 | * | |
1790 | * RETURNS | |
1791 | * HINTERNET a session handle on success | |
1792 | * NULL on failure | |
1793 | * | |
1794 | */ | |
3a1391b8 | 1795 | HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, |
a4e902cb | 1796 | INTERNET_PORT nServerPort, LPCWSTR lpszUserName, |
917df923 KK |
1797 | LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext, |
1798 | DWORD dwInternalFlags) | |
c275724c UC |
1799 | { |
1800 | BOOL bSuccess = FALSE; | |
a4e902cb | 1801 | LPWININETHTTPSESSIONW lpwhs = NULL; |
7cc70c0a | 1802 | HINTERNET handle = NULL; |
c275724c | 1803 | |
ff9b9d4e | 1804 | TRACE("-->\n"); |
c275724c | 1805 | |
3a1391b8 | 1806 | assert( hIC->hdr.htype == WH_HINIT ); |
c275724c | 1807 | |
ff9b9d4e | 1808 | hIC->hdr.dwContext = dwContext; |
94c02fef | 1809 | |
a4e902cb | 1810 | lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW)); |
c275724c UC |
1811 | if (NULL == lpwhs) |
1812 | { | |
1813 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
1814 | goto lerror; | |
1815 | } | |
1816 | ||
ff9b9d4e AS |
1817 | /* |
1818 | * According to my tests. The name is not resolved until a request is sent | |
1819 | */ | |
c275724c UC |
1820 | |
1821 | if (nServerPort == INTERNET_INVALID_PORT_NUMBER) | |
1822 | nServerPort = INTERNET_DEFAULT_HTTP_PORT; | |
1823 | ||
c275724c | 1824 | lpwhs->hdr.htype = WH_HHTTPSESSION; |
3a1391b8 | 1825 | lpwhs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr ); |
c275724c UC |
1826 | lpwhs->hdr.dwFlags = dwFlags; |
1827 | lpwhs->hdr.dwContext = dwContext; | |
917df923 | 1828 | lpwhs->hdr.dwInternalFlags = dwInternalFlags; |
3a1391b8 MM |
1829 | lpwhs->hdr.dwRefCount = 1; |
1830 | lpwhs->hdr.destroy = HTTP_CloseHTTPSessionHandle; | |
1831 | ||
1832 | handle = WININET_AllocHandle( &lpwhs->hdr ); | |
1833 | if (NULL == handle) | |
1834 | { | |
1835 | ERR("Failed to alloc handle\n"); | |
1836 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
1837 | goto lerror; | |
1838 | } | |
1839 | ||
94c02fef | 1840 | if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) { |
09d2d477 | 1841 | if(strchrW(hIC->lpszProxy, ' ')) |
94c02fef DS |
1842 | FIXME("Several proxies not implemented.\n"); |
1843 | if(hIC->lpszProxyBypass) | |
1844 | FIXME("Proxy bypass is ignored.\n"); | |
1845 | } | |
c275724c | 1846 | if (NULL != lpszServerName) |
a4e902cb | 1847 | lpwhs->lpszServerName = WININET_strdupW(lpszServerName); |
c275724c | 1848 | if (NULL != lpszUserName) |
a4e902cb | 1849 | lpwhs->lpszUserName = WININET_strdupW(lpszUserName); |
c275724c UC |
1850 | lpwhs->nServerPort = nServerPort; |
1851 | ||
917df923 KK |
1852 | /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ |
1853 | if (hIC->lpfnStatusCB && !(lpwhs->hdr.dwInternalFlags & INET_OPENURL)) | |
c275724c UC |
1854 | { |
1855 | INTERNET_ASYNC_RESULT iar; | |
1856 | ||
a29b4c7c | 1857 | iar.dwResult = (DWORD)handle; |
c275724c UC |
1858 | iar.dwError = ERROR_SUCCESS; |
1859 | ||
3a1391b8 | 1860 | SendAsyncCallback(hIC, &hIC->hdr, dwContext, |
ff9b9d4e AS |
1861 | INTERNET_STATUS_HANDLE_CREATED, &iar, |
1862 | sizeof(INTERNET_ASYNC_RESULT)); | |
c275724c UC |
1863 | } |
1864 | ||
1865 | bSuccess = TRUE; | |
1866 | ||
1867 | lerror: | |
3a1391b8 MM |
1868 | if( lpwhs ) |
1869 | WININET_Release( &lpwhs->hdr ); | |
c275724c | 1870 | |
ff9b9d4e AS |
1871 | /* |
1872 | * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on | |
1873 | * windows | |
1874 | */ | |
9a624916 | 1875 | |
3a1391b8 | 1876 | TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs); |
7cc70c0a | 1877 | return handle; |
c275724c UC |
1878 | } |
1879 | ||
1880 | ||
1881 | /*********************************************************************** | |
1882 | * HTTP_OpenConnection (internal) | |
1883 | * | |
1884 | * Connect to a web server | |
1885 | * | |
1886 | * RETURNS | |
1887 | * | |
1888 | * TRUE on success | |
1889 | * FALSE on failure | |
1890 | */ | |
a4e902cb | 1891 | BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) |
c275724c UC |
1892 | { |
1893 | BOOL bSuccess = FALSE; | |
a4e902cb | 1894 | LPWININETHTTPSESSIONW lpwhs; |
09d2d477 | 1895 | LPWININETAPPINFOW hIC = NULL; |
ff9b9d4e AS |
1896 | |
1897 | TRACE("-->\n"); | |
c275724c | 1898 | |
c275724c UC |
1899 | |
1900 | if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) | |
1901 | { | |
1902 | INTERNET_SetLastError(ERROR_INVALID_PARAMETER); | |
1903 | goto lend; | |
1904 | } | |
1905 | ||
a4e902cb | 1906 | lpwhs = (LPWININETHTTPSESSIONW)lpwhr->hdr.lpwhparent; |
c275724c | 1907 | |
09d2d477 | 1908 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
3a1391b8 | 1909 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e AS |
1910 | INTERNET_STATUS_CONNECTING_TO_SERVER, |
1911 | &(lpwhs->socketAddress), | |
1912 | sizeof(struct sockaddr_in)); | |
1913 | ||
852c7ae4 DH |
1914 | if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype, |
1915 | SOCK_STREAM, 0)) | |
c275724c UC |
1916 | { |
1917 | WARN("Socket creation failed\n"); | |
1918 | goto lend; | |
1919 | } | |
1920 | ||
852c7ae4 DH |
1921 | if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, |
1922 | sizeof(lpwhs->socketAddress))) | |
c275724c | 1923 | { |
34965563 | 1924 | WARN("Unable to connect to host (%s)\n", strerror(errno)); |
c275724c UC |
1925 | goto lend; |
1926 | } | |
1927 | ||
3a1391b8 | 1928 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e AS |
1929 | INTERNET_STATUS_CONNECTED_TO_SERVER, |
1930 | &(lpwhs->socketAddress), | |
1931 | sizeof(struct sockaddr_in)); | |
1932 | ||
c275724c UC |
1933 | bSuccess = TRUE; |
1934 | ||
1935 | lend: | |
ff9b9d4e | 1936 | TRACE("%d <--\n", bSuccess); |
c275724c UC |
1937 | return bSuccess; |
1938 | } | |
1939 | ||
1940 | ||
48243e32 AJ |
1941 | /*********************************************************************** |
1942 | * HTTP_clear_response_headers (internal) | |
1943 | * | |
1944 | * clear out any old response headers | |
1945 | */ | |
1946 | static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) | |
1947 | { | |
1948 | DWORD i; | |
1949 | ||
1950 | for( i=0; i<=HTTP_QUERY_MAX; i++ ) | |
1951 | { | |
1952 | if( !lpwhr->StdHeaders[i].lpszField ) | |
1953 | continue; | |
1954 | if( !lpwhr->StdHeaders[i].lpszValue ) | |
1955 | continue; | |
1956 | if ( lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST ) | |
1957 | continue; | |
1958 | HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[i], NULL ); | |
1959 | } | |
1960 | for( i=0; i<lpwhr->nCustHeaders; i++) | |
1961 | { | |
1962 | if( !lpwhr->pCustHeaders[i].lpszField ) | |
1963 | continue; | |
1964 | if( !lpwhr->pCustHeaders[i].lpszValue ) | |
1965 | continue; | |
1966 | if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST ) | |
1967 | continue; | |
1968 | HTTP_ReplaceHeaderValue( &lpwhr->pCustHeaders[i], NULL ); | |
1969 | } | |
1970 | } | |
1971 | ||
c275724c UC |
1972 | /*********************************************************************** |
1973 | * HTTP_GetResponseHeaders (internal) | |
1974 | * | |
1975 | * Read server response | |
1976 | * | |
1977 | * RETURNS | |
1978 | * | |
1979 | * TRUE on success | |
1980 | * FALSE on error | |
1981 | */ | |
a4e902cb | 1982 | BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr) |
c275724c UC |
1983 | { |
1984 | INT cbreaks = 0; | |
a4e902cb | 1985 | WCHAR buffer[MAX_REPLY_LEN]; |
c275724c UC |
1986 | DWORD buflen = MAX_REPLY_LEN; |
1987 | BOOL bSuccess = FALSE; | |
ff9b9d4e | 1988 | INT rc = 0; |
a4e902cb | 1989 | WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN]; |
6a6c85c6 | 1990 | static const WCHAR szHttp[] = { 'H','T','T','P',0 }; |
dee8751c | 1991 | static const WCHAR szCrLf[] = {'\r','\n',0}; |
a4e902cb | 1992 | char bufferA[MAX_REPLY_LEN]; |
48243e32 | 1993 | LPWSTR status_code, status_text; |
13b6ce6d | 1994 | DWORD cchMaxRawHeaders = 1024; |
dee8751c | 1995 | LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR)); |
13b6ce6d | 1996 | DWORD cchRawHeaders = 0; |
c275724c | 1997 | |
ff9b9d4e | 1998 | TRACE("-->\n"); |
c275724c | 1999 | |
48243e32 AJ |
2000 | /* clear old response headers (eg. from a redirect response) */ |
2001 | HTTP_clear_response_headers( lpwhr ); | |
2002 | ||
852c7ae4 | 2003 | if (!NETCON_connected(&lpwhr->netConnection)) |
c275724c UC |
2004 | goto lend; |
2005 | ||
ff9b9d4e AS |
2006 | /* |
2007 | * HACK peek at the buffer | |
2008 | */ | |
852c7ae4 | 2009 | NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc); |
ff9b9d4e | 2010 | |
9a624916 | 2011 | /* |
48243e32 | 2012 | * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. |
c275724c | 2013 | */ |
ff9b9d4e | 2014 | buflen = MAX_REPLY_LEN; |
852c7ae4 | 2015 | memset(buffer, 0, MAX_REPLY_LEN); |
a4e902cb | 2016 | if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) |
c275724c | 2017 | goto lend; |
a4e902cb | 2018 | MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); |
c275724c | 2019 | |
a4e902cb | 2020 | if (strncmpW(buffer, szHttp, 4) != 0) |
c275724c | 2021 | goto lend; |
9a624916 | 2022 | |
dee8751c RS |
2023 | /* regenerate raw headers */ |
2024 | while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) | |
2025 | { | |
2026 | cchMaxRawHeaders *= 2; | |
2027 | lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); | |
2028 | } | |
2029 | memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); | |
2030 | cchRawHeaders += (buflen-1); | |
2031 | memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); | |
2032 | cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; | |
2033 | lpszRawHeaders[cchRawHeaders] = '\0'; | |
2034 | ||
48243e32 AJ |
2035 | /* split the version from the status code */ |
2036 | status_code = strchrW( buffer, ' ' ); | |
2037 | if( !status_code ) | |
2038 | goto lend; | |
2039 | *status_code++=0; | |
2040 | ||
2041 | /* split the status code from the status text */ | |
2042 | status_text = strchrW( status_code, ' ' ); | |
2043 | if( !status_text ) | |
2044 | goto lend; | |
2045 | *status_text++=0; | |
2046 | ||
2047 | TRACE("version [%s] status code [%s] status text [%s]\n", | |
2048 | debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); | |
2049 | HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_VERSION], buffer ); | |
2050 | HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_STATUS_CODE], status_code ); | |
2051 | HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_STATUS_TEXT], status_text ); | |
c275724c UC |
2052 | |
2053 | /* Parse each response line */ | |
2054 | do | |
2055 | { | |
2056 | buflen = MAX_REPLY_LEN; | |
a4e902cb | 2057 | if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) |
c275724c | 2058 | { |
a4e902cb MM |
2059 | TRACE("got line %s, now interpretting\n", debugstr_a(bufferA)); |
2060 | MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); | |
dee8751c RS |
2061 | |
2062 | while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) | |
2063 | { | |
2064 | cchMaxRawHeaders *= 2; | |
2065 | lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); | |
2066 | } | |
2067 | memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); | |
2068 | cchRawHeaders += (buflen-1); | |
2069 | memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); | |
2070 | cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; | |
2071 | lpszRawHeaders[cchRawHeaders] = '\0'; | |
2072 | ||
c275724c UC |
2073 | if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN)) |
2074 | break; | |
2075 | ||
2076 | HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE)); | |
2077 | } | |
2078 | else | |
2079 | { | |
2080 | cbreaks++; | |
2081 | if (cbreaks >= 2) | |
2082 | break; | |
2083 | } | |
2084 | }while(1); | |
2085 | ||
dee8751c RS |
2086 | if (lpwhr->lpszRawHeaders) HeapFree(GetProcessHeap(), 0, lpszRawHeaders); |
2087 | lpwhr->lpszRawHeaders = lpszRawHeaders; | |
2088 | TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); | |
c275724c UC |
2089 | bSuccess = TRUE; |
2090 | ||
2091 | lend: | |
2092 | ||
ff9b9d4e AS |
2093 | TRACE("<--\n"); |
2094 | if (bSuccess) | |
2095 | return rc; | |
2096 | else | |
2097 | return FALSE; | |
c275724c UC |
2098 | } |
2099 | ||
2100 | ||
2101 | /*********************************************************************** | |
2102 | * HTTP_InterpretHttpHeader (internal) | |
2103 | * | |
2104 | * Parse server response | |
2105 | * | |
2106 | * RETURNS | |
2107 | * | |
2108 | * TRUE on success | |
2109 | * FALSE on error | |
2110 | */ | |
3a1391b8 | 2111 | static INT stripSpaces(LPCWSTR lpszSrc, LPWSTR lpszStart, INT *len) |
c275724c | 2112 | { |
a4e902cb | 2113 | LPCWSTR lpsztmp; |
c275724c UC |
2114 | INT srclen; |
2115 | ||
2116 | srclen = 0; | |
2117 | ||
2118 | while (*lpszSrc == ' ' && *lpszSrc != '\0') | |
2119 | lpszSrc++; | |
9a624916 | 2120 | |
c275724c UC |
2121 | lpsztmp = lpszSrc; |
2122 | while(*lpsztmp != '\0') | |
2123 | { | |
2124 | if (*lpsztmp != ' ') | |
2125 | srclen = lpsztmp - lpszSrc + 1; | |
2126 | ||
2127 | lpsztmp++; | |
2128 | } | |
2129 | ||
2130 | *len = min(*len, srclen); | |
a4e902cb | 2131 | strncpyW(lpszStart, lpszSrc, *len); |
c275724c UC |
2132 | lpszStart[*len] = '\0'; |
2133 | ||
2134 | return *len; | |
2135 | } | |
2136 | ||
2137 | ||
a4e902cb | 2138 | BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen) |
c275724c | 2139 | { |
a4e902cb | 2140 | WCHAR *pd; |
c275724c UC |
2141 | BOOL bSuccess = FALSE; |
2142 | ||
2143 | TRACE("\n"); | |
2144 | ||
2145 | *field = '\0'; | |
2146 | *value = '\0'; | |
2147 | ||
a4e902cb | 2148 | pd = strchrW(buffer, ':'); |
c275724c UC |
2149 | if (pd) |
2150 | { | |
2151 | *pd = '\0'; | |
2152 | if (stripSpaces(buffer, field, &fieldlen) > 0) | |
2153 | { | |
2154 | if (stripSpaces(pd+1, value, &valuelen) > 0) | |
2155 | bSuccess = TRUE; | |
2156 | } | |
2157 | } | |
2158 | ||
a4e902cb | 2159 | TRACE("%d: field(%s) Value(%s)\n", bSuccess, debugstr_w(field), debugstr_w(value)); |
c275724c UC |
2160 | return bSuccess; |
2161 | } | |
2162 | ||
2163 | ||
2164 | /*********************************************************************** | |
2165 | * HTTP_GetStdHeaderIndex (internal) | |
2166 | * | |
646d2a2a | 2167 | * Lookup field index in standard http header array |
c275724c UC |
2168 | * |
2169 | * FIXME: This should be stuffed into a hash table | |
2170 | */ | |
a4e902cb | 2171 | INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField) |
c275724c UC |
2172 | { |
2173 | INT index = -1; | |
6a6c85c6 | 2174 | static const WCHAR szContentLength[] = { |
a4e902cb | 2175 | 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; |
6a6c85c6 | 2176 | static const WCHAR szContentType[] = { |
a4e902cb | 2177 | 'C','o','n','t','e','n','t','-','T','y','p','e',0}; |
6a6c85c6 | 2178 | static const WCHAR szLastModified[] = { |
a4e902cb | 2179 | 'L','a','s','t','-','M','o','d','i','f','i','e','d',0}; |
6a6c85c6 FG |
2180 | static const WCHAR szLocation[] = {'L','o','c','a','t','i','o','n',0}; |
2181 | static const WCHAR szAccept[] = {'A','c','c','e','p','t',0}; | |
2182 | static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0}; | |
2183 | static const WCHAR szContentTrans[] = { 'C','o','n','t','e','n','t','-', | |
a4e902cb | 2184 | 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0}; |
6a6c85c6 FG |
2185 | static const WCHAR szDate[] = { 'D','a','t','e',0}; |
2186 | static const WCHAR szServer[] = { 'S','e','r','v','e','r',0}; | |
2187 | static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0}; | |
2188 | static const WCHAR szETag[] = { 'E','T','a','g',0}; | |
2189 | static const WCHAR szAcceptRanges[] = { | |
a4e902cb | 2190 | 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; |
6a6c85c6 FG |
2191 | static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; |
2192 | static const WCHAR szMimeVersion[] = { | |
a4e902cb | 2193 | 'M','i','m','e','-','V','e','r','s','i','o','n', 0}; |
6a6c85c6 FG |
2194 | static const WCHAR szPragma[] = { 'P','r','a','g','m','a', 0}; |
2195 | static const WCHAR szCacheControl[] = { | |
a4e902cb | 2196 | 'C','a','c','h','e','-','C','o','n','t','r','o','l',0}; |
6a6c85c6 FG |
2197 | static const WCHAR szUserAgent[] = { 'U','s','e','r','-','A','g','e','n','t',0}; |
2198 | static const WCHAR szProxyAuth[] = { | |
a4e902cb MM |
2199 | 'P','r','o','x','y','-', |
2200 | 'A','u','t','h','e','n','t','i','c','a','t','e', 0}; | |
48243e32 AJ |
2201 | static const WCHAR szContentEncoding[] = { |
2202 | 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0}; | |
2203 | static const WCHAR szCookie[] = {'C','o','o','k','i','e',0}; | |
2204 | static const WCHAR szVary[] = {'V','a','r','y',0}; | |
2205 | static const WCHAR szVia[] = {'V','i','a',0}; | |
a4e902cb MM |
2206 | |
2207 | if (!strcmpiW(lpszField, szContentLength)) | |
c275724c | 2208 | index = HTTP_QUERY_CONTENT_LENGTH; |
a4e902cb | 2209 | else if (!strcmpiW(lpszField,szContentType)) |
c275724c | 2210 | index = HTTP_QUERY_CONTENT_TYPE; |
a4e902cb | 2211 | else if (!strcmpiW(lpszField,szLastModified)) |
c275724c | 2212 | index = HTTP_QUERY_LAST_MODIFIED; |
a4e902cb | 2213 | else if (!strcmpiW(lpszField,szLocation)) |
c275724c | 2214 | index = HTTP_QUERY_LOCATION; |
a4e902cb | 2215 | else if (!strcmpiW(lpszField,szAccept)) |
c275724c | 2216 | index = HTTP_QUERY_ACCEPT; |
a4e902cb | 2217 | else if (!strcmpiW(lpszField,szReferer)) |
c275724c | 2218 | index = HTTP_QUERY_REFERER; |
a4e902cb | 2219 | else if (!strcmpiW(lpszField,szContentTrans)) |
c275724c | 2220 | index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING; |
a4e902cb | 2221 | else if (!strcmpiW(lpszField,szDate)) |
646d2a2a | 2222 | index = HTTP_QUERY_DATE; |
a4e902cb | 2223 | else if (!strcmpiW(lpszField,szServer)) |
646d2a2a | 2224 | index = HTTP_QUERY_SERVER; |
a4e902cb | 2225 | else if (!strcmpiW(lpszField,szConnection)) |
646d2a2a | 2226 | index = HTTP_QUERY_CONNECTION; |
a4e902cb | 2227 | else if (!strcmpiW(lpszField,szETag)) |
646d2a2a | 2228 | index = HTTP_QUERY_ETAG; |
a4e902cb | 2229 | else if (!strcmpiW(lpszField,szAcceptRanges)) |
646d2a2a | 2230 | index = HTTP_QUERY_ACCEPT_RANGES; |
a4e902cb | 2231 | else if (!strcmpiW(lpszField,szExpires)) |
646d2a2a | 2232 | index = HTTP_QUERY_EXPIRES; |
a4e902cb | 2233 | else if (!strcmpiW(lpszField,szMimeVersion)) |
66b4dd28 | 2234 | index = HTTP_QUERY_MIME_VERSION; |
a4e902cb | 2235 | else if (!strcmpiW(lpszField,szPragma)) |
664b9bbb | 2236 | index = HTTP_QUERY_PRAGMA; |
a4e902cb | 2237 | else if (!strcmpiW(lpszField,szCacheControl)) |
664b9bbb | 2238 | index = HTTP_QUERY_CACHE_CONTROL; |
a4e902cb | 2239 | else if (!strcmpiW(lpszField,szUserAgent)) |
664b9bbb | 2240 | index = HTTP_QUERY_USER_AGENT; |
a4e902cb | 2241 | else if (!strcmpiW(lpszField,szProxyAuth)) |
a1c16d28 | 2242 | index = HTTP_QUERY_PROXY_AUTHENTICATE; |
48243e32 AJ |
2243 | else if (!strcmpiW(lpszField,szContentEncoding)) |
2244 | index = HTTP_QUERY_CONTENT_ENCODING; | |
2245 | else if (!strcmpiW(lpszField,szCookie)) | |
2246 | index = HTTP_QUERY_COOKIE; | |
2247 | else if (!strcmpiW(lpszField,szVary)) | |
2248 | index = HTTP_QUERY_VARY; | |
2249 | else if (!strcmpiW(lpszField,szVia)) | |
2250 | index = HTTP_QUERY_VIA; | |
c275724c UC |
2251 | else |
2252 | { | |
a4e902cb | 2253 | TRACE("Couldn't find %s in standard header table\n", debugstr_w(lpszField)); |
c275724c UC |
2254 | } |
2255 | ||
2256 | return index; | |
2257 | } | |
2258 | ||
48243e32 AJ |
2259 | /*********************************************************************** |
2260 | * HTTP_ReplaceHeaderValue (internal) | |
2261 | */ | |
2262 | BOOL HTTP_ReplaceHeaderValue( LPHTTPHEADERW lphttpHdr, LPCWSTR value ) | |
2263 | { | |
2264 | INT len = 0; | |
2265 | ||
2266 | if( lphttpHdr->lpszValue ) | |
2267 | HeapFree( GetProcessHeap(), 0, lphttpHdr->lpszValue ); | |
2268 | lphttpHdr->lpszValue = NULL; | |
2269 | ||
2270 | if( value ) | |
2271 | len = strlenW(value); | |
2272 | if (len) | |
2273 | { | |
2274 | lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, | |
2275 | (len+1)*sizeof(WCHAR)); | |
2276 | strcpyW(lphttpHdr->lpszValue, value); | |
2277 | } | |
2278 | return TRUE; | |
2279 | } | |
c275724c UC |
2280 | |
2281 | /*********************************************************************** | |
2282 | * HTTP_ProcessHeader (internal) | |
2283 | * | |
2284 | * Stuff header into header tables according to <dwModifier> | |
2285 | * | |
2286 | */ | |
2287 | ||
2288 | #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) | |
2289 | ||
a4e902cb | 2290 | BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) |
c275724c | 2291 | { |
a4e902cb | 2292 | LPHTTPHEADERW lphttpHdr = NULL; |
c275724c UC |
2293 | BOOL bSuccess = FALSE; |
2294 | INT index; | |
2295 | ||
13b6ce6d | 2296 | TRACE("--> %s: %s - 0x%08lx\n", debugstr_w(field), debugstr_w(value), dwModifier); |
c275724c UC |
2297 | |
2298 | /* Adjust modifier flags */ | |
2299 | if (dwModifier & COALESCEFLASG) | |
2300 | dwModifier |= HTTP_ADDHDR_FLAG_ADD; | |
2301 | ||
2302 | /* Try to get index into standard header array */ | |
2303 | index = HTTP_GetStdHeaderIndex(field); | |
2304 | if (index >= 0) | |
2305 | { | |
2306 | lphttpHdr = &lpwhr->StdHeaders[index]; | |
2307 | } | |
2308 | else /* Find or create new custom header */ | |
2309 | { | |
ff9b9d4e AS |
2310 | index = HTTP_GetCustomHeaderIndex(lpwhr, field); |
2311 | if (index >= 0) | |
2312 | { | |
2313 | if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) | |
2314 | { | |
2315 | return FALSE; | |
2316 | } | |
2317 | lphttpHdr = &lpwhr->pCustHeaders[index]; | |
2318 | } | |
2319 | else | |
2320 | { | |
a4e902cb | 2321 | HTTPHEADERW hdr; |
c275724c | 2322 | |
a4e902cb MM |
2323 | hdr.lpszField = (LPWSTR)field; |
2324 | hdr.lpszValue = (LPWSTR)value; | |
ff9b9d4e | 2325 | hdr.wFlags = hdr.wCount = 0; |
c275724c UC |
2326 | |
2327 | if (dwModifier & HTTP_ADDHDR_FLAG_REQ) | |
2328 | hdr.wFlags |= HDR_ISREQUEST; | |
2329 | ||
a1c16d28 | 2330 | return HTTP_InsertCustomHeader(lpwhr, &hdr); |
ff9b9d4e | 2331 | } |
c275724c | 2332 | } |
9a624916 | 2333 | |
c275724c UC |
2334 | if (dwModifier & HTTP_ADDHDR_FLAG_REQ) |
2335 | lphttpHdr->wFlags |= HDR_ISREQUEST; | |
2336 | else | |
2337 | lphttpHdr->wFlags &= ~HDR_ISREQUEST; | |
9a624916 | 2338 | |
c275724c UC |
2339 | if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW))) |
2340 | { | |
2341 | INT slen; | |
2342 | ||
2343 | if (!lpwhr->StdHeaders[index].lpszField) | |
2344 | { | |
a4e902cb | 2345 | lphttpHdr->lpszField = WININET_strdupW(field); |
c275724c UC |
2346 | |
2347 | if (dwModifier & HTTP_ADDHDR_FLAG_REQ) | |
2348 | lphttpHdr->wFlags |= HDR_ISREQUEST; | |
2349 | } | |
2350 | ||
a4e902cb MM |
2351 | slen = strlenW(value) + 1; |
2352 | lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen*sizeof(WCHAR)); | |
c275724c UC |
2353 | if (lphttpHdr->lpszValue) |
2354 | { | |
a4e902cb | 2355 | strcpyW(lphttpHdr->lpszValue, value); |
c275724c UC |
2356 | bSuccess = TRUE; |
2357 | } | |
2358 | else | |
2359 | { | |
2360 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
2361 | } | |
2362 | } | |
9a624916 | 2363 | else if (lphttpHdr->lpszValue) |
c275724c | 2364 | { |
9a624916 | 2365 | if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) |
48243e32 | 2366 | bSuccess = HTTP_ReplaceHeaderValue( lphttpHdr, value ); |
c275724c UC |
2367 | else if (dwModifier & COALESCEFLASG) |
2368 | { | |
a4e902cb MM |
2369 | LPWSTR lpsztmp; |
2370 | WCHAR ch = 0; | |
c275724c | 2371 | INT len = 0; |
a4e902cb MM |
2372 | INT origlen = strlenW(lphttpHdr->lpszValue); |
2373 | INT valuelen = strlenW(value); | |
c275724c UC |
2374 | |
2375 | if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA) | |
2376 | { | |
2377 | ch = ','; | |
2378 | lphttpHdr->wFlags |= HDR_COMMADELIMITED; | |
2379 | } | |
2380 | else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) | |
2381 | { | |
2382 | ch = ';'; | |
2383 | lphttpHdr->wFlags |= HDR_COMMADELIMITED; | |
2384 | } | |
2385 | ||
bc8bd722 | 2386 | len = origlen + valuelen + ((ch > 0) ? 1 : 0); |
c275724c | 2387 | |
a4e902cb | 2388 | lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR)); |
c275724c UC |
2389 | if (lpsztmp) |
2390 | { | |
9a624916 | 2391 | /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */ |
c275724c UC |
2392 | if (ch > 0) |
2393 | { | |
2394 | lphttpHdr->lpszValue[origlen] = ch; | |
2395 | origlen++; | |
2396 | } | |
2397 | ||
a4e902cb | 2398 | memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); |
c275724c UC |
2399 | lphttpHdr->lpszValue[len] = '\0'; |
2400 | bSuccess = TRUE; | |
2401 | } | |
2402 | else | |
2403 | { | |
bc8bd722 | 2404 | WARN("HeapReAlloc (%d bytes) failed\n",len+1); |
c275724c UC |
2405 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); |
2406 | } | |
2407 | } | |
2408 | } | |
bc8bd722 | 2409 | TRACE("<-- %d\n",bSuccess); |
c275724c UC |
2410 | return bSuccess; |
2411 | } | |
2412 | ||
2413 | ||
2414 | /*********************************************************************** | |
2415 | * HTTP_CloseConnection (internal) | |
2416 | * | |
2417 | * Close socket connection | |
2418 | * | |
2419 | */ | |
a4e902cb | 2420 | VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr) |
c275724c | 2421 | { |
a4e902cb | 2422 | LPWININETHTTPSESSIONW lpwhs = NULL; |
09d2d477 | 2423 | LPWININETAPPINFOW hIC = NULL; |
ff9b9d4e AS |
2424 | |
2425 | TRACE("%p\n",lpwhr); | |
2426 | ||
a4e902cb | 2427 | lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent; |
09d2d477 | 2428 | hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent; |
ff9b9d4e | 2429 | |
3a1391b8 | 2430 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e AS |
2431 | INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); |
2432 | ||
852c7ae4 DH |
2433 | if (NETCON_connected(&lpwhr->netConnection)) |
2434 | { | |
2435 | NETCON_close(&lpwhr->netConnection); | |
2436 | } | |
ff9b9d4e | 2437 | |
3a1391b8 | 2438 | SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext, |
ff9b9d4e | 2439 | INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); |
c275724c UC |
2440 | } |
2441 | ||
2442 | ||
2443 | /*********************************************************************** | |
2444 | * HTTP_CloseHTTPRequestHandle (internal) | |
2445 | * | |
2446 | * Deallocate request handle | |
2447 | * | |
2448 | */ | |
3a1391b8 | 2449 | static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr) |
c275724c | 2450 | { |
13b6ce6d | 2451 | DWORD i; |
3a1391b8 | 2452 | LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; |
c275724c UC |
2453 | |
2454 | TRACE("\n"); | |
2455 | ||
852c7ae4 | 2456 | if (NETCON_connected(&lpwhr->netConnection)) |
c275724c UC |
2457 | HTTP_CloseConnection(lpwhr); |
2458 | ||
2459 | if (lpwhr->lpszPath) | |
2460 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); | |
2461 | if (lpwhr->lpszVerb) | |
2462 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); | |
2463 | if (lpwhr->lpszHostName) | |
2464 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName); | |
dee8751c RS |
2465 | if (lpwhr->lpszRawHeaders) |
2466 | HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); | |
c275724c UC |
2467 | |
2468 | for (i = 0; i <= HTTP_QUERY_MAX; i++) | |
2469 | { | |
2470 | if (lpwhr->StdHeaders[i].lpszField) | |
2471 | HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField); | |
2472 | if (lpwhr->StdHeaders[i].lpszValue) | |
2473 | HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue); | |
2474 | } | |
2475 | ||
2476 | for (i = 0; i < lpwhr->nCustHeaders; i++) | |
2477 | { | |
2478 | if (lpwhr->pCustHeaders[i].lpszField) | |
2479 | HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField); | |
2480 | if (lpwhr->pCustHeaders[i].lpszValue) | |
2481 | HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue); | |
2482 | } | |
2483 | ||
2484 | HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders); | |
2485 | HeapFree(GetProcessHeap(), 0, lpwhr); | |
2486 | } | |
2487 | ||
2488 | ||
2489 | /*********************************************************************** | |
2490 | * HTTP_CloseHTTPSessionHandle (internal) | |
2491 | * | |
2492 | * Deallocate session handle | |
2493 | * | |
2494 | */ | |
3a1391b8 | 2495 | void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr) |
c275724c | 2496 | { |
3a1391b8 | 2497 | LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr; |
7cc70c0a | 2498 | |
852c7ae4 | 2499 | TRACE("%p\n", lpwhs); |
c275724c UC |
2500 | |
2501 | if (lpwhs->lpszServerName) | |
2502 | HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); | |
2503 | if (lpwhs->lpszUserName) | |
2504 | HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); | |
2505 | HeapFree(GetProcessHeap(), 0, lpwhs); | |
2506 | } | |
2507 | ||
2508 | ||
2509 | /*********************************************************************** | |
2510 | * HTTP_GetCustomHeaderIndex (internal) | |
2511 | * | |
2512 | * Return index of custom header from header array | |
2513 | * | |
2514 | */ | |
a4e902cb | 2515 | INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField) |
c275724c | 2516 | { |
13b6ce6d | 2517 | DWORD index; |
c275724c | 2518 | |
a4e902cb | 2519 | TRACE("%s\n", debugstr_w(lpszField)); |
c275724c UC |
2520 | |
2521 | for (index = 0; index < lpwhr->nCustHeaders; index++) | |
2522 | { | |
a4e902cb | 2523 | if (!strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField)) |
c275724c UC |
2524 | break; |
2525 | ||
2526 | } | |
2527 | ||
2528 | if (index >= lpwhr->nCustHeaders) | |
2529 | index = -1; | |
2530 | ||
13b6ce6d | 2531 | TRACE("Return: %lu\n", index); |
c275724c UC |
2532 | return index; |
2533 | } | |
2534 | ||
2535 | ||
2536 | /*********************************************************************** | |
2537 | * HTTP_InsertCustomHeader (internal) | |
2538 | * | |
2539 | * Insert header into array | |
2540 | * | |
2541 | */ | |
a4e902cb | 2542 | BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr) |
c275724c UC |
2543 | { |
2544 | INT count; | |
a4e902cb | 2545 | LPHTTPHEADERW lph = NULL; |
a1c16d28 | 2546 | BOOL r = FALSE; |
c275724c | 2547 | |
a4e902cb | 2548 | TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue)); |
c275724c UC |
2549 | count = lpwhr->nCustHeaders + 1; |
2550 | if (count > 1) | |
a4e902cb | 2551 | lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count); |
c275724c | 2552 | else |
a4e902cb | 2553 | lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count); |
c275724c UC |
2554 | |
2555 | if (NULL != lph) | |
2556 | { | |
2557 | lpwhr->pCustHeaders = lph; | |
a4e902cb MM |
2558 | lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField); |
2559 | lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue); | |
c275724c UC |
2560 | lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; |
2561 | lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; | |
2562 | lpwhr->nCustHeaders++; | |
a1c16d28 | 2563 | r = TRUE; |
c275724c UC |
2564 | } |
2565 | else | |
2566 | { | |
2567 | INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
c275724c UC |
2568 | } |
2569 | ||
a1c16d28 | 2570 | return r; |
c275724c UC |
2571 | } |
2572 | ||
2573 | ||
2574 | /*********************************************************************** | |
2575 | * HTTP_DeleteCustomHeader (internal) | |
2576 | * | |
2577 | * Delete header from array | |
a1c16d28 | 2578 | * If this function is called, the indexs may change. |
c275724c | 2579 | */ |
13b6ce6d | 2580 | BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) |
c275724c | 2581 | { |
a1c16d28 MM |
2582 | if( lpwhr->nCustHeaders <= 0 ) |
2583 | return FALSE; | |
2584 | if( lpwhr->nCustHeaders >= index ) | |
2585 | return FALSE; | |
2586 | lpwhr->nCustHeaders--; | |
2587 | ||
2588 | memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1], | |
a4e902cb MM |
2589 | (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) ); |
2590 | memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) ); | |
a1c16d28 MM |
2591 | |
2592 | return TRUE; | |
c275724c | 2593 | } |
b09eef23 AM |
2594 | |
2595 | /*********************************************************************** | |
2596 | * IsHostInProxyBypassList (@) | |
2597 | * | |
2598 | * Undocumented | |
2599 | * | |
2600 | */ | |
2601 | BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length) | |
2602 | { | |
2603 | FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length); | |
2604 | return FALSE; | |
2605 | } |