- Added My Computer.
[wine/dcerpc.git] / dlls / wininet / http.c
blob0d6f748fc5c78423b7578e19f5f9436c6fd1a30a
1 /*
2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 TransGaming Technologies Inc.
7 * Copyright 2004 Mike McCormack for CodeWeavers
9 * Ulrich Czekalla
10 * Aric Stewart
11 * David Hammerton
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.
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.
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
28 #include "config.h"
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
33 #endif
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <errno.h>
41 #include <string.h>
42 #include <time.h>
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wininet.h"
47 #include "winreg.h"
48 #include "winerror.h"
49 #define NO_SHLWAPI_STREAM
50 #include "shlwapi.h"
52 #include "internet.h"
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
58 #define HTTPHEADER " HTTP/1.0"
59 #define HTTPHOSTHEADER "\r\nHost: "
60 #define MAXHOSTNAME 100
61 #define MAX_FIELD_VALUE_LEN 256
62 #define MAX_FIELD_LEN 256
65 #define HTTP_REFERER "Referer"
66 #define HTTP_ACCEPT "Accept"
67 #define HTTP_USERAGENT "User-Agent"
69 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
70 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
71 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
72 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
73 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
74 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
75 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
78 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
79 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
80 void *Buffer, int BytesToWrite);
81 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
82 void *Buffer, int BytesToRead);
83 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
84 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
85 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
86 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
87 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
88 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
89 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
90 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index);
92 /***********************************************************************
93 * HttpAddRequestHeadersA (WININET.@)
95 * Adds one or more HTTP header to the request handler
97 * RETURNS
98 * TRUE on success
99 * FALSE on failure
102 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
103 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
105 LPSTR lpszStart;
106 LPSTR lpszEnd;
107 LPSTR buffer;
108 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
109 BOOL bSuccess = FALSE;
110 LPWININETHTTPREQA lpwhr;
112 TRACE("%p, %s, %li, %li\n", hHttpRequest, lpszHeader, dwHeaderLength,
113 dwModifier);
115 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
117 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
119 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
120 return FALSE;
123 if (!lpszHeader)
124 return TRUE;
126 TRACE("copying header: %s\n", lpszHeader);
127 buffer = WININET_strdup(lpszHeader);
128 lpszStart = buffer;
132 lpszEnd = lpszStart;
134 while (*lpszEnd != '\0')
136 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
137 break;
138 lpszEnd++;
141 if (*lpszEnd == '\0')
142 break;
144 *lpszEnd = '\0';
146 TRACE("interpreting header %s\n", debugstr_a(lpszStart));
147 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
148 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
150 lpszStart = lpszEnd + 2; /* Jump over \0\n */
152 } while (bSuccess);
154 HeapFree(GetProcessHeap(), 0, buffer);
155 return bSuccess;
158 /***********************************************************************
159 * HttpEndRequestA (WININET.@)
161 * Ends an HTTP request that was started by HttpSendRequestEx
163 * RETURNS
164 * TRUE if successful
165 * FALSE on failure
168 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
169 DWORD dwFlags, DWORD dwContext)
171 FIXME("stub\n");
172 return FALSE;
175 /***********************************************************************
176 * HttpEndRequestW (WININET.@)
178 * Ends an HTTP request that was started by HttpSendRequestEx
180 * RETURNS
181 * TRUE if successful
182 * FALSE on failure
185 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
186 DWORD dwFlags, DWORD dwContext)
188 FIXME("stub\n");
189 return FALSE;
192 /***********************************************************************
193 * HttpOpenRequestA (WININET.@)
195 * Open a HTTP request handle
197 * RETURNS
198 * HINTERNET a HTTP request handle on success
199 * NULL on failure
202 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
203 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
204 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
205 DWORD dwFlags, DWORD dwContext)
207 LPWININETHTTPSESSIONA lpwhs;
208 LPWININETAPPINFOA hIC = NULL;
209 HINTERNET handle = NULL;
211 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
212 debugstr_a(lpszVerb), lpszObjectName,
213 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
214 dwFlags, dwContext);
215 if(lpszAcceptTypes!=NULL)
217 int i;
218 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
219 TRACE("\taccept type: %s\n",lpszAcceptTypes[i]);
222 lpwhs = (LPWININETHTTPSESSIONA) WININET_GetObject( hHttpSession );
223 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
226 return NULL;
228 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
231 * My tests seem to show that the windows version does not
232 * become asynchronous until after this point. And anyhow
233 * if this call was asynchronous then how would you get the
234 * necessary HINTERNET pointer returned by this function.
236 * I am leaving this here just in case I am wrong
238 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
240 if (0)
242 WORKREQUEST workRequest;
243 struct WORKREQ_HTTPOPENREQUESTA *req;
245 workRequest.asyncall = HTTPOPENREQUESTA;
246 workRequest.handle = hHttpSession;
247 req = &workRequest.u.HttpOpenRequestA;
248 req->lpszVerb = WININET_strdup(lpszVerb);
249 req->lpszObjectName = WININET_strdup(lpszObjectName);
250 if (lpszVersion)
251 req->lpszVersion = WININET_strdup(lpszVersion);
252 else
253 req->lpszVersion = 0;
254 if (lpszReferrer)
255 req->lpszReferrer = WININET_strdup(lpszReferrer);
256 else
257 req->lpszReferrer = 0;
258 req->lpszAcceptTypes = lpszAcceptTypes;
259 req->dwFlags = dwFlags;
260 req->dwContext = dwContext;
262 INTERNET_AsyncCall(&workRequest);
264 else
266 handle = HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
267 lpszVersion, lpszReferrer, lpszAcceptTypes,
268 dwFlags, dwContext);
270 TRACE("returning %p\n", handle);
271 return handle;
275 /***********************************************************************
276 * HttpOpenRequestW (WININET.@)
278 * Open a HTTP request handle
280 * RETURNS
281 * HINTERNET a HTTP request handle on success
282 * NULL on failure
284 * FIXME: This should be the other way around (A should call W)
286 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
287 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
288 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
289 DWORD dwFlags, DWORD dwContext)
291 CHAR *szVerb = NULL, *szObjectName = NULL;
292 CHAR *szVersion = NULL, *szReferrer = NULL, **szAcceptTypes = NULL;
293 INT len;
294 INT acceptTypesCount;
295 HINTERNET rc = FALSE;
296 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
297 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
298 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
299 dwFlags, dwContext);
301 if (lpszVerb)
303 len = WideCharToMultiByte(CP_ACP, 0, lpszVerb, -1, NULL, 0, NULL, NULL);
304 szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR) );
305 if ( !szVerb )
306 goto end;
307 WideCharToMultiByte(CP_ACP, 0, lpszVerb, -1, szVerb, len, NULL, NULL);
310 if (lpszObjectName)
312 len = WideCharToMultiByte(CP_ACP, 0, lpszObjectName, -1, NULL, 0, NULL, NULL);
313 szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR) );
314 if ( !szObjectName )
315 goto end;
316 WideCharToMultiByte(CP_ACP, 0, lpszObjectName, -1, szObjectName, len, NULL, NULL);
319 if (lpszVersion)
321 len = WideCharToMultiByte(CP_ACP, 0, lpszVersion, -1, NULL, 0, NULL, NULL);
322 szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
323 if ( !szVersion )
324 goto end;
325 WideCharToMultiByte(CP_ACP, 0, lpszVersion, -1, szVersion, len, NULL, NULL);
328 if (lpszReferrer)
330 len = WideCharToMultiByte(CP_ACP, 0, lpszReferrer, -1, NULL, 0, NULL, NULL);
331 szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
332 if ( !szReferrer )
333 goto end;
334 WideCharToMultiByte(CP_ACP, 0, lpszReferrer, -1, szReferrer, len, NULL, NULL);
337 acceptTypesCount = 0;
338 if (lpszAcceptTypes)
340 while (lpszAcceptTypes[acceptTypesCount]) { acceptTypesCount++; } /* find out how many there are */
341 szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR *) * acceptTypesCount);
342 acceptTypesCount = 0;
343 while (lpszAcceptTypes[acceptTypesCount])
345 len = WideCharToMultiByte(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
346 -1, NULL, 0, NULL, NULL);
347 szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
348 if (!szAcceptTypes[acceptTypesCount] )
349 goto end;
350 WideCharToMultiByte(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
351 -1, szAcceptTypes[acceptTypesCount], len, NULL, NULL);
352 acceptTypesCount++;
355 else szAcceptTypes = 0;
357 rc = HttpOpenRequestA(hHttpSession, (LPCSTR)szVerb, (LPCSTR)szObjectName,
358 (LPCSTR)szVersion, (LPCSTR)szReferrer,
359 (LPCSTR *)szAcceptTypes, dwFlags, dwContext);
361 end:
362 if (szAcceptTypes)
364 acceptTypesCount = 0;
365 while (szAcceptTypes[acceptTypesCount])
367 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
368 acceptTypesCount++;
370 HeapFree(GetProcessHeap(), 0, szAcceptTypes);
372 if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer);
373 if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion);
374 if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName);
375 if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb);
377 return rc;
380 /***********************************************************************
381 * HTTP_Base64
383 static UINT HTTP_Base64( LPCSTR bin, LPSTR base64 )
385 UINT n = 0, x;
386 static LPSTR HTTP_Base64Enc =
387 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
389 while( bin[0] )
391 /* first 6 bits, all from bin[0] */
392 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
393 x = (bin[0] & 3) << 4;
395 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
396 if( !bin[1] )
398 base64[n++] = HTTP_Base64Enc[x];
399 base64[n++] = '=';
400 base64[n++] = '=';
401 break;
403 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
404 x = ( bin[1] & 0x0f ) << 2;
406 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
407 if( !bin[2] )
409 base64[n++] = HTTP_Base64Enc[x];
410 base64[n++] = '=';
411 break;
413 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
415 /* last 6 bits, all from bin [2] */
416 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
417 bin += 3;
419 base64[n] = 0;
420 return n;
423 /***********************************************************************
424 * HTTP_EncodeBasicAuth
426 * Encode the basic authentication string for HTTP 1.1
428 static LPSTR HTTP_EncodeBasicAuth( LPCSTR username, LPCSTR password)
430 UINT len;
431 LPSTR in, out, szBasic = "Basic ";
433 len = strlen( username ) + 1 + strlen ( password ) + 1;
434 in = HeapAlloc( GetProcessHeap(), 0, len );
435 if( !in )
436 return NULL;
438 len = strlen(szBasic) +
439 (strlen( username ) + 1 + strlen ( password ))*2 + 1 + 1;
440 out = HeapAlloc( GetProcessHeap(), 0, len );
441 if( out )
443 strcpy( in, username );
444 strcat( in, ":" );
445 strcat( in, password );
446 strcpy( out, szBasic );
447 HTTP_Base64( in, &out[strlen(out)] );
449 HeapFree( GetProcessHeap(), 0, in );
451 return out;
454 /***********************************************************************
455 * HTTP_InsertProxyAuthorization
457 * Insert the basic authorization field in the request header
459 BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQA lpwhr,
460 LPCSTR username, LPCSTR password )
462 HTTPHEADERA hdr;
463 INT index;
465 hdr.lpszField = "Proxy-Authorization";
466 hdr.lpszValue = HTTP_EncodeBasicAuth( username, password );
467 hdr.wFlags = HDR_ISREQUEST;
468 hdr.wCount = 0;
469 if( !hdr.lpszValue )
470 return FALSE;
472 TRACE("Inserting %s = %s\n",
473 debugstr_a( hdr.lpszField ), debugstr_a( hdr.lpszValue ) );
475 /* remove the old proxy authorization header */
476 index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField );
477 if( index >=0 )
478 HTTP_DeleteCustomHeader( lpwhr, index );
480 HTTP_InsertCustomHeader(lpwhr, &hdr);
481 HeapFree( GetProcessHeap(), 0, hdr.lpszValue );
483 return TRUE;
486 /***********************************************************************
487 * HTTP_DealWithProxy
489 static BOOL HTTP_DealWithProxy( LPWININETAPPINFOA hIC,
490 LPWININETHTTPSESSIONA lpwhs, LPWININETHTTPREQA lpwhr)
492 char buf[MAXHOSTNAME];
493 char proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
494 char* url, *szNul = "";
495 URL_COMPONENTSA UrlComponents;
497 memset( &UrlComponents, 0, sizeof UrlComponents );
498 UrlComponents.dwStructSize = sizeof UrlComponents;
499 UrlComponents.lpszHostName = buf;
500 UrlComponents.dwHostNameLength = MAXHOSTNAME;
502 if (strncasecmp(hIC->lpszProxy,"http://",strlen("http://")))
503 sprintf(proxy, "http://%s/", hIC->lpszProxy);
504 else
505 strcpy(proxy,hIC->lpszProxy);
506 if( !InternetCrackUrlA(proxy, 0, 0, &UrlComponents) )
507 return FALSE;
508 if( UrlComponents.dwHostNameLength == 0 )
509 return FALSE;
511 if( !lpwhr->lpszPath )
512 lpwhr->lpszPath = szNul;
513 TRACE("server='%s' path='%s'\n",
514 lpwhs->lpszServerName, lpwhr->lpszPath);
515 /* for constant 15 see above */
516 url = HeapAlloc(GetProcessHeap(), 0,
517 strlen(lpwhs->lpszServerName) + strlen(lpwhr->lpszPath) + 15);
519 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
520 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
522 sprintf(url, "http://%s:%d", lpwhs->lpszServerName,
523 lpwhs->nServerPort);
524 if( lpwhr->lpszPath[0] != '/' )
525 strcat( url, "/" );
526 strcat(url, lpwhr->lpszPath);
527 if(lpwhr->lpszPath != szNul)
528 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
529 lpwhr->lpszPath = url;
530 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
531 lpwhs->lpszServerName = WININET_strdup(UrlComponents.lpszHostName);
532 lpwhs->nServerPort = UrlComponents.nPort;
534 return TRUE;
537 /***********************************************************************
538 * HTTP_HttpOpenRequestA (internal)
540 * Open a HTTP request handle
542 * RETURNS
543 * HINTERNET a HTTP request handle on success
544 * NULL on failure
547 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
548 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
549 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
550 DWORD dwFlags, DWORD dwContext)
552 LPWININETHTTPSESSIONA lpwhs;
553 LPWININETAPPINFOA hIC = NULL;
554 LPWININETHTTPREQA lpwhr;
555 LPSTR lpszCookies;
556 LPSTR lpszUrl = NULL;
557 DWORD nCookieSize;
558 HINTERNET handle;
560 TRACE("--> \n");
562 lpwhs = (LPWININETHTTPSESSIONA) WININET_GetObject( hHttpSession );
563 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
565 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
566 return NULL;
569 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
571 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
572 if (NULL == lpwhr)
574 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
575 return NULL;
577 handle = WININET_AllocHandle( &lpwhr->hdr );
578 if (NULL == handle)
580 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
581 HeapFree( GetProcessHeap(), 0, lpwhr );
582 return NULL;
585 lpwhr->hdr.htype = WH_HHTTPREQ;
586 lpwhr->hdr.lpwhparent = &lpwhs->hdr;
587 lpwhr->hdr.dwFlags = dwFlags;
588 lpwhr->hdr.dwContext = dwContext;
589 NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE);
591 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
592 DWORD needed = 0;
593 HRESULT rc;
594 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
595 if (rc != E_POINTER)
596 needed = strlen(lpszObjectName)+1;
597 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
598 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
599 URL_ESCAPE_SPACES_ONLY);
600 if (rc)
602 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
603 strcpy(lpwhr->lpszPath,lpszObjectName);
607 if (NULL != lpszReferrer && strlen(lpszReferrer))
608 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
610 if(lpszAcceptTypes!=NULL)
612 int i;
613 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
614 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
617 if (NULL == lpszVerb)
618 lpwhr->lpszVerb = WININET_strdup("GET");
619 else if (strlen(lpszVerb))
620 lpwhr->lpszVerb = WININET_strdup(lpszVerb);
622 if (NULL != lpszReferrer && strlen(lpszReferrer))
624 char buf[MAXHOSTNAME];
625 URL_COMPONENTSA UrlComponents;
627 memset( &UrlComponents, 0, sizeof UrlComponents );
628 UrlComponents.dwStructSize = sizeof UrlComponents;
629 UrlComponents.lpszHostName = buf;
630 UrlComponents.dwHostNameLength = MAXHOSTNAME;
632 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
633 if (strlen(UrlComponents.lpszHostName))
634 lpwhr->lpszHostName = WININET_strdup(UrlComponents.lpszHostName);
635 } else {
636 lpwhr->lpszHostName = WININET_strdup(lpwhs->lpszServerName);
638 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
639 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
641 if (hIC->lpszAgent)
643 char *agent_header = HeapAlloc(GetProcessHeap(), 0, strlen(hIC->lpszAgent) + 1 + 14);
644 sprintf(agent_header, "User-Agent: %s\r\n", hIC->lpszAgent);
645 HttpAddRequestHeadersA(handle, agent_header, strlen(agent_header),
646 HTTP_ADDREQ_FLAG_ADD);
647 HeapFree(GetProcessHeap(), 0, agent_header);
650 lpszUrl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + 1 + 7);
651 sprintf(lpszUrl, "http://%s", lpwhr->lpszHostName);
652 if (InternetGetCookieA(lpszUrl, NULL, NULL, &nCookieSize))
654 int cnt = 0;
656 lpszCookies = HeapAlloc(GetProcessHeap(), 0, nCookieSize + 1 + 8);
658 cnt += sprintf(lpszCookies, "Cookie: ");
659 InternetGetCookieA(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
660 cnt += nCookieSize - 1;
661 sprintf(lpszCookies + cnt, "\r\n");
663 HttpAddRequestHeadersA(handle, lpszCookies, strlen(lpszCookies),
664 HTTP_ADDREQ_FLAG_ADD);
665 HeapFree(GetProcessHeap(), 0, lpszCookies);
667 HeapFree(GetProcessHeap(), 0, lpszUrl);
671 if (hIC->lpfnStatusCB)
673 INTERNET_ASYNC_RESULT iar;
675 iar.dwResult = (DWORD)handle;
676 iar.dwError = ERROR_SUCCESS;
678 SendAsyncCallback(hIC, hHttpSession, dwContext,
679 INTERNET_STATUS_HANDLE_CREATED, &iar,
680 sizeof(INTERNET_ASYNC_RESULT));
684 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
688 * According to my tests. The name is not resolved until a request is Opened
690 SendAsyncCallback(hIC, hHttpSession, dwContext,
691 INTERNET_STATUS_RESOLVING_NAME,
692 lpwhs->lpszServerName,
693 strlen(lpwhs->lpszServerName)+1);
694 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
695 &lpwhs->phostent, &lpwhs->socketAddress))
697 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
698 return NULL;
701 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
702 INTERNET_STATUS_NAME_RESOLVED,
703 &(lpwhs->socketAddress),
704 sizeof(struct sockaddr_in));
706 TRACE("<-- %p\n", handle);
707 return handle;
711 /***********************************************************************
712 * HttpQueryInfoA (WININET.@)
714 * Queries for information about an HTTP request
716 * RETURNS
717 * TRUE on success
718 * FALSE on failure
721 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
722 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
724 LPHTTPHEADERA lphttpHdr = NULL;
725 BOOL bSuccess = FALSE;
726 LPWININETHTTPREQA lpwhr;
728 if (TRACE_ON(wininet)) {
729 #define FE(x) { x, #x }
730 static const wininet_flag_info query_flags[] = {
731 FE(HTTP_QUERY_MIME_VERSION),
732 FE(HTTP_QUERY_CONTENT_TYPE),
733 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
734 FE(HTTP_QUERY_CONTENT_ID),
735 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
736 FE(HTTP_QUERY_CONTENT_LENGTH),
737 FE(HTTP_QUERY_CONTENT_LANGUAGE),
738 FE(HTTP_QUERY_ALLOW),
739 FE(HTTP_QUERY_PUBLIC),
740 FE(HTTP_QUERY_DATE),
741 FE(HTTP_QUERY_EXPIRES),
742 FE(HTTP_QUERY_LAST_MODIFIED),
743 FE(HTTP_QUERY_MESSAGE_ID),
744 FE(HTTP_QUERY_URI),
745 FE(HTTP_QUERY_DERIVED_FROM),
746 FE(HTTP_QUERY_COST),
747 FE(HTTP_QUERY_LINK),
748 FE(HTTP_QUERY_PRAGMA),
749 FE(HTTP_QUERY_VERSION),
750 FE(HTTP_QUERY_STATUS_CODE),
751 FE(HTTP_QUERY_STATUS_TEXT),
752 FE(HTTP_QUERY_RAW_HEADERS),
753 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
754 FE(HTTP_QUERY_CONNECTION),
755 FE(HTTP_QUERY_ACCEPT),
756 FE(HTTP_QUERY_ACCEPT_CHARSET),
757 FE(HTTP_QUERY_ACCEPT_ENCODING),
758 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
759 FE(HTTP_QUERY_AUTHORIZATION),
760 FE(HTTP_QUERY_CONTENT_ENCODING),
761 FE(HTTP_QUERY_FORWARDED),
762 FE(HTTP_QUERY_FROM),
763 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
764 FE(HTTP_QUERY_LOCATION),
765 FE(HTTP_QUERY_ORIG_URI),
766 FE(HTTP_QUERY_REFERER),
767 FE(HTTP_QUERY_RETRY_AFTER),
768 FE(HTTP_QUERY_SERVER),
769 FE(HTTP_QUERY_TITLE),
770 FE(HTTP_QUERY_USER_AGENT),
771 FE(HTTP_QUERY_WWW_AUTHENTICATE),
772 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
773 FE(HTTP_QUERY_ACCEPT_RANGES),
774 FE(HTTP_QUERY_SET_COOKIE),
775 FE(HTTP_QUERY_COOKIE),
776 FE(HTTP_QUERY_REQUEST_METHOD),
777 FE(HTTP_QUERY_REFRESH),
778 FE(HTTP_QUERY_CONTENT_DISPOSITION),
779 FE(HTTP_QUERY_AGE),
780 FE(HTTP_QUERY_CACHE_CONTROL),
781 FE(HTTP_QUERY_CONTENT_BASE),
782 FE(HTTP_QUERY_CONTENT_LOCATION),
783 FE(HTTP_QUERY_CONTENT_MD5),
784 FE(HTTP_QUERY_CONTENT_RANGE),
785 FE(HTTP_QUERY_ETAG),
786 FE(HTTP_QUERY_HOST),
787 FE(HTTP_QUERY_IF_MATCH),
788 FE(HTTP_QUERY_IF_NONE_MATCH),
789 FE(HTTP_QUERY_IF_RANGE),
790 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
791 FE(HTTP_QUERY_MAX_FORWARDS),
792 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
793 FE(HTTP_QUERY_RANGE),
794 FE(HTTP_QUERY_TRANSFER_ENCODING),
795 FE(HTTP_QUERY_UPGRADE),
796 FE(HTTP_QUERY_VARY),
797 FE(HTTP_QUERY_VIA),
798 FE(HTTP_QUERY_WARNING),
799 FE(HTTP_QUERY_CUSTOM)
801 static const wininet_flag_info modifier_flags[] = {
802 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
803 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
804 FE(HTTP_QUERY_FLAG_NUMBER),
805 FE(HTTP_QUERY_FLAG_COALESCE)
807 #undef FE
808 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
809 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
810 int i;
812 TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
813 TRACE(" Attribute:");
814 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
815 if (query_flags[i].val == info) {
816 DPRINTF(" %s", query_flags[i].name);
817 break;
820 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
821 DPRINTF(" Unknown (%08lx)", info);
824 DPRINTF(" Modifier:");
825 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
826 if (modifier_flags[i].val & info_mod) {
827 DPRINTF(" %s", modifier_flags[i].name);
828 info_mod &= ~ modifier_flags[i].val;
832 if (info_mod) {
833 DPRINTF(" Unknown (%08lx)", info_mod);
835 DPRINTF("\n");
838 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
839 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
841 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
842 goto lend;
845 /* Find requested header structure */
846 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
848 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
850 if (index < 0)
851 goto lend;
853 lphttpHdr = &lpwhr->pCustHeaders[index];
855 else
857 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
859 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
861 INT i, delim, size = 0, cnt = 0;
863 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
865 /* Calculate length of custom reuqest headers */
866 for (i = 0; i < lpwhr->nCustHeaders; i++)
868 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
869 lpwhr->pCustHeaders[i].lpszValue)
871 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
872 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
876 /* Calculate the length of stadard request headers */
877 for (i = 0; i <= HTTP_QUERY_MAX; i++)
879 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
880 lpwhr->StdHeaders[i].lpszValue)
882 size += strlen(lpwhr->StdHeaders[i].lpszField) +
883 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
886 size += delim;
888 if (size + 1 > *lpdwBufferLength)
890 *lpdwBufferLength = size + 1;
891 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
892 goto lend;
895 /* Append standard request heades */
896 for (i = 0; i <= HTTP_QUERY_MAX; i++)
898 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
899 lpwhr->StdHeaders[i].lpszField &&
900 lpwhr->StdHeaders[i].lpszValue)
902 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
903 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
907 /* Append custom request heades */
908 for (i = 0; i < lpwhr->nCustHeaders; i++)
910 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
911 lpwhr->pCustHeaders[i].lpszField &&
912 lpwhr->pCustHeaders[i].lpszValue)
914 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
915 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
916 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
920 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
922 *lpdwBufferLength = cnt + delim;
923 bSuccess = TRUE;
924 goto lend;
926 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
928 lphttpHdr = &lpwhr->StdHeaders[index];
930 else
931 goto lend;
934 /* Ensure header satisifies requested attributes */
935 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
936 (~lphttpHdr->wFlags & HDR_ISREQUEST))
937 goto lend;
939 /* coalesce value to reuqested type */
940 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
942 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
943 bSuccess = TRUE;
945 TRACE(" returning number : %d\n", *(int *)lpBuffer);
947 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
949 time_t tmpTime;
950 struct tm tmpTM;
951 SYSTEMTIME *STHook;
953 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
955 tmpTM = *gmtime(&tmpTime);
956 STHook = (SYSTEMTIME *) lpBuffer;
957 if(STHook==NULL)
958 goto lend;
960 STHook->wDay = tmpTM.tm_mday;
961 STHook->wHour = tmpTM.tm_hour;
962 STHook->wMilliseconds = 0;
963 STHook->wMinute = tmpTM.tm_min;
964 STHook->wDayOfWeek = tmpTM.tm_wday;
965 STHook->wMonth = tmpTM.tm_mon + 1;
966 STHook->wSecond = tmpTM.tm_sec;
967 STHook->wYear = tmpTM.tm_year;
969 bSuccess = TRUE;
971 TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
972 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
973 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
975 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
977 if (*lpdwIndex >= lphttpHdr->wCount)
979 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
981 else
983 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
984 (*lpdwIndex)++;
987 else
989 INT len = strlen(lphttpHdr->lpszValue);
991 if (len + 1 > *lpdwBufferLength)
993 *lpdwBufferLength = len + 1;
994 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
995 goto lend;
998 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
999 ((char*)lpBuffer)[len]=0;
1000 *lpdwBufferLength = len;
1001 bSuccess = TRUE;
1003 TRACE(" returning string : '%s'\n", debugstr_a(lpBuffer));
1006 lend:
1007 TRACE("%d <--\n", bSuccess);
1008 return bSuccess;
1011 /***********************************************************************
1012 * HttpQueryInfoW (WININET.@)
1014 * Queries for information about an HTTP request
1016 * RETURNS
1017 * TRUE on success
1018 * FALSE on failure
1021 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1022 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1024 BOOL result;
1025 DWORD charLen=*lpdwBufferLength;
1026 char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
1027 result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
1028 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1029 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1031 memcpy(lpBuffer,tempBuffer,charLen);
1033 else
1035 int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
1036 *lpdwBufferLength=nChars;
1038 HeapFree(GetProcessHeap(), 0, tempBuffer);
1039 return result;
1042 /***********************************************************************
1043 * HttpSendRequestExA (WININET.@)
1045 * Sends the specified request to the HTTP server and allows chunked
1046 * transfers
1048 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1049 LPINTERNET_BUFFERSA lpBuffersIn,
1050 LPINTERNET_BUFFERSA lpBuffersOut,
1051 DWORD dwFlags, DWORD dwContext)
1053 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1054 lpBuffersOut, dwFlags, dwContext);
1055 return FALSE;
1058 /***********************************************************************
1059 * HttpSendRequestA (WININET.@)
1061 * Sends the specified request to the HTTP server
1063 * RETURNS
1064 * TRUE on success
1065 * FALSE on failure
1068 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1069 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1071 LPWININETHTTPREQA lpwhr;
1072 LPWININETHTTPSESSIONA lpwhs = NULL;
1073 LPWININETAPPINFOA hIC = NULL;
1075 TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1076 lpszHeaders, debugstr_a(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1078 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1079 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1081 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1082 return FALSE;
1085 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1086 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1088 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1089 return FALSE;
1092 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1093 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1095 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1096 return FALSE;
1099 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1101 WORKREQUEST workRequest;
1102 struct WORKREQ_HTTPSENDREQUESTA *req;
1104 workRequest.asyncall = HTTPSENDREQUESTA;
1105 workRequest.handle = hHttpRequest;
1106 req = &workRequest.u.HttpSendRequestA;
1107 if (lpszHeaders)
1108 req->lpszHeader = WININET_strdup(lpszHeaders);
1109 else
1110 req->lpszHeader = 0;
1111 req->dwHeaderLength = dwHeaderLength;
1112 req->lpOptional = lpOptional;
1113 req->dwOptionalLength = dwOptionalLength;
1115 INTERNET_AsyncCall(&workRequest);
1117 * This is from windows.
1119 SetLastError(ERROR_IO_PENDING);
1120 return 0;
1122 else
1124 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
1125 dwHeaderLength, lpOptional, dwOptionalLength);
1129 /***********************************************************************
1130 * HttpSendRequestW (WININET.@)
1132 * Sends the specified request to the HTTP server
1134 * RETURNS
1135 * TRUE on success
1136 * FALSE on failure
1139 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1140 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1142 BOOL result;
1143 char* szHeaders=NULL;
1144 DWORD nLen=dwHeaderLength;
1145 if(lpszHeaders!=NULL)
1147 nLen=WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0,NULL,NULL);
1148 szHeaders=HeapAlloc(GetProcessHeap(),0,nLen);
1149 WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen,NULL,NULL);
1151 result=HttpSendRequestA(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1152 if(szHeaders!=NULL)
1153 HeapFree(GetProcessHeap(),0,szHeaders);
1154 return result;
1157 /***********************************************************************
1158 * HTTP_HandleRedirect (internal)
1160 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
1161 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1163 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1164 LPWININETAPPINFOA hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1165 char path[2048];
1166 HINTERNET handle;
1168 if(lpszUrl[0]=='/')
1170 /* if it's an absolute path, keep the same session info */
1171 strcpy(path,lpszUrl);
1173 else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1175 TRACE("Redirect through proxy\n");
1176 strcpy(path,lpszUrl);
1178 else
1180 URL_COMPONENTSA urlComponents;
1181 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
1182 char password[1024], extra[1024];
1183 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
1184 urlComponents.lpszScheme = protocol;
1185 urlComponents.dwSchemeLength = 32;
1186 urlComponents.lpszHostName = hostName;
1187 urlComponents.dwHostNameLength = MAXHOSTNAME;
1188 urlComponents.lpszUserName = userName;
1189 urlComponents.dwUserNameLength = 1024;
1190 urlComponents.lpszPassword = password;
1191 urlComponents.dwPasswordLength = 1024;
1192 urlComponents.lpszUrlPath = path;
1193 urlComponents.dwUrlPathLength = 2048;
1194 urlComponents.lpszExtraInfo = extra;
1195 urlComponents.dwExtraInfoLength = 1024;
1196 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
1197 return FALSE;
1199 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1200 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1202 #if 0
1204 * This upsets redirects to binary files on sourceforge.net
1205 * and gives an html page instead of the target file
1206 * Examination of the HTTP request sent by native wininet.dll
1207 * reveals that it doesn't send a referrer in that case.
1208 * Maybe there's a flag that enables this, or maybe a referrer
1209 * shouldn't be added in case of a redirect.
1212 /* consider the current host as the referrer */
1213 if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
1214 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1215 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1216 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1217 #endif
1219 if (NULL != lpwhs->lpszServerName)
1220 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1221 lpwhs->lpszServerName = WININET_strdup(hostName);
1222 if (NULL != lpwhs->lpszUserName)
1223 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1224 lpwhs->lpszUserName = WININET_strdup(userName);
1225 lpwhs->nServerPort = urlComponents.nPort;
1227 if (NULL != lpwhr->lpszHostName)
1228 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1229 lpwhr->lpszHostName=WININET_strdup(hostName);
1231 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1232 INTERNET_STATUS_RESOLVING_NAME,
1233 lpwhs->lpszServerName,
1234 strlen(lpwhs->lpszServerName)+1);
1236 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1237 &lpwhs->phostent, &lpwhs->socketAddress))
1239 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1240 return FALSE;
1243 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1244 INTERNET_STATUS_NAME_RESOLVED,
1245 &(lpwhs->socketAddress),
1246 sizeof(struct sockaddr_in));
1250 if(lpwhr->lpszPath)
1251 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1252 lpwhr->lpszPath=NULL;
1253 if (strlen(path))
1255 DWORD needed = 0;
1256 HRESULT rc;
1257 rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1258 if (rc != E_POINTER)
1259 needed = strlen(path)+1;
1260 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
1261 rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
1262 URL_ESCAPE_SPACES_ONLY);
1263 if (rc)
1265 ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
1266 strcpy(lpwhr->lpszPath,path);
1270 handle = WININET_FindHandle( &lpwhr->hdr );
1271 return HttpSendRequestA(handle, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1274 /***********************************************************************
1275 * HTTP_HttpSendRequestA (internal)
1277 * Sends the specified request to the HTTP server
1279 * RETURNS
1280 * TRUE on success
1281 * FALSE on failure
1284 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1285 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1287 INT cnt;
1288 INT i;
1289 BOOL bSuccess = FALSE;
1290 LPSTR requestString = NULL;
1291 LPSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */
1292 INT requestStringLen;
1293 INT responseLen;
1294 INT headerLength = 0;
1295 LPWININETHTTPREQA lpwhr;
1296 LPWININETHTTPSESSIONA lpwhs = NULL;
1297 LPWININETAPPINFOA hIC = NULL;
1298 BOOL loop_next = FALSE;
1299 int CustHeaderIndex;
1301 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
1303 /* Verify our tree of internet handles */
1304 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1305 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1307 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1308 return FALSE;
1311 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1312 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1314 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1315 return FALSE;
1318 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1319 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1321 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1322 return FALSE;
1325 /* Clear any error information */
1326 INTERNET_SetLastError(0);
1329 /* We must have a verb */
1330 if (NULL == lpwhr->lpszVerb)
1332 goto lend;
1335 /* if we are using optional stuff, we must add the fixed header of that option length */
1336 if (lpOptional && dwOptionalLength)
1338 char contentLengthStr[sizeof("Content-Length: ") + 20 /* int */ + 2 /* \n\r */];
1339 sprintf(contentLengthStr, "Content-Length: %li\r\n", dwOptionalLength);
1340 HttpAddRequestHeadersA(hHttpRequest, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1345 TRACE("Going to url %s %s\n", debugstr_a(lpwhr->lpszHostName), debugstr_a(lpwhr->lpszPath));
1346 loop_next = FALSE;
1348 /* If we don't have a path we set it to root */
1349 if (NULL == lpwhr->lpszPath)
1350 lpwhr->lpszPath = WININET_strdup("/");
1352 if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
1353 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1355 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
1356 *fixurl = '/';
1357 strcpy(fixurl + 1, lpwhr->lpszPath);
1358 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1359 lpwhr->lpszPath = fixurl;
1362 /* Calculate length of request string */
1363 requestStringLen =
1364 strlen(lpwhr->lpszVerb) +
1365 strlen(lpwhr->lpszPath) +
1366 strlen(HTTPHEADER) +
1367 5; /* " \r\n\r\n" */
1369 /* add "\r\n" to end of lpszHeaders if needed */
1370 if (lpszHeaders)
1372 int len = strlen(lpszHeaders);
1374 /* Check if the string is terminated with \r\n, but not if
1375 * the string is less that 2 characters long, because then
1376 * we would be looking at memory before the beginning of
1377 * the string. Besides, if it is less than 2 characters
1378 * long, then clearly, its not terminated with \r\n.
1380 if ((len > 2) && (memcmp(lpszHeaders + (len - 2), "\r\n", 2) == 0))
1382 lpszHeaders_r_n = WININET_strdup(lpszHeaders);
1384 else
1386 TRACE("Adding \r\n to lpszHeaders.\n");
1387 lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0, strlen(lpszHeaders) + 3 );
1388 strcpy( lpszHeaders_r_n, lpszHeaders );
1389 strcpy( lpszHeaders_r_n + strlen(lpszHeaders), "\r\n" );
1393 /* Add length of passed headers */
1394 if (lpszHeaders)
1396 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders_r_n) : dwHeaderLength;
1397 requestStringLen += headerLength + 2; /* \r\n */
1401 /* if there isa proxy username and password, add it to the headers */
1402 if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) )
1404 HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword );
1407 /* Calculate length of custom request headers */
1408 for (i = 0; i < lpwhr->nCustHeaders; i++)
1410 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1412 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
1413 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
1417 /* Calculate the length of standard request headers */
1418 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1420 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1422 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
1423 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
1427 if (lpwhr->lpszHostName)
1428 requestStringLen += (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName));
1430 /* if there is optional data to send, add the length */
1431 if (lpOptional)
1433 requestStringLen += dwOptionalLength;
1436 /* Allocate string to hold entire request */
1437 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
1438 if (NULL == requestString)
1440 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1441 goto lend;
1444 /* Build request string */
1445 cnt = sprintf(requestString, "%s %s%s",
1446 lpwhr->lpszVerb,
1447 lpwhr->lpszPath,
1448 HTTPHEADER);
1450 /* Append standard request headers */
1451 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1453 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1455 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1456 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1457 TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
1461 /* Append custom request heades */
1462 for (i = 0; i < lpwhr->nCustHeaders; i++)
1464 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1466 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1467 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1468 TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
1472 if (lpwhr->lpszHostName)
1473 cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName);
1475 /* Append passed request headers */
1476 if (lpszHeaders_r_n)
1478 strcpy(requestString + cnt, "\r\n");
1479 cnt += 2;
1480 strcpy(requestString + cnt, lpszHeaders_r_n);
1481 cnt += headerLength;
1482 /* only add \r\n if not already present */
1483 if (memcmp((requestString + cnt) - 2, "\r\n", 2) != 0)
1485 strcpy(requestString + cnt, "\r\n");
1486 cnt += 2;
1490 /* Set (header) termination string for request */
1491 if (memcmp((requestString + cnt) - 4, "\r\n\r\n", 4) != 0)
1492 { /* only add it if the request string doesn't already
1493 have the thing.. (could happen if the custom header
1494 added it */
1495 strcpy(requestString + cnt, "\r\n");
1496 cnt += 2;
1498 else
1499 requestStringLen -= 2;
1501 /* if optional data, append it */
1502 if (lpOptional)
1504 memcpy(requestString + cnt, lpOptional, dwOptionalLength);
1505 cnt += dwOptionalLength;
1506 /* we also have to decrease the expected string length by two,
1507 * since we won't be adding on those following \r\n's */
1508 requestStringLen -= 2;
1510 else
1511 { /* if there is no optional data, add on another \r\n just to be safe */
1512 /* termination for request */
1513 strcpy(requestString + cnt, "\r\n");
1514 cnt += 2;
1517 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1518 /* Send the request and store the results */
1519 if (!HTTP_OpenConnection(lpwhr))
1520 goto lend;
1522 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1523 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1525 NETCON_send(&lpwhr->netConnection, requestString, requestStringLen,
1526 0, &cnt);
1529 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1530 INTERNET_STATUS_REQUEST_SENT,
1531 &requestStringLen,sizeof(DWORD));
1533 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1534 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1536 if (cnt < 0)
1537 goto lend;
1539 responseLen = HTTP_GetResponseHeaders(lpwhr);
1540 if (responseLen)
1541 bSuccess = TRUE;
1543 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1544 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1545 sizeof(DWORD));
1547 /* process headers here. Is this right? */
1548 CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, "Set-Cookie");
1549 if (CustHeaderIndex >= 0)
1551 LPHTTPHEADERA setCookieHeader;
1552 int nPosStart = 0, nPosEnd = 0;
1554 setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1556 while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1558 LPSTR buf_cookie, cookie_name, cookie_data;
1559 LPSTR buf_url;
1560 LPSTR domain = NULL;
1561 int nEqualPos = 0;
1562 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1563 setCookieHeader->lpszValue[nPosEnd] != '\0')
1565 nPosEnd++;
1567 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1569 /* fixme: not case sensitive, strcasestr is gnu only */
1570 int nDomainPosEnd = 0;
1571 int nDomainPosStart = 0, nDomainLength = 0;
1572 LPSTR lpszDomain = strstr(&setCookieHeader->lpszValue[nPosEnd], "domain=");
1573 if (lpszDomain)
1574 { /* they have specified their own domain, lets use it */
1575 while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1576 lpszDomain[nDomainPosEnd] != '\0')
1578 nDomainPosEnd++;
1580 nDomainPosStart = strlen("domain=");
1581 nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1582 domain = HeapAlloc(GetProcessHeap(), 0, nDomainLength + 1);
1583 strncpy(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1584 domain[nDomainLength] = '\0';
1587 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1588 buf_cookie = HeapAlloc(GetProcessHeap(), 0, (nPosEnd - nPosStart) + 1);
1589 strncpy(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1590 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1591 TRACE("%s\n", buf_cookie);
1592 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1594 nEqualPos++;
1596 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1598 HeapFree(GetProcessHeap(), 0, buf_cookie);
1599 break;
1602 cookie_name = HeapAlloc(GetProcessHeap(), 0, nEqualPos + 1);
1603 strncpy(cookie_name, buf_cookie, nEqualPos);
1604 cookie_name[nEqualPos] = '\0';
1605 cookie_data = &buf_cookie[nEqualPos + 1];
1608 buf_url = HeapAlloc(GetProcessHeap(), 0, strlen((domain ? domain : lpwhr->lpszHostName)) + strlen(lpwhr->lpszPath) + 9);
1609 sprintf(buf_url, "http://%s/", (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1610 InternetSetCookieA(buf_url, cookie_name, cookie_data);
1612 HeapFree(GetProcessHeap(), 0, buf_url);
1613 HeapFree(GetProcessHeap(), 0, buf_cookie);
1614 HeapFree(GetProcessHeap(), 0, cookie_name);
1615 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1616 nPosStart = nPosEnd;
1620 while (loop_next);
1622 lend:
1624 if (requestString)
1625 HeapFree(GetProcessHeap(), 0, requestString);
1627 if (lpszHeaders)
1628 HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n);
1630 /* TODO: send notification for P3P header */
1632 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1634 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1635 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1636 (dwCode==302 || dwCode==301))
1638 char szNewLocation[2048];
1639 DWORD dwBufferSize=2048;
1640 dwIndex=0;
1641 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1643 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1644 INTERNET_STATUS_REDIRECT, szNewLocation,
1645 dwBufferSize);
1646 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1647 dwHeaderLength, lpOptional, dwOptionalLength);
1652 if (hIC->lpfnStatusCB)
1654 INTERNET_ASYNC_RESULT iar;
1656 iar.dwResult = (DWORD)bSuccess;
1657 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1659 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1660 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1661 sizeof(INTERNET_ASYNC_RESULT));
1664 TRACE("<--\n");
1665 return bSuccess;
1669 /***********************************************************************
1670 * HTTP_Connect (internal)
1672 * Create http session handle
1674 * RETURNS
1675 * HINTERNET a session handle on success
1676 * NULL on failure
1679 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1680 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1681 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1683 BOOL bSuccess = FALSE;
1684 LPWININETAPPINFOA hIC = NULL;
1685 LPWININETHTTPSESSIONA lpwhs = NULL;
1686 HINTERNET handle = NULL;
1688 TRACE("-->\n");
1690 hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
1691 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1692 goto lerror;
1694 hIC->hdr.dwContext = dwContext;
1696 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1697 if (NULL == lpwhs)
1699 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1700 goto lerror;
1703 handle = WININET_AllocHandle( &lpwhs->hdr );
1704 if (NULL == handle)
1706 ERR("Failed to alloc handle\n");
1707 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1708 goto lerror;
1712 * According to my tests. The name is not resolved until a request is sent
1715 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1716 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1718 lpwhs->hdr.htype = WH_HHTTPSESSION;
1719 lpwhs->hdr.lpwhparent = &hIC->hdr;
1720 lpwhs->hdr.dwFlags = dwFlags;
1721 lpwhs->hdr.dwContext = dwContext;
1722 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1723 if(strchr(hIC->lpszProxy, ' '))
1724 FIXME("Several proxies not implemented.\n");
1725 if(hIC->lpszProxyBypass)
1726 FIXME("Proxy bypass is ignored.\n");
1728 if (NULL != lpszServerName)
1729 lpwhs->lpszServerName = WININET_strdup(lpszServerName);
1730 if (NULL != lpszUserName)
1731 lpwhs->lpszUserName = WININET_strdup(lpszUserName);
1732 lpwhs->nServerPort = nServerPort;
1734 if (hIC->lpfnStatusCB)
1736 INTERNET_ASYNC_RESULT iar;
1738 iar.dwResult = (DWORD)handle;
1739 iar.dwError = ERROR_SUCCESS;
1741 SendAsyncCallback(hIC, hInternet, dwContext,
1742 INTERNET_STATUS_HANDLE_CREATED, &iar,
1743 sizeof(INTERNET_ASYNC_RESULT));
1746 bSuccess = TRUE;
1748 lerror:
1749 if (!bSuccess && lpwhs)
1751 HeapFree(GetProcessHeap(), 0, lpwhs);
1752 WININET_FreeHandle( handle );
1753 lpwhs = NULL;
1757 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1758 * windows
1761 TRACE("%p --> %p\n", hInternet, handle);
1762 return handle;
1766 /***********************************************************************
1767 * HTTP_OpenConnection (internal)
1769 * Connect to a web server
1771 * RETURNS
1773 * TRUE on success
1774 * FALSE on failure
1776 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1778 BOOL bSuccess = FALSE;
1779 LPWININETHTTPSESSIONA lpwhs;
1780 LPWININETAPPINFOA hIC = NULL;
1782 TRACE("-->\n");
1785 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1787 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1788 goto lend;
1791 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1793 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1794 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1795 INTERNET_STATUS_CONNECTING_TO_SERVER,
1796 &(lpwhs->socketAddress),
1797 sizeof(struct sockaddr_in));
1799 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1800 SOCK_STREAM, 0))
1802 WARN("Socket creation failed\n");
1803 goto lend;
1806 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1807 sizeof(lpwhs->socketAddress)))
1809 WARN("Unable to connect to host (%s)\n", strerror(errno));
1810 goto lend;
1813 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1814 INTERNET_STATUS_CONNECTED_TO_SERVER,
1815 &(lpwhs->socketAddress),
1816 sizeof(struct sockaddr_in));
1818 bSuccess = TRUE;
1820 lend:
1821 TRACE("%d <--\n", bSuccess);
1822 return bSuccess;
1826 /***********************************************************************
1827 * HTTP_GetResponseHeaders (internal)
1829 * Read server response
1831 * RETURNS
1833 * TRUE on success
1834 * FALSE on error
1836 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1838 INT cbreaks = 0;
1839 CHAR buffer[MAX_REPLY_LEN];
1840 DWORD buflen = MAX_REPLY_LEN;
1841 BOOL bSuccess = FALSE;
1842 INT rc = 0;
1843 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1845 TRACE("-->\n");
1847 if (!NETCON_connected(&lpwhr->netConnection))
1848 goto lend;
1851 * HACK peek at the buffer
1853 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1856 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1858 buflen = MAX_REPLY_LEN;
1859 memset(buffer, 0, MAX_REPLY_LEN);
1860 if (!NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1861 goto lend;
1863 if (strncmp(buffer, "HTTP", 4) != 0)
1864 goto lend;
1866 buffer[12]='\0';
1867 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1869 /* Parse each response line */
1872 buflen = MAX_REPLY_LEN;
1873 if (NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1875 TRACE("got line %s, now interpretting\n", debugstr_a(buffer));
1876 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1877 break;
1879 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1881 else
1883 cbreaks++;
1884 if (cbreaks >= 2)
1885 break;
1887 }while(1);
1889 bSuccess = TRUE;
1891 lend:
1893 TRACE("<--\n");
1894 if (bSuccess)
1895 return rc;
1896 else
1897 return FALSE;
1901 /***********************************************************************
1902 * HTTP_InterpretHttpHeader (internal)
1904 * Parse server response
1906 * RETURNS
1908 * TRUE on success
1909 * FALSE on error
1911 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1913 LPCSTR lpsztmp;
1914 INT srclen;
1916 srclen = 0;
1918 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1919 lpszSrc++;
1921 lpsztmp = lpszSrc;
1922 while(*lpsztmp != '\0')
1924 if (*lpsztmp != ' ')
1925 srclen = lpsztmp - lpszSrc + 1;
1927 lpsztmp++;
1930 *len = min(*len, srclen);
1931 strncpy(lpszStart, lpszSrc, *len);
1932 lpszStart[*len] = '\0';
1934 return *len;
1938 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1940 CHAR *pd;
1941 BOOL bSuccess = FALSE;
1943 TRACE("\n");
1945 *field = '\0';
1946 *value = '\0';
1948 pd = strchr(buffer, ':');
1949 if (pd)
1951 *pd = '\0';
1952 if (stripSpaces(buffer, field, &fieldlen) > 0)
1954 if (stripSpaces(pd+1, value, &valuelen) > 0)
1955 bSuccess = TRUE;
1959 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1960 return bSuccess;
1964 /***********************************************************************
1965 * HTTP_GetStdHeaderIndex (internal)
1967 * Lookup field index in standard http header array
1969 * FIXME: This should be stuffed into a hash table
1971 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1973 INT index = -1;
1975 if (!strcasecmp(lpszField, "Content-Length"))
1976 index = HTTP_QUERY_CONTENT_LENGTH;
1977 else if (!strcasecmp(lpszField,"Status"))
1978 index = HTTP_QUERY_STATUS_CODE;
1979 else if (!strcasecmp(lpszField,"Content-Type"))
1980 index = HTTP_QUERY_CONTENT_TYPE;
1981 else if (!strcasecmp(lpszField,"Last-Modified"))
1982 index = HTTP_QUERY_LAST_MODIFIED;
1983 else if (!strcasecmp(lpszField,"Location"))
1984 index = HTTP_QUERY_LOCATION;
1985 else if (!strcasecmp(lpszField,"Accept"))
1986 index = HTTP_QUERY_ACCEPT;
1987 else if (!strcasecmp(lpszField,"Referer"))
1988 index = HTTP_QUERY_REFERER;
1989 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1990 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1991 else if (!strcasecmp(lpszField,"Date"))
1992 index = HTTP_QUERY_DATE;
1993 else if (!strcasecmp(lpszField,"Server"))
1994 index = HTTP_QUERY_SERVER;
1995 else if (!strcasecmp(lpszField,"Connection"))
1996 index = HTTP_QUERY_CONNECTION;
1997 else if (!strcasecmp(lpszField,"ETag"))
1998 index = HTTP_QUERY_ETAG;
1999 else if (!strcasecmp(lpszField,"Accept-Ranges"))
2000 index = HTTP_QUERY_ACCEPT_RANGES;
2001 else if (!strcasecmp(lpszField,"Expires"))
2002 index = HTTP_QUERY_EXPIRES;
2003 else if (!strcasecmp(lpszField,"Mime-Version"))
2004 index = HTTP_QUERY_MIME_VERSION;
2005 else if (!strcasecmp(lpszField,"Pragma"))
2006 index = HTTP_QUERY_PRAGMA;
2007 else if (!strcasecmp(lpszField,"Cache-Control"))
2008 index = HTTP_QUERY_CACHE_CONTROL;
2009 else if (!strcasecmp(lpszField,"Content-Length"))
2010 index = HTTP_QUERY_CONTENT_LENGTH;
2011 else if (!strcasecmp(lpszField,"User-Agent"))
2012 index = HTTP_QUERY_USER_AGENT;
2013 else if (!strcasecmp(lpszField,"Proxy-Authenticate"))
2014 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2015 else
2017 TRACE("Couldn't find %s in standard header table\n", lpszField);
2020 return index;
2024 /***********************************************************************
2025 * HTTP_ProcessHeader (internal)
2027 * Stuff header into header tables according to <dwModifier>
2031 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2033 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
2035 LPHTTPHEADERA lphttpHdr = NULL;
2036 BOOL bSuccess = FALSE;
2037 INT index;
2039 TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
2041 /* Adjust modifier flags */
2042 if (dwModifier & COALESCEFLASG)
2043 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2045 /* Try to get index into standard header array */
2046 index = HTTP_GetStdHeaderIndex(field);
2047 if (index >= 0)
2049 lphttpHdr = &lpwhr->StdHeaders[index];
2051 else /* Find or create new custom header */
2053 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2054 if (index >= 0)
2056 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2058 return FALSE;
2060 lphttpHdr = &lpwhr->pCustHeaders[index];
2062 else
2064 HTTPHEADERA hdr;
2066 hdr.lpszField = (LPSTR)field;
2067 hdr.lpszValue = (LPSTR)value;
2068 hdr.wFlags = hdr.wCount = 0;
2070 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2071 hdr.wFlags |= HDR_ISREQUEST;
2073 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2077 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2078 lphttpHdr->wFlags |= HDR_ISREQUEST;
2079 else
2080 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2082 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2084 INT slen;
2086 if (!lpwhr->StdHeaders[index].lpszField)
2088 lphttpHdr->lpszField = WININET_strdup(field);
2090 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2091 lphttpHdr->wFlags |= HDR_ISREQUEST;
2094 slen = strlen(value) + 1;
2095 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
2096 if (lphttpHdr->lpszValue)
2098 memcpy(lphttpHdr->lpszValue, value, slen);
2099 bSuccess = TRUE;
2101 else
2103 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2106 else if (lphttpHdr->lpszValue)
2108 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2110 LPSTR lpsztmp;
2111 INT len;
2113 len = strlen(value);
2115 if (len <= 0)
2117 /* if custom header delete from array */
2118 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2119 lphttpHdr->lpszValue = NULL;
2120 bSuccess = TRUE;
2122 else
2124 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2125 if (lpsztmp)
2127 lphttpHdr->lpszValue = lpsztmp;
2128 strcpy(lpsztmp, value);
2129 bSuccess = TRUE;
2131 else
2133 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2134 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2138 else if (dwModifier & COALESCEFLASG)
2140 LPSTR lpsztmp;
2141 CHAR ch = 0;
2142 INT len = 0;
2143 INT origlen = strlen(lphttpHdr->lpszValue);
2144 INT valuelen = strlen(value);
2146 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2148 ch = ',';
2149 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2151 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2153 ch = ';';
2154 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2157 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2159 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2160 if (lpsztmp)
2162 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2163 if (ch > 0)
2165 lphttpHdr->lpszValue[origlen] = ch;
2166 origlen++;
2169 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
2170 lphttpHdr->lpszValue[len] = '\0';
2171 bSuccess = TRUE;
2173 else
2175 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2176 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2180 TRACE("<-- %d\n",bSuccess);
2181 return bSuccess;
2185 /***********************************************************************
2186 * HTTP_CloseConnection (internal)
2188 * Close socket connection
2191 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
2195 LPWININETHTTPSESSIONA lpwhs = NULL;
2196 LPWININETAPPINFOA hIC = NULL;
2197 HINTERNET handle;
2199 TRACE("%p\n",lpwhr);
2201 handle = WININET_FindHandle( &lpwhr->hdr );
2202 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2203 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2205 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2206 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2208 if (NETCON_connected(&lpwhr->netConnection))
2210 NETCON_close(&lpwhr->netConnection);
2213 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2214 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2218 /***********************************************************************
2219 * HTTP_CloseHTTPRequestHandle (internal)
2221 * Deallocate request handle
2224 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
2226 int i;
2227 LPWININETHTTPSESSIONA lpwhs = NULL;
2228 LPWININETAPPINFOA hIC = NULL;
2229 HINTERNET handle;
2231 TRACE("\n");
2233 if (NETCON_connected(&lpwhr->netConnection))
2234 HTTP_CloseConnection(lpwhr);
2236 handle = WININET_FindHandle( &lpwhr->hdr );
2237 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2238 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2240 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2241 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2242 sizeof(HINTERNET));
2244 if (lpwhr->lpszPath)
2245 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2246 if (lpwhr->lpszVerb)
2247 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2248 if (lpwhr->lpszHostName)
2249 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2251 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2253 if (lpwhr->StdHeaders[i].lpszField)
2254 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2255 if (lpwhr->StdHeaders[i].lpszValue)
2256 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2259 for (i = 0; i < lpwhr->nCustHeaders; i++)
2261 if (lpwhr->pCustHeaders[i].lpszField)
2262 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2263 if (lpwhr->pCustHeaders[i].lpszValue)
2264 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2267 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2268 HeapFree(GetProcessHeap(), 0, lpwhr);
2272 /***********************************************************************
2273 * HTTP_CloseHTTPSessionHandle (internal)
2275 * Deallocate session handle
2278 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
2280 LPWININETAPPINFOA hIC = NULL;
2281 HINTERNET handle;
2283 TRACE("%p\n", lpwhs);
2285 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2287 handle = WININET_FindHandle( &lpwhs->hdr );
2288 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2289 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2290 sizeof(HINTERNET));
2292 if (lpwhs->lpszServerName)
2293 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2294 if (lpwhs->lpszUserName)
2295 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2296 HeapFree(GetProcessHeap(), 0, lpwhs);
2300 /***********************************************************************
2301 * HTTP_GetCustomHeaderIndex (internal)
2303 * Return index of custom header from header array
2306 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
2308 INT index;
2310 TRACE("%s\n", lpszField);
2312 for (index = 0; index < lpwhr->nCustHeaders; index++)
2314 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
2315 break;
2319 if (index >= lpwhr->nCustHeaders)
2320 index = -1;
2322 TRACE("Return: %d\n", index);
2323 return index;
2327 /***********************************************************************
2328 * HTTP_InsertCustomHeader (internal)
2330 * Insert header into array
2333 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
2335 INT count;
2336 LPHTTPHEADERA lph = NULL;
2337 BOOL r = FALSE;
2339 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
2340 count = lpwhr->nCustHeaders + 1;
2341 if (count > 1)
2342 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
2343 else
2344 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
2346 if (NULL != lph)
2348 lpwhr->pCustHeaders = lph;
2349 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdup(lpHdr->lpszField);
2350 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdup(lpHdr->lpszValue);
2351 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2352 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2353 lpwhr->nCustHeaders++;
2354 r = TRUE;
2356 else
2358 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2361 return r;
2365 /***********************************************************************
2366 * HTTP_DeleteCustomHeader (internal)
2368 * Delete header from array
2369 * If this function is called, the indexs may change.
2371 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index)
2373 if( lpwhr->nCustHeaders <= 0 )
2374 return FALSE;
2375 if( lpwhr->nCustHeaders >= index )
2376 return FALSE;
2377 lpwhr->nCustHeaders--;
2379 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2380 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERA) );
2381 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERA) );
2383 return TRUE;
2386 /***********************************************************************
2387 * IsHostInProxyBypassList (@)
2389 * Undocumented
2392 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2394 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
2395 return FALSE;