Allocate the correct nr of bytes for lpszCookies in HTTP_HttpOpenRequestA.
[wine.git] / dlls / wininet / http.c
blobaf4036610fff28534c1843806e68b3011b62e684
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+1));
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++;
354 szAcceptTypes[acceptTypesCount] = NULL;
356 else szAcceptTypes = 0;
358 rc = HttpOpenRequestA(hHttpSession, (LPCSTR)szVerb, (LPCSTR)szObjectName,
359 (LPCSTR)szVersion, (LPCSTR)szReferrer,
360 (LPCSTR *)szAcceptTypes, dwFlags, dwContext);
362 end:
363 if (szAcceptTypes)
365 acceptTypesCount = 0;
366 while (szAcceptTypes[acceptTypesCount])
368 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
369 acceptTypesCount++;
371 HeapFree(GetProcessHeap(), 0, szAcceptTypes);
373 if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer);
374 if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion);
375 if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName);
376 if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb);
378 return rc;
381 /***********************************************************************
382 * HTTP_Base64
384 static UINT HTTP_Base64( LPCSTR bin, LPSTR base64 )
386 UINT n = 0, x;
387 static LPSTR HTTP_Base64Enc =
388 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
390 while( bin[0] )
392 /* first 6 bits, all from bin[0] */
393 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
394 x = (bin[0] & 3) << 4;
396 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
397 if( !bin[1] )
399 base64[n++] = HTTP_Base64Enc[x];
400 base64[n++] = '=';
401 base64[n++] = '=';
402 break;
404 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
405 x = ( bin[1] & 0x0f ) << 2;
407 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
408 if( !bin[2] )
410 base64[n++] = HTTP_Base64Enc[x];
411 base64[n++] = '=';
412 break;
414 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
416 /* last 6 bits, all from bin [2] */
417 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
418 bin += 3;
420 base64[n] = 0;
421 return n;
424 /***********************************************************************
425 * HTTP_EncodeBasicAuth
427 * Encode the basic authentication string for HTTP 1.1
429 static LPSTR HTTP_EncodeBasicAuth( LPCSTR username, LPCSTR password)
431 UINT len;
432 LPSTR in, out, szBasic = "Basic ";
434 len = strlen( username ) + 1 + strlen ( password ) + 1;
435 in = HeapAlloc( GetProcessHeap(), 0, len );
436 if( !in )
437 return NULL;
439 len = strlen(szBasic) +
440 (strlen( username ) + 1 + strlen ( password ))*2 + 1 + 1;
441 out = HeapAlloc( GetProcessHeap(), 0, len );
442 if( out )
444 strcpy( in, username );
445 strcat( in, ":" );
446 strcat( in, password );
447 strcpy( out, szBasic );
448 HTTP_Base64( in, &out[strlen(out)] );
450 HeapFree( GetProcessHeap(), 0, in );
452 return out;
455 /***********************************************************************
456 * HTTP_InsertProxyAuthorization
458 * Insert the basic authorization field in the request header
460 BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQA lpwhr,
461 LPCSTR username, LPCSTR password )
463 HTTPHEADERA hdr;
464 INT index;
466 hdr.lpszField = "Proxy-Authorization";
467 hdr.lpszValue = HTTP_EncodeBasicAuth( username, password );
468 hdr.wFlags = HDR_ISREQUEST;
469 hdr.wCount = 0;
470 if( !hdr.lpszValue )
471 return FALSE;
473 TRACE("Inserting %s = %s\n",
474 debugstr_a( hdr.lpszField ), debugstr_a( hdr.lpszValue ) );
476 /* remove the old proxy authorization header */
477 index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField );
478 if( index >=0 )
479 HTTP_DeleteCustomHeader( lpwhr, index );
481 HTTP_InsertCustomHeader(lpwhr, &hdr);
482 HeapFree( GetProcessHeap(), 0, hdr.lpszValue );
484 return TRUE;
487 /***********************************************************************
488 * HTTP_DealWithProxy
490 static BOOL HTTP_DealWithProxy( LPWININETAPPINFOA hIC,
491 LPWININETHTTPSESSIONA lpwhs, LPWININETHTTPREQA lpwhr)
493 char buf[MAXHOSTNAME];
494 char proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
495 char* url, *szNul = "";
496 URL_COMPONENTSA UrlComponents;
498 memset( &UrlComponents, 0, sizeof UrlComponents );
499 UrlComponents.dwStructSize = sizeof UrlComponents;
500 UrlComponents.lpszHostName = buf;
501 UrlComponents.dwHostNameLength = MAXHOSTNAME;
503 if (strncasecmp(hIC->lpszProxy,"http://",strlen("http://")))
504 sprintf(proxy, "http://%s/", hIC->lpszProxy);
505 else
506 strcpy(proxy,hIC->lpszProxy);
507 if( !InternetCrackUrlA(proxy, 0, 0, &UrlComponents) )
508 return FALSE;
509 if( UrlComponents.dwHostNameLength == 0 )
510 return FALSE;
512 if( !lpwhr->lpszPath )
513 lpwhr->lpszPath = szNul;
514 TRACE("server='%s' path='%s'\n",
515 lpwhs->lpszServerName, lpwhr->lpszPath);
516 /* for constant 15 see above */
517 url = HeapAlloc(GetProcessHeap(), 0,
518 strlen(lpwhs->lpszServerName) + strlen(lpwhr->lpszPath) + 15);
520 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
521 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
523 sprintf(url, "http://%s:%d", lpwhs->lpszServerName,
524 lpwhs->nServerPort);
525 if( lpwhr->lpszPath[0] != '/' )
526 strcat( url, "/" );
527 strcat(url, lpwhr->lpszPath);
528 if(lpwhr->lpszPath != szNul)
529 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
530 lpwhr->lpszPath = url;
531 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
532 lpwhs->lpszServerName = WININET_strdup(UrlComponents.lpszHostName);
533 lpwhs->nServerPort = UrlComponents.nPort;
535 return TRUE;
538 /***********************************************************************
539 * HTTP_HttpOpenRequestA (internal)
541 * Open a HTTP request handle
543 * RETURNS
544 * HINTERNET a HTTP request handle on success
545 * NULL on failure
548 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
549 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
550 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
551 DWORD dwFlags, DWORD dwContext)
553 LPWININETHTTPSESSIONA lpwhs;
554 LPWININETAPPINFOA hIC = NULL;
555 LPWININETHTTPREQA lpwhr;
556 LPSTR lpszCookies;
557 LPSTR lpszUrl = NULL;
558 DWORD nCookieSize;
559 HINTERNET handle;
561 TRACE("--> \n");
563 lpwhs = (LPWININETHTTPSESSIONA) WININET_GetObject( hHttpSession );
564 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
566 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
567 return NULL;
570 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
572 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
573 if (NULL == lpwhr)
575 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
576 return NULL;
578 handle = WININET_AllocHandle( &lpwhr->hdr );
579 if (NULL == handle)
581 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
582 HeapFree( GetProcessHeap(), 0, lpwhr );
583 return NULL;
586 lpwhr->hdr.htype = WH_HHTTPREQ;
587 lpwhr->hdr.lpwhparent = &lpwhs->hdr;
588 lpwhr->hdr.dwFlags = dwFlags;
589 lpwhr->hdr.dwContext = dwContext;
590 NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE);
592 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
593 DWORD needed = 0;
594 HRESULT rc;
595 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
596 if (rc != E_POINTER)
597 needed = strlen(lpszObjectName)+1;
598 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
599 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
600 URL_ESCAPE_SPACES_ONLY);
601 if (rc)
603 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
604 strcpy(lpwhr->lpszPath,lpszObjectName);
608 if (NULL != lpszReferrer && strlen(lpszReferrer))
609 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
611 if(lpszAcceptTypes!=NULL)
613 int i;
614 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
615 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
618 if (NULL == lpszVerb)
619 lpwhr->lpszVerb = WININET_strdup("GET");
620 else if (strlen(lpszVerb))
621 lpwhr->lpszVerb = WININET_strdup(lpszVerb);
623 if (NULL != lpszReferrer && strlen(lpszReferrer))
625 char buf[MAXHOSTNAME];
626 URL_COMPONENTSA UrlComponents;
628 memset( &UrlComponents, 0, sizeof UrlComponents );
629 UrlComponents.dwStructSize = sizeof UrlComponents;
630 UrlComponents.lpszHostName = buf;
631 UrlComponents.dwHostNameLength = MAXHOSTNAME;
633 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
634 if (strlen(UrlComponents.lpszHostName))
635 lpwhr->lpszHostName = WININET_strdup(UrlComponents.lpszHostName);
636 } else {
637 lpwhr->lpszHostName = WININET_strdup(lpwhs->lpszServerName);
639 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
640 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
642 if (hIC->lpszAgent)
644 char *agent_header = HeapAlloc(GetProcessHeap(), 0, strlen(hIC->lpszAgent) + 1 + 14);
645 sprintf(agent_header, "User-Agent: %s\r\n", hIC->lpszAgent);
646 HttpAddRequestHeadersA(handle, agent_header, strlen(agent_header),
647 HTTP_ADDREQ_FLAG_ADD);
648 HeapFree(GetProcessHeap(), 0, agent_header);
651 lpszUrl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + 1 + strlen("http://"));
652 sprintf(lpszUrl, "http://%s", lpwhr->lpszHostName);
653 if (InternetGetCookieA(lpszUrl, NULL, NULL, &nCookieSize))
655 int cnt = 0;
657 lpszCookies = HeapAlloc(GetProcessHeap(), 0, nCookieSize + strlen("Cookie: ") + strlen("\r\n") + 1);
659 cnt += sprintf(lpszCookies, "Cookie: ");
660 InternetGetCookieA(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
661 cnt += nCookieSize - 1;
662 sprintf(lpszCookies + cnt, "\r\n");
664 HttpAddRequestHeadersA(handle, lpszCookies, strlen(lpszCookies),
665 HTTP_ADDREQ_FLAG_ADD);
666 HeapFree(GetProcessHeap(), 0, lpszCookies);
668 HeapFree(GetProcessHeap(), 0, lpszUrl);
672 if (hIC->lpfnStatusCB)
674 INTERNET_ASYNC_RESULT iar;
676 iar.dwResult = (DWORD)handle;
677 iar.dwError = ERROR_SUCCESS;
679 SendAsyncCallback(hIC, hHttpSession, dwContext,
680 INTERNET_STATUS_HANDLE_CREATED, &iar,
681 sizeof(INTERNET_ASYNC_RESULT));
685 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
689 * According to my tests. The name is not resolved until a request is Opened
691 SendAsyncCallback(hIC, hHttpSession, dwContext,
692 INTERNET_STATUS_RESOLVING_NAME,
693 lpwhs->lpszServerName,
694 strlen(lpwhs->lpszServerName)+1);
695 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
696 &lpwhs->phostent, &lpwhs->socketAddress))
698 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
699 return NULL;
702 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
703 INTERNET_STATUS_NAME_RESOLVED,
704 &(lpwhs->socketAddress),
705 sizeof(struct sockaddr_in));
707 TRACE("<-- %p\n", handle);
708 return handle;
712 /***********************************************************************
713 * HttpQueryInfoA (WININET.@)
715 * Queries for information about an HTTP request
717 * RETURNS
718 * TRUE on success
719 * FALSE on failure
722 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
723 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
725 LPHTTPHEADERA lphttpHdr = NULL;
726 BOOL bSuccess = FALSE;
727 LPWININETHTTPREQA lpwhr;
729 if (TRACE_ON(wininet)) {
730 #define FE(x) { x, #x }
731 static const wininet_flag_info query_flags[] = {
732 FE(HTTP_QUERY_MIME_VERSION),
733 FE(HTTP_QUERY_CONTENT_TYPE),
734 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
735 FE(HTTP_QUERY_CONTENT_ID),
736 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
737 FE(HTTP_QUERY_CONTENT_LENGTH),
738 FE(HTTP_QUERY_CONTENT_LANGUAGE),
739 FE(HTTP_QUERY_ALLOW),
740 FE(HTTP_QUERY_PUBLIC),
741 FE(HTTP_QUERY_DATE),
742 FE(HTTP_QUERY_EXPIRES),
743 FE(HTTP_QUERY_LAST_MODIFIED),
744 FE(HTTP_QUERY_MESSAGE_ID),
745 FE(HTTP_QUERY_URI),
746 FE(HTTP_QUERY_DERIVED_FROM),
747 FE(HTTP_QUERY_COST),
748 FE(HTTP_QUERY_LINK),
749 FE(HTTP_QUERY_PRAGMA),
750 FE(HTTP_QUERY_VERSION),
751 FE(HTTP_QUERY_STATUS_CODE),
752 FE(HTTP_QUERY_STATUS_TEXT),
753 FE(HTTP_QUERY_RAW_HEADERS),
754 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
755 FE(HTTP_QUERY_CONNECTION),
756 FE(HTTP_QUERY_ACCEPT),
757 FE(HTTP_QUERY_ACCEPT_CHARSET),
758 FE(HTTP_QUERY_ACCEPT_ENCODING),
759 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
760 FE(HTTP_QUERY_AUTHORIZATION),
761 FE(HTTP_QUERY_CONTENT_ENCODING),
762 FE(HTTP_QUERY_FORWARDED),
763 FE(HTTP_QUERY_FROM),
764 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
765 FE(HTTP_QUERY_LOCATION),
766 FE(HTTP_QUERY_ORIG_URI),
767 FE(HTTP_QUERY_REFERER),
768 FE(HTTP_QUERY_RETRY_AFTER),
769 FE(HTTP_QUERY_SERVER),
770 FE(HTTP_QUERY_TITLE),
771 FE(HTTP_QUERY_USER_AGENT),
772 FE(HTTP_QUERY_WWW_AUTHENTICATE),
773 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
774 FE(HTTP_QUERY_ACCEPT_RANGES),
775 FE(HTTP_QUERY_SET_COOKIE),
776 FE(HTTP_QUERY_COOKIE),
777 FE(HTTP_QUERY_REQUEST_METHOD),
778 FE(HTTP_QUERY_REFRESH),
779 FE(HTTP_QUERY_CONTENT_DISPOSITION),
780 FE(HTTP_QUERY_AGE),
781 FE(HTTP_QUERY_CACHE_CONTROL),
782 FE(HTTP_QUERY_CONTENT_BASE),
783 FE(HTTP_QUERY_CONTENT_LOCATION),
784 FE(HTTP_QUERY_CONTENT_MD5),
785 FE(HTTP_QUERY_CONTENT_RANGE),
786 FE(HTTP_QUERY_ETAG),
787 FE(HTTP_QUERY_HOST),
788 FE(HTTP_QUERY_IF_MATCH),
789 FE(HTTP_QUERY_IF_NONE_MATCH),
790 FE(HTTP_QUERY_IF_RANGE),
791 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
792 FE(HTTP_QUERY_MAX_FORWARDS),
793 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
794 FE(HTTP_QUERY_RANGE),
795 FE(HTTP_QUERY_TRANSFER_ENCODING),
796 FE(HTTP_QUERY_UPGRADE),
797 FE(HTTP_QUERY_VARY),
798 FE(HTTP_QUERY_VIA),
799 FE(HTTP_QUERY_WARNING),
800 FE(HTTP_QUERY_CUSTOM)
802 static const wininet_flag_info modifier_flags[] = {
803 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
804 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
805 FE(HTTP_QUERY_FLAG_NUMBER),
806 FE(HTTP_QUERY_FLAG_COALESCE)
808 #undef FE
809 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
810 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
811 int i;
813 TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
814 TRACE(" Attribute:");
815 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
816 if (query_flags[i].val == info) {
817 DPRINTF(" %s", query_flags[i].name);
818 break;
821 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
822 DPRINTF(" Unknown (%08lx)", info);
825 DPRINTF(" Modifier:");
826 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
827 if (modifier_flags[i].val & info_mod) {
828 DPRINTF(" %s", modifier_flags[i].name);
829 info_mod &= ~ modifier_flags[i].val;
833 if (info_mod) {
834 DPRINTF(" Unknown (%08lx)", info_mod);
836 DPRINTF("\n");
839 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
840 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
842 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
843 goto lend;
846 /* Find requested header structure */
847 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
849 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
851 if (index < 0)
852 goto lend;
854 lphttpHdr = &lpwhr->pCustHeaders[index];
856 else
858 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
860 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
862 INT i, delim, size = 0, cnt = 0;
864 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
866 /* Calculate length of custom reuqest headers */
867 for (i = 0; i < lpwhr->nCustHeaders; i++)
869 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
870 lpwhr->pCustHeaders[i].lpszValue)
872 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
873 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
877 /* Calculate the length of stadard request headers */
878 for (i = 0; i <= HTTP_QUERY_MAX; i++)
880 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
881 lpwhr->StdHeaders[i].lpszValue)
883 size += strlen(lpwhr->StdHeaders[i].lpszField) +
884 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
887 size += delim;
889 if (size + 1 > *lpdwBufferLength)
891 *lpdwBufferLength = size + 1;
892 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
893 goto lend;
896 /* Append standard request heades */
897 for (i = 0; i <= HTTP_QUERY_MAX; i++)
899 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
900 lpwhr->StdHeaders[i].lpszField &&
901 lpwhr->StdHeaders[i].lpszValue)
903 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
904 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
908 /* Append custom request heades */
909 for (i = 0; i < lpwhr->nCustHeaders; i++)
911 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
912 lpwhr->pCustHeaders[i].lpszField &&
913 lpwhr->pCustHeaders[i].lpszValue)
915 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
916 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
917 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
921 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
923 *lpdwBufferLength = cnt + delim;
924 bSuccess = TRUE;
925 goto lend;
927 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
929 lphttpHdr = &lpwhr->StdHeaders[index];
931 else
932 goto lend;
935 /* Ensure header satisifies requested attributes */
936 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
937 (~lphttpHdr->wFlags & HDR_ISREQUEST))
938 goto lend;
940 /* coalesce value to reuqested type */
941 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
943 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
944 bSuccess = TRUE;
946 TRACE(" returning number : %d\n", *(int *)lpBuffer);
948 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
950 time_t tmpTime;
951 struct tm tmpTM;
952 SYSTEMTIME *STHook;
954 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
956 tmpTM = *gmtime(&tmpTime);
957 STHook = (SYSTEMTIME *) lpBuffer;
958 if(STHook==NULL)
959 goto lend;
961 STHook->wDay = tmpTM.tm_mday;
962 STHook->wHour = tmpTM.tm_hour;
963 STHook->wMilliseconds = 0;
964 STHook->wMinute = tmpTM.tm_min;
965 STHook->wDayOfWeek = tmpTM.tm_wday;
966 STHook->wMonth = tmpTM.tm_mon + 1;
967 STHook->wSecond = tmpTM.tm_sec;
968 STHook->wYear = tmpTM.tm_year;
970 bSuccess = TRUE;
972 TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
973 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
974 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
976 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
978 if (*lpdwIndex >= lphttpHdr->wCount)
980 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
982 else
984 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
985 (*lpdwIndex)++;
988 else
990 INT len = strlen(lphttpHdr->lpszValue);
992 if (len + 1 > *lpdwBufferLength)
994 *lpdwBufferLength = len + 1;
995 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
996 goto lend;
999 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
1000 ((char*)lpBuffer)[len]=0;
1001 *lpdwBufferLength = len;
1002 bSuccess = TRUE;
1004 TRACE(" returning string : '%s'\n", debugstr_a(lpBuffer));
1007 lend:
1008 TRACE("%d <--\n", bSuccess);
1009 return bSuccess;
1012 /***********************************************************************
1013 * HttpQueryInfoW (WININET.@)
1015 * Queries for information about an HTTP request
1017 * RETURNS
1018 * TRUE on success
1019 * FALSE on failure
1022 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1023 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1025 BOOL result;
1026 DWORD charLen=*lpdwBufferLength;
1027 char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
1028 result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
1029 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1030 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1032 memcpy(lpBuffer,tempBuffer,charLen);
1034 else
1036 int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
1037 *lpdwBufferLength=nChars;
1039 HeapFree(GetProcessHeap(), 0, tempBuffer);
1040 return result;
1043 /***********************************************************************
1044 * HttpSendRequestExA (WININET.@)
1046 * Sends the specified request to the HTTP server and allows chunked
1047 * transfers
1049 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1050 LPINTERNET_BUFFERSA lpBuffersIn,
1051 LPINTERNET_BUFFERSA lpBuffersOut,
1052 DWORD dwFlags, DWORD dwContext)
1054 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1055 lpBuffersOut, dwFlags, dwContext);
1056 return FALSE;
1059 /***********************************************************************
1060 * HttpSendRequestA (WININET.@)
1062 * Sends the specified request to the HTTP server
1064 * RETURNS
1065 * TRUE on success
1066 * FALSE on failure
1069 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1070 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1072 LPWININETHTTPREQA lpwhr;
1073 LPWININETHTTPSESSIONA lpwhs = NULL;
1074 LPWININETAPPINFOA hIC = NULL;
1076 TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1077 lpszHeaders, debugstr_a(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1079 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1080 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1082 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1083 return FALSE;
1086 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1087 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1089 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1090 return FALSE;
1093 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1094 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1096 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1097 return FALSE;
1100 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1102 WORKREQUEST workRequest;
1103 struct WORKREQ_HTTPSENDREQUESTA *req;
1105 workRequest.asyncall = HTTPSENDREQUESTA;
1106 workRequest.handle = hHttpRequest;
1107 req = &workRequest.u.HttpSendRequestA;
1108 if (lpszHeaders)
1109 req->lpszHeader = WININET_strdup(lpszHeaders);
1110 else
1111 req->lpszHeader = 0;
1112 req->dwHeaderLength = dwHeaderLength;
1113 req->lpOptional = lpOptional;
1114 req->dwOptionalLength = dwOptionalLength;
1116 INTERNET_AsyncCall(&workRequest);
1118 * This is from windows.
1120 SetLastError(ERROR_IO_PENDING);
1121 return 0;
1123 else
1125 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
1126 dwHeaderLength, lpOptional, dwOptionalLength);
1130 /***********************************************************************
1131 * HttpSendRequestW (WININET.@)
1133 * Sends the specified request to the HTTP server
1135 * RETURNS
1136 * TRUE on success
1137 * FALSE on failure
1140 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1141 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1143 BOOL result;
1144 char* szHeaders=NULL;
1145 DWORD nLen=dwHeaderLength;
1146 if(lpszHeaders!=NULL)
1148 nLen=WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0,NULL,NULL);
1149 szHeaders=HeapAlloc(GetProcessHeap(),0,nLen);
1150 WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen,NULL,NULL);
1152 result=HttpSendRequestA(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1153 if(szHeaders!=NULL)
1154 HeapFree(GetProcessHeap(),0,szHeaders);
1155 return result;
1158 /***********************************************************************
1159 * HTTP_HandleRedirect (internal)
1161 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
1162 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1164 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1165 LPWININETAPPINFOA hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1166 char path[2048];
1167 HINTERNET handle;
1169 if(lpszUrl[0]=='/')
1171 /* if it's an absolute path, keep the same session info */
1172 strcpy(path,lpszUrl);
1174 else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1176 TRACE("Redirect through proxy\n");
1177 strcpy(path,lpszUrl);
1179 else
1181 URL_COMPONENTSA urlComponents;
1182 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
1183 char password[1024], extra[1024];
1184 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
1185 urlComponents.lpszScheme = protocol;
1186 urlComponents.dwSchemeLength = 32;
1187 urlComponents.lpszHostName = hostName;
1188 urlComponents.dwHostNameLength = MAXHOSTNAME;
1189 urlComponents.lpszUserName = userName;
1190 urlComponents.dwUserNameLength = 1024;
1191 urlComponents.lpszPassword = password;
1192 urlComponents.dwPasswordLength = 1024;
1193 urlComponents.lpszUrlPath = path;
1194 urlComponents.dwUrlPathLength = 2048;
1195 urlComponents.lpszExtraInfo = extra;
1196 urlComponents.dwExtraInfoLength = 1024;
1197 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
1198 return FALSE;
1200 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1201 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1203 #if 0
1205 * This upsets redirects to binary files on sourceforge.net
1206 * and gives an html page instead of the target file
1207 * Examination of the HTTP request sent by native wininet.dll
1208 * reveals that it doesn't send a referrer in that case.
1209 * Maybe there's a flag that enables this, or maybe a referrer
1210 * shouldn't be added in case of a redirect.
1213 /* consider the current host as the referrer */
1214 if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
1215 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1216 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1217 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1218 #endif
1220 if (NULL != lpwhs->lpszServerName)
1221 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1222 lpwhs->lpszServerName = WININET_strdup(hostName);
1223 if (NULL != lpwhs->lpszUserName)
1224 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1225 lpwhs->lpszUserName = WININET_strdup(userName);
1226 lpwhs->nServerPort = urlComponents.nPort;
1228 if (NULL != lpwhr->lpszHostName)
1229 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1230 lpwhr->lpszHostName=WININET_strdup(hostName);
1232 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1233 INTERNET_STATUS_RESOLVING_NAME,
1234 lpwhs->lpszServerName,
1235 strlen(lpwhs->lpszServerName)+1);
1237 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1238 &lpwhs->phostent, &lpwhs->socketAddress))
1240 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1241 return FALSE;
1244 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1245 INTERNET_STATUS_NAME_RESOLVED,
1246 &(lpwhs->socketAddress),
1247 sizeof(struct sockaddr_in));
1251 if(lpwhr->lpszPath)
1252 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1253 lpwhr->lpszPath=NULL;
1254 if (strlen(path))
1256 DWORD needed = 0;
1257 HRESULT rc;
1258 rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1259 if (rc != E_POINTER)
1260 needed = strlen(path)+1;
1261 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
1262 rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
1263 URL_ESCAPE_SPACES_ONLY);
1264 if (rc)
1266 ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
1267 strcpy(lpwhr->lpszPath,path);
1271 handle = WININET_FindHandle( &lpwhr->hdr );
1272 return HttpSendRequestA(handle, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1275 /***********************************************************************
1276 * HTTP_HttpSendRequestA (internal)
1278 * Sends the specified request to the HTTP server
1280 * RETURNS
1281 * TRUE on success
1282 * FALSE on failure
1285 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1286 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1288 INT cnt;
1289 INT i;
1290 BOOL bSuccess = FALSE;
1291 LPSTR requestString = NULL;
1292 LPSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */
1293 INT requestStringLen;
1294 INT responseLen;
1295 INT headerLength = 0;
1296 LPWININETHTTPREQA lpwhr;
1297 LPWININETHTTPSESSIONA lpwhs = NULL;
1298 LPWININETAPPINFOA hIC = NULL;
1299 BOOL loop_next = FALSE;
1300 int CustHeaderIndex;
1302 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
1304 /* Verify our tree of internet handles */
1305 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1306 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1308 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1309 return FALSE;
1312 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1313 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1315 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1316 return FALSE;
1319 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1320 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1322 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1323 return FALSE;
1326 /* Clear any error information */
1327 INTERNET_SetLastError(0);
1330 /* We must have a verb */
1331 if (NULL == lpwhr->lpszVerb)
1333 goto lend;
1336 /* if we are using optional stuff, we must add the fixed header of that option length */
1337 if (lpOptional && dwOptionalLength)
1339 char contentLengthStr[sizeof("Content-Length: ") + 20 /* int */ + 2 /* \n\r */];
1340 sprintf(contentLengthStr, "Content-Length: %li\r\n", dwOptionalLength);
1341 HttpAddRequestHeadersA(hHttpRequest, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1346 TRACE("Going to url %s %s\n", debugstr_a(lpwhr->lpszHostName), debugstr_a(lpwhr->lpszPath));
1347 loop_next = FALSE;
1349 /* If we don't have a path we set it to root */
1350 if (NULL == lpwhr->lpszPath)
1351 lpwhr->lpszPath = WININET_strdup("/");
1352 else /* remove \r and \n*/
1354 int nLen = strlen(lpwhr->lpszPath);
1355 while ((nLen > 0) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
1356 lpwhr->lpszPath[--nLen]='\0';
1358 if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
1359 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1361 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
1362 *fixurl = '/';
1363 strcpy(fixurl + 1, lpwhr->lpszPath);
1364 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1365 lpwhr->lpszPath = fixurl;
1368 /* Calculate length of request string */
1369 requestStringLen =
1370 strlen(lpwhr->lpszVerb) +
1371 strlen(lpwhr->lpszPath) +
1372 strlen(HTTPHEADER) +
1373 5; /* " \r\n\r\n" */
1375 /* add "\r\n" to end of lpszHeaders if needed */
1376 if (lpszHeaders)
1378 int len = strlen(lpszHeaders);
1380 /* Check if the string is terminated with \r\n, but not if
1381 * the string is less that 2 characters long, because then
1382 * we would be looking at memory before the beginning of
1383 * the string. Besides, if it is less than 2 characters
1384 * long, then clearly, its not terminated with \r\n.
1386 if ((len > 2) && (memcmp(lpszHeaders + (len - 2), "\r\n", 2) == 0))
1388 lpszHeaders_r_n = WININET_strdup(lpszHeaders);
1390 else
1392 TRACE("Adding \r\n to lpszHeaders.\n");
1393 lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0, strlen(lpszHeaders) + 3 );
1394 strcpy( lpszHeaders_r_n, lpszHeaders );
1395 strcpy( lpszHeaders_r_n + strlen(lpszHeaders), "\r\n" );
1399 /* Add length of passed headers */
1400 if (lpszHeaders)
1402 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders_r_n) : dwHeaderLength;
1403 requestStringLen += headerLength + 2; /* \r\n */
1407 /* if there isa proxy username and password, add it to the headers */
1408 if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) )
1410 HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword );
1413 /* Calculate length of custom request headers */
1414 for (i = 0; i < lpwhr->nCustHeaders; i++)
1416 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1418 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
1419 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
1423 /* Calculate the length of standard request headers */
1424 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1426 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1428 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
1429 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
1433 if (lpwhr->lpszHostName)
1434 requestStringLen += (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName));
1436 /* if there is optional data to send, add the length */
1437 if (lpOptional)
1439 requestStringLen += dwOptionalLength;
1440 } else {
1441 requestStringLen += 2;
1444 /* Allocate string to hold entire request */
1445 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
1446 if (NULL == requestString)
1448 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1449 goto lend;
1452 /* Build request string */
1453 cnt = sprintf(requestString, "%s %s%s",
1454 lpwhr->lpszVerb,
1455 lpwhr->lpszPath,
1456 HTTPHEADER);
1458 /* Append standard request headers */
1459 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1461 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1463 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1464 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1465 TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
1469 /* Append custom request heades */
1470 for (i = 0; i < lpwhr->nCustHeaders; i++)
1472 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1474 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1475 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1476 TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
1480 if (lpwhr->lpszHostName)
1481 cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName);
1483 /* Append passed request headers */
1484 if (lpszHeaders_r_n)
1486 strcpy(requestString + cnt, "\r\n");
1487 cnt += 2;
1488 strcpy(requestString + cnt, lpszHeaders_r_n);
1489 cnt += headerLength;
1490 /* only add \r\n if not already present */
1491 if (memcmp((requestString + cnt) - 2, "\r\n", 2) != 0)
1493 strcpy(requestString + cnt, "\r\n");
1494 cnt += 2;
1498 /* Set (header) termination string for request */
1499 if (memcmp((requestString + cnt) - 4, "\r\n\r\n", 4) != 0)
1500 { /* only add it if the request string doesn't already
1501 have the thing.. (could happen if the custom header
1502 added it */
1503 strcpy(requestString + cnt, "\r\n");
1504 cnt += 2;
1506 else
1507 requestStringLen -= 2;
1509 /* if optional data, append it */
1510 if (lpOptional)
1512 memcpy(requestString + cnt, lpOptional, dwOptionalLength);
1513 cnt += dwOptionalLength;
1514 /* we also have to decrease the expected string length by two,
1515 * since we won't be adding on those following \r\n's */
1516 requestStringLen -= 2;
1518 else
1519 { /* if there is no optional data, add on another \r\n just to be safe */
1520 /* termination for request */
1521 strcpy(requestString + cnt, "\r\n");
1522 cnt += 2;
1525 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1526 /* Send the request and store the results */
1527 if (!HTTP_OpenConnection(lpwhr))
1528 goto lend;
1530 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1531 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1533 NETCON_send(&lpwhr->netConnection, requestString, requestStringLen,
1534 0, &cnt);
1537 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1538 INTERNET_STATUS_REQUEST_SENT,
1539 &requestStringLen,sizeof(DWORD));
1541 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1542 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1544 if (cnt < 0)
1545 goto lend;
1547 responseLen = HTTP_GetResponseHeaders(lpwhr);
1548 if (responseLen)
1549 bSuccess = TRUE;
1551 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1552 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1553 sizeof(DWORD));
1555 /* process headers here. Is this right? */
1556 CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, "Set-Cookie");
1557 if (CustHeaderIndex >= 0)
1559 LPHTTPHEADERA setCookieHeader;
1560 int nPosStart = 0, nPosEnd = 0;
1562 setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1564 while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1566 LPSTR buf_cookie, cookie_name, cookie_data;
1567 LPSTR buf_url;
1568 LPSTR domain = NULL;
1569 int nEqualPos = 0;
1570 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1571 setCookieHeader->lpszValue[nPosEnd] != '\0')
1573 nPosEnd++;
1575 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1577 /* fixme: not case sensitive, strcasestr is gnu only */
1578 int nDomainPosEnd = 0;
1579 int nDomainPosStart = 0, nDomainLength = 0;
1580 LPSTR lpszDomain = strstr(&setCookieHeader->lpszValue[nPosEnd], "domain=");
1581 if (lpszDomain)
1582 { /* they have specified their own domain, lets use it */
1583 while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1584 lpszDomain[nDomainPosEnd] != '\0')
1586 nDomainPosEnd++;
1588 nDomainPosStart = strlen("domain=");
1589 nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1590 domain = HeapAlloc(GetProcessHeap(), 0, nDomainLength + 1);
1591 strncpy(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1592 domain[nDomainLength] = '\0';
1595 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1596 buf_cookie = HeapAlloc(GetProcessHeap(), 0, (nPosEnd - nPosStart) + 1);
1597 strncpy(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1598 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1599 TRACE("%s\n", buf_cookie);
1600 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1602 nEqualPos++;
1604 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1606 HeapFree(GetProcessHeap(), 0, buf_cookie);
1607 break;
1610 cookie_name = HeapAlloc(GetProcessHeap(), 0, nEqualPos + 1);
1611 strncpy(cookie_name, buf_cookie, nEqualPos);
1612 cookie_name[nEqualPos] = '\0';
1613 cookie_data = &buf_cookie[nEqualPos + 1];
1616 buf_url = HeapAlloc(GetProcessHeap(), 0, strlen((domain ? domain : lpwhr->lpszHostName)) + strlen(lpwhr->lpszPath) + 9);
1617 sprintf(buf_url, "http://%s/", (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1618 InternetSetCookieA(buf_url, cookie_name, cookie_data);
1620 HeapFree(GetProcessHeap(), 0, buf_url);
1621 HeapFree(GetProcessHeap(), 0, buf_cookie);
1622 HeapFree(GetProcessHeap(), 0, cookie_name);
1623 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1624 nPosStart = nPosEnd;
1628 while (loop_next);
1630 lend:
1632 if (requestString)
1633 HeapFree(GetProcessHeap(), 0, requestString);
1635 if (lpszHeaders)
1636 HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n);
1638 /* TODO: send notification for P3P header */
1640 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1642 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1643 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1644 (dwCode==302 || dwCode==301))
1646 char szNewLocation[2048];
1647 DWORD dwBufferSize=2048;
1648 dwIndex=0;
1649 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1651 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1652 INTERNET_STATUS_REDIRECT, szNewLocation,
1653 dwBufferSize);
1654 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1655 dwHeaderLength, lpOptional, dwOptionalLength);
1660 if (hIC->lpfnStatusCB)
1662 INTERNET_ASYNC_RESULT iar;
1664 iar.dwResult = (DWORD)bSuccess;
1665 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1667 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1668 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1669 sizeof(INTERNET_ASYNC_RESULT));
1672 TRACE("<--\n");
1673 return bSuccess;
1677 /***********************************************************************
1678 * HTTP_Connect (internal)
1680 * Create http session handle
1682 * RETURNS
1683 * HINTERNET a session handle on success
1684 * NULL on failure
1687 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1688 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1689 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1691 BOOL bSuccess = FALSE;
1692 LPWININETAPPINFOA hIC = NULL;
1693 LPWININETHTTPSESSIONA lpwhs = NULL;
1694 HINTERNET handle = NULL;
1696 TRACE("-->\n");
1698 hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
1699 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1700 goto lerror;
1702 hIC->hdr.dwContext = dwContext;
1704 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1705 if (NULL == lpwhs)
1707 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1708 goto lerror;
1711 handle = WININET_AllocHandle( &lpwhs->hdr );
1712 if (NULL == handle)
1714 ERR("Failed to alloc handle\n");
1715 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1716 goto lerror;
1720 * According to my tests. The name is not resolved until a request is sent
1723 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1724 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1726 lpwhs->hdr.htype = WH_HHTTPSESSION;
1727 lpwhs->hdr.lpwhparent = &hIC->hdr;
1728 lpwhs->hdr.dwFlags = dwFlags;
1729 lpwhs->hdr.dwContext = dwContext;
1730 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1731 if(strchr(hIC->lpszProxy, ' '))
1732 FIXME("Several proxies not implemented.\n");
1733 if(hIC->lpszProxyBypass)
1734 FIXME("Proxy bypass is ignored.\n");
1736 if (NULL != lpszServerName)
1737 lpwhs->lpszServerName = WININET_strdup(lpszServerName);
1738 if (NULL != lpszUserName)
1739 lpwhs->lpszUserName = WININET_strdup(lpszUserName);
1740 lpwhs->nServerPort = nServerPort;
1742 if (hIC->lpfnStatusCB)
1744 INTERNET_ASYNC_RESULT iar;
1746 iar.dwResult = (DWORD)handle;
1747 iar.dwError = ERROR_SUCCESS;
1749 SendAsyncCallback(hIC, hInternet, dwContext,
1750 INTERNET_STATUS_HANDLE_CREATED, &iar,
1751 sizeof(INTERNET_ASYNC_RESULT));
1754 bSuccess = TRUE;
1756 lerror:
1757 if (!bSuccess && lpwhs)
1759 HeapFree(GetProcessHeap(), 0, lpwhs);
1760 WININET_FreeHandle( handle );
1761 lpwhs = NULL;
1765 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1766 * windows
1769 TRACE("%p --> %p\n", hInternet, handle);
1770 return handle;
1774 /***********************************************************************
1775 * HTTP_OpenConnection (internal)
1777 * Connect to a web server
1779 * RETURNS
1781 * TRUE on success
1782 * FALSE on failure
1784 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1786 BOOL bSuccess = FALSE;
1787 LPWININETHTTPSESSIONA lpwhs;
1788 LPWININETAPPINFOA hIC = NULL;
1790 TRACE("-->\n");
1793 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1795 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1796 goto lend;
1799 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1801 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1802 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1803 INTERNET_STATUS_CONNECTING_TO_SERVER,
1804 &(lpwhs->socketAddress),
1805 sizeof(struct sockaddr_in));
1807 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1808 SOCK_STREAM, 0))
1810 WARN("Socket creation failed\n");
1811 goto lend;
1814 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1815 sizeof(lpwhs->socketAddress)))
1817 WARN("Unable to connect to host (%s)\n", strerror(errno));
1818 goto lend;
1821 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1822 INTERNET_STATUS_CONNECTED_TO_SERVER,
1823 &(lpwhs->socketAddress),
1824 sizeof(struct sockaddr_in));
1826 bSuccess = TRUE;
1828 lend:
1829 TRACE("%d <--\n", bSuccess);
1830 return bSuccess;
1834 /***********************************************************************
1835 * HTTP_GetResponseHeaders (internal)
1837 * Read server response
1839 * RETURNS
1841 * TRUE on success
1842 * FALSE on error
1844 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1846 INT cbreaks = 0;
1847 CHAR buffer[MAX_REPLY_LEN];
1848 DWORD buflen = MAX_REPLY_LEN;
1849 BOOL bSuccess = FALSE;
1850 INT rc = 0;
1851 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1853 TRACE("-->\n");
1855 if (!NETCON_connected(&lpwhr->netConnection))
1856 goto lend;
1859 * HACK peek at the buffer
1861 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1864 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1866 buflen = MAX_REPLY_LEN;
1867 memset(buffer, 0, MAX_REPLY_LEN);
1868 if (!NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1869 goto lend;
1871 if (strncmp(buffer, "HTTP", 4) != 0)
1872 goto lend;
1874 buffer[12]='\0';
1875 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1877 /* Parse each response line */
1880 buflen = MAX_REPLY_LEN;
1881 if (NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1883 TRACE("got line %s, now interpretting\n", debugstr_a(buffer));
1884 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1885 break;
1887 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1889 else
1891 cbreaks++;
1892 if (cbreaks >= 2)
1893 break;
1895 }while(1);
1897 bSuccess = TRUE;
1899 lend:
1901 TRACE("<--\n");
1902 if (bSuccess)
1903 return rc;
1904 else
1905 return FALSE;
1909 /***********************************************************************
1910 * HTTP_InterpretHttpHeader (internal)
1912 * Parse server response
1914 * RETURNS
1916 * TRUE on success
1917 * FALSE on error
1919 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1921 LPCSTR lpsztmp;
1922 INT srclen;
1924 srclen = 0;
1926 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1927 lpszSrc++;
1929 lpsztmp = lpszSrc;
1930 while(*lpsztmp != '\0')
1932 if (*lpsztmp != ' ')
1933 srclen = lpsztmp - lpszSrc + 1;
1935 lpsztmp++;
1938 *len = min(*len, srclen);
1939 strncpy(lpszStart, lpszSrc, *len);
1940 lpszStart[*len] = '\0';
1942 return *len;
1946 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1948 CHAR *pd;
1949 BOOL bSuccess = FALSE;
1951 TRACE("\n");
1953 *field = '\0';
1954 *value = '\0';
1956 pd = strchr(buffer, ':');
1957 if (pd)
1959 *pd = '\0';
1960 if (stripSpaces(buffer, field, &fieldlen) > 0)
1962 if (stripSpaces(pd+1, value, &valuelen) > 0)
1963 bSuccess = TRUE;
1967 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1968 return bSuccess;
1972 /***********************************************************************
1973 * HTTP_GetStdHeaderIndex (internal)
1975 * Lookup field index in standard http header array
1977 * FIXME: This should be stuffed into a hash table
1979 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1981 INT index = -1;
1983 if (!strcasecmp(lpszField, "Content-Length"))
1984 index = HTTP_QUERY_CONTENT_LENGTH;
1985 else if (!strcasecmp(lpszField,"Status"))
1986 index = HTTP_QUERY_STATUS_CODE;
1987 else if (!strcasecmp(lpszField,"Content-Type"))
1988 index = HTTP_QUERY_CONTENT_TYPE;
1989 else if (!strcasecmp(lpszField,"Last-Modified"))
1990 index = HTTP_QUERY_LAST_MODIFIED;
1991 else if (!strcasecmp(lpszField,"Location"))
1992 index = HTTP_QUERY_LOCATION;
1993 else if (!strcasecmp(lpszField,"Accept"))
1994 index = HTTP_QUERY_ACCEPT;
1995 else if (!strcasecmp(lpszField,"Referer"))
1996 index = HTTP_QUERY_REFERER;
1997 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1998 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1999 else if (!strcasecmp(lpszField,"Date"))
2000 index = HTTP_QUERY_DATE;
2001 else if (!strcasecmp(lpszField,"Server"))
2002 index = HTTP_QUERY_SERVER;
2003 else if (!strcasecmp(lpszField,"Connection"))
2004 index = HTTP_QUERY_CONNECTION;
2005 else if (!strcasecmp(lpszField,"ETag"))
2006 index = HTTP_QUERY_ETAG;
2007 else if (!strcasecmp(lpszField,"Accept-Ranges"))
2008 index = HTTP_QUERY_ACCEPT_RANGES;
2009 else if (!strcasecmp(lpszField,"Expires"))
2010 index = HTTP_QUERY_EXPIRES;
2011 else if (!strcasecmp(lpszField,"Mime-Version"))
2012 index = HTTP_QUERY_MIME_VERSION;
2013 else if (!strcasecmp(lpszField,"Pragma"))
2014 index = HTTP_QUERY_PRAGMA;
2015 else if (!strcasecmp(lpszField,"Cache-Control"))
2016 index = HTTP_QUERY_CACHE_CONTROL;
2017 else if (!strcasecmp(lpszField,"Content-Length"))
2018 index = HTTP_QUERY_CONTENT_LENGTH;
2019 else if (!strcasecmp(lpszField,"User-Agent"))
2020 index = HTTP_QUERY_USER_AGENT;
2021 else if (!strcasecmp(lpszField,"Proxy-Authenticate"))
2022 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2023 else
2025 TRACE("Couldn't find %s in standard header table\n", lpszField);
2028 return index;
2032 /***********************************************************************
2033 * HTTP_ProcessHeader (internal)
2035 * Stuff header into header tables according to <dwModifier>
2039 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2041 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
2043 LPHTTPHEADERA lphttpHdr = NULL;
2044 BOOL bSuccess = FALSE;
2045 INT index;
2047 TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
2049 /* Adjust modifier flags */
2050 if (dwModifier & COALESCEFLASG)
2051 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2053 /* Try to get index into standard header array */
2054 index = HTTP_GetStdHeaderIndex(field);
2055 if (index >= 0)
2057 lphttpHdr = &lpwhr->StdHeaders[index];
2059 else /* Find or create new custom header */
2061 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2062 if (index >= 0)
2064 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2066 return FALSE;
2068 lphttpHdr = &lpwhr->pCustHeaders[index];
2070 else
2072 HTTPHEADERA hdr;
2074 hdr.lpszField = (LPSTR)field;
2075 hdr.lpszValue = (LPSTR)value;
2076 hdr.wFlags = hdr.wCount = 0;
2078 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2079 hdr.wFlags |= HDR_ISREQUEST;
2081 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2085 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2086 lphttpHdr->wFlags |= HDR_ISREQUEST;
2087 else
2088 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2090 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2092 INT slen;
2094 if (!lpwhr->StdHeaders[index].lpszField)
2096 lphttpHdr->lpszField = WININET_strdup(field);
2098 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2099 lphttpHdr->wFlags |= HDR_ISREQUEST;
2102 slen = strlen(value) + 1;
2103 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
2104 if (lphttpHdr->lpszValue)
2106 memcpy(lphttpHdr->lpszValue, value, slen);
2107 bSuccess = TRUE;
2109 else
2111 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2114 else if (lphttpHdr->lpszValue)
2116 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2118 LPSTR lpsztmp;
2119 INT len;
2121 len = strlen(value);
2123 if (len <= 0)
2125 /* if custom header delete from array */
2126 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2127 lphttpHdr->lpszValue = NULL;
2128 bSuccess = TRUE;
2130 else
2132 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2133 if (lpsztmp)
2135 lphttpHdr->lpszValue = lpsztmp;
2136 strcpy(lpsztmp, value);
2137 bSuccess = TRUE;
2139 else
2141 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2142 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2146 else if (dwModifier & COALESCEFLASG)
2148 LPSTR lpsztmp;
2149 CHAR ch = 0;
2150 INT len = 0;
2151 INT origlen = strlen(lphttpHdr->lpszValue);
2152 INT valuelen = strlen(value);
2154 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2156 ch = ',';
2157 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2159 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2161 ch = ';';
2162 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2165 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2167 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2168 if (lpsztmp)
2170 lphttpHdr->lpszValue = lpsztmp;
2171 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2172 if (ch > 0)
2174 lphttpHdr->lpszValue[origlen] = ch;
2175 origlen++;
2178 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
2179 lphttpHdr->lpszValue[len] = '\0';
2180 bSuccess = TRUE;
2182 else
2184 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2185 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2189 TRACE("<-- %d\n",bSuccess);
2190 return bSuccess;
2194 /***********************************************************************
2195 * HTTP_CloseConnection (internal)
2197 * Close socket connection
2200 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
2204 LPWININETHTTPSESSIONA lpwhs = NULL;
2205 LPWININETAPPINFOA hIC = NULL;
2206 HINTERNET handle;
2208 TRACE("%p\n",lpwhr);
2210 handle = WININET_FindHandle( &lpwhr->hdr );
2211 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2212 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2214 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2215 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2217 if (NETCON_connected(&lpwhr->netConnection))
2219 NETCON_close(&lpwhr->netConnection);
2222 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2223 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2227 /***********************************************************************
2228 * HTTP_CloseHTTPRequestHandle (internal)
2230 * Deallocate request handle
2233 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
2235 int i;
2236 LPWININETHTTPSESSIONA lpwhs = NULL;
2237 LPWININETAPPINFOA hIC = NULL;
2238 HINTERNET handle;
2240 TRACE("\n");
2242 if (NETCON_connected(&lpwhr->netConnection))
2243 HTTP_CloseConnection(lpwhr);
2245 handle = WININET_FindHandle( &lpwhr->hdr );
2246 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2247 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2249 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2250 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2251 sizeof(HINTERNET));
2253 if (lpwhr->lpszPath)
2254 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2255 if (lpwhr->lpszVerb)
2256 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2257 if (lpwhr->lpszHostName)
2258 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2260 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2262 if (lpwhr->StdHeaders[i].lpszField)
2263 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2264 if (lpwhr->StdHeaders[i].lpszValue)
2265 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2268 for (i = 0; i < lpwhr->nCustHeaders; i++)
2270 if (lpwhr->pCustHeaders[i].lpszField)
2271 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2272 if (lpwhr->pCustHeaders[i].lpszValue)
2273 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2276 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2277 HeapFree(GetProcessHeap(), 0, lpwhr);
2281 /***********************************************************************
2282 * HTTP_CloseHTTPSessionHandle (internal)
2284 * Deallocate session handle
2287 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
2289 LPWININETAPPINFOA hIC = NULL;
2290 HINTERNET handle;
2292 TRACE("%p\n", lpwhs);
2294 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
2296 handle = WININET_FindHandle( &lpwhs->hdr );
2297 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2298 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2299 sizeof(HINTERNET));
2301 if (lpwhs->lpszServerName)
2302 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2303 if (lpwhs->lpszUserName)
2304 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2305 HeapFree(GetProcessHeap(), 0, lpwhs);
2309 /***********************************************************************
2310 * HTTP_GetCustomHeaderIndex (internal)
2312 * Return index of custom header from header array
2315 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
2317 INT index;
2319 TRACE("%s\n", lpszField);
2321 for (index = 0; index < lpwhr->nCustHeaders; index++)
2323 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
2324 break;
2328 if (index >= lpwhr->nCustHeaders)
2329 index = -1;
2331 TRACE("Return: %d\n", index);
2332 return index;
2336 /***********************************************************************
2337 * HTTP_InsertCustomHeader (internal)
2339 * Insert header into array
2342 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
2344 INT count;
2345 LPHTTPHEADERA lph = NULL;
2346 BOOL r = FALSE;
2348 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
2349 count = lpwhr->nCustHeaders + 1;
2350 if (count > 1)
2351 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
2352 else
2353 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
2355 if (NULL != lph)
2357 lpwhr->pCustHeaders = lph;
2358 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdup(lpHdr->lpszField);
2359 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdup(lpHdr->lpszValue);
2360 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2361 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2362 lpwhr->nCustHeaders++;
2363 r = TRUE;
2365 else
2367 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2370 return r;
2374 /***********************************************************************
2375 * HTTP_DeleteCustomHeader (internal)
2377 * Delete header from array
2378 * If this function is called, the indexs may change.
2380 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index)
2382 if( lpwhr->nCustHeaders <= 0 )
2383 return FALSE;
2384 if( lpwhr->nCustHeaders >= index )
2385 return FALSE;
2386 lpwhr->nCustHeaders--;
2388 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2389 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERA) );
2390 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERA) );
2392 return TRUE;
2395 /***********************************************************************
2396 * IsHostInProxyBypassList (@)
2398 * Undocumented
2401 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2403 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
2404 return FALSE;