Added stub for WINNLS32EnableIME.
[wine/hacks.git] / dlls / wininet / http.c
blobf9cab891ef004dc876146eb039ef9d413b2c3166
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 LPWININETAPPINFOW 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 = (LPWININETAPPINFOW) 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( LPCWSTR bin, LPWSTR 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 LPWSTR HTTP_EncodeBasicAuth( LPCWSTR username, LPCWSTR password)
431 UINT len;
432 LPWSTR in, out;
433 WCHAR szBasic[] = {'B','a','s','i','c',' ',0};
434 WCHAR szColon[] = {':',0};
436 len = lstrlenW( username ) + 1 + lstrlenW ( password ) + 1;
437 in = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
438 if( !in )
439 return NULL;
441 len = lstrlenW(szBasic) +
442 (lstrlenW( username ) + 1 + lstrlenW ( password ))*2 + 1 + 1;
443 out = HeapAlloc( GetProcessHeap(), 0, len );
444 if( out )
446 lstrcpyW( in, username );
447 lstrcatW( in, szColon );
448 lstrcatW( in, password );
449 lstrcpyW( out, szBasic );
450 HTTP_Base64( in, &out[strlenW(out)] );
452 HeapFree( GetProcessHeap(), 0, in );
454 return out;
457 /***********************************************************************
458 * HTTP_InsertProxyAuthorization
460 * Insert the basic authorization field in the request header
462 BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQA lpwhr,
463 LPCWSTR username, LPCWSTR password )
465 HTTPHEADERA hdr;
466 INT index, len;
467 LPWSTR authW;
469 authW = HTTP_EncodeBasicAuth( username, password );
471 len = WideCharToMultiByte( CP_ACP, 0, authW, -1, NULL, 0, NULL, NULL);
472 hdr.lpszValue = HeapAlloc( GetProcessHeap(), 0, len );
473 WideCharToMultiByte( CP_ACP, 0, authW, -1, hdr.lpszValue, len, NULL, NULL);
475 hdr.lpszField = "Proxy-Authorization";
476 hdr.wFlags = HDR_ISREQUEST;
477 hdr.wCount = 0;
478 if( !hdr.lpszValue )
479 return FALSE;
481 TRACE("Inserting %s = %s\n",
482 debugstr_a( hdr.lpszField ), debugstr_a( hdr.lpszValue ) );
484 /* remove the old proxy authorization header */
485 index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField );
486 if( index >=0 )
487 HTTP_DeleteCustomHeader( lpwhr, index );
489 HTTP_InsertCustomHeader(lpwhr, &hdr);
490 HeapFree( GetProcessHeap(), 0, hdr.lpszValue );
491 HeapFree( GetProcessHeap(), 0, authW );
493 return TRUE;
496 /***********************************************************************
497 * HTTP_DealWithProxy
499 static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
500 LPWININETHTTPSESSIONA lpwhs, LPWININETHTTPREQA lpwhr)
502 char buf[MAXHOSTNAME];
503 char proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
504 char* url, *szNul = "";
505 URL_COMPONENTSA UrlComponents;
507 memset( &UrlComponents, 0, sizeof UrlComponents );
508 UrlComponents.dwStructSize = sizeof UrlComponents;
509 UrlComponents.lpszHostName = buf;
510 UrlComponents.dwHostNameLength = MAXHOSTNAME;
512 WideCharToMultiByte(CP_ACP, 0, hIC->lpszProxy, -1, buf, sizeof buf, NULL, NULL);
513 if (strncasecmp(buf,"http://",strlen("http://")))
514 sprintf(proxy, "http://%s/", buf);
515 else
516 strcpy(proxy,buf);
517 if( !InternetCrackUrlA(proxy, 0, 0, &UrlComponents) )
518 return FALSE;
519 if( UrlComponents.dwHostNameLength == 0 )
520 return FALSE;
522 if( !lpwhr->lpszPath )
523 lpwhr->lpszPath = szNul;
524 TRACE("server='%s' path='%s'\n",
525 lpwhs->lpszServerName, lpwhr->lpszPath);
526 /* for constant 15 see above */
527 url = HeapAlloc(GetProcessHeap(), 0,
528 strlen(lpwhs->lpszServerName) + strlen(lpwhr->lpszPath) + 15);
530 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
531 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
533 sprintf(url, "http://%s:%d", lpwhs->lpszServerName,
534 lpwhs->nServerPort);
535 if( lpwhr->lpszPath[0] != '/' )
536 strcat( url, "/" );
537 strcat(url, lpwhr->lpszPath);
538 if(lpwhr->lpszPath != szNul)
539 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
540 lpwhr->lpszPath = url;
541 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
542 lpwhs->lpszServerName = WININET_strdup(UrlComponents.lpszHostName);
543 lpwhs->nServerPort = UrlComponents.nPort;
545 return TRUE;
548 /***********************************************************************
549 * HTTP_HttpOpenRequestA (internal)
551 * Open a HTTP request handle
553 * RETURNS
554 * HINTERNET a HTTP request handle on success
555 * NULL on failure
558 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
559 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
560 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
561 DWORD dwFlags, DWORD dwContext)
563 LPWININETHTTPSESSIONA lpwhs;
564 LPWININETAPPINFOW hIC = NULL;
565 LPWININETHTTPREQA lpwhr;
566 LPSTR lpszCookies;
567 LPSTR lpszUrl = NULL;
568 DWORD nCookieSize;
569 HINTERNET handle;
571 TRACE("--> \n");
573 lpwhs = (LPWININETHTTPSESSIONA) WININET_GetObject( hHttpSession );
574 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
576 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
577 return NULL;
580 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
582 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
583 if (NULL == lpwhr)
585 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
586 return NULL;
588 handle = WININET_AllocHandle( &lpwhr->hdr );
589 if (NULL == handle)
591 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
592 HeapFree( GetProcessHeap(), 0, lpwhr );
593 return NULL;
596 lpwhr->hdr.htype = WH_HHTTPREQ;
597 lpwhr->hdr.lpwhparent = &lpwhs->hdr;
598 lpwhr->hdr.dwFlags = dwFlags;
599 lpwhr->hdr.dwContext = dwContext;
600 NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE);
602 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
603 DWORD needed = 0;
604 HRESULT rc;
605 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
606 if (rc != E_POINTER)
607 needed = strlen(lpszObjectName)+1;
608 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
609 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
610 URL_ESCAPE_SPACES_ONLY);
611 if (rc)
613 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
614 strcpy(lpwhr->lpszPath,lpszObjectName);
618 if (NULL != lpszReferrer && strlen(lpszReferrer))
619 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
621 if(lpszAcceptTypes!=NULL)
623 int i;
624 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
625 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
628 if (NULL == lpszVerb)
629 lpwhr->lpszVerb = WININET_strdup("GET");
630 else if (strlen(lpszVerb))
631 lpwhr->lpszVerb = WININET_strdup(lpszVerb);
633 if (NULL != lpszReferrer && strlen(lpszReferrer))
635 char buf[MAXHOSTNAME];
636 URL_COMPONENTSA UrlComponents;
638 memset( &UrlComponents, 0, sizeof UrlComponents );
639 UrlComponents.dwStructSize = sizeof UrlComponents;
640 UrlComponents.lpszHostName = buf;
641 UrlComponents.dwHostNameLength = MAXHOSTNAME;
643 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
644 if (strlen(UrlComponents.lpszHostName))
645 lpwhr->lpszHostName = WININET_strdup(UrlComponents.lpszHostName);
646 } else {
647 lpwhr->lpszHostName = WININET_strdup(lpwhs->lpszServerName);
649 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
650 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
652 if (hIC->lpszAgent)
654 int len = WideCharToMultiByte(CP_ACP, 0, hIC->lpszAgent, -1, NULL, 0, NULL, NULL );
655 char *agent_header, *user_agent = "User-Agent: ";
657 agent_header = HeapAlloc( GetProcessHeap(), 0,
658 strlen(user_agent) + len + 3 );
659 strcpy(agent_header, user_agent);
660 WideCharToMultiByte(CP_ACP, 0, hIC->lpszAgent, -1,
661 agent_header+strlen(user_agent), len, NULL, NULL );
662 strcat(agent_header, "\r\n");
664 HttpAddRequestHeadersA(handle, agent_header, strlen(agent_header),
665 HTTP_ADDREQ_FLAG_ADD);
666 HeapFree(GetProcessHeap(), 0, agent_header);
669 lpszUrl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + 1 + strlen("http://"));
670 sprintf(lpszUrl, "http://%s", lpwhr->lpszHostName);
671 if (InternetGetCookieA(lpszUrl, NULL, NULL, &nCookieSize))
673 int cnt = 0;
675 lpszCookies = HeapAlloc(GetProcessHeap(), 0, nCookieSize + strlen("Cookie: ") + strlen("\r\n") + 1);
677 cnt += sprintf(lpszCookies, "Cookie: ");
678 InternetGetCookieA(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
679 cnt += nCookieSize - 1;
680 sprintf(lpszCookies + cnt, "\r\n");
682 HttpAddRequestHeadersA(handle, lpszCookies, strlen(lpszCookies),
683 HTTP_ADDREQ_FLAG_ADD);
684 HeapFree(GetProcessHeap(), 0, lpszCookies);
686 HeapFree(GetProcessHeap(), 0, lpszUrl);
690 if (hIC->lpfnStatusCB)
692 INTERNET_ASYNC_RESULT iar;
694 iar.dwResult = (DWORD)handle;
695 iar.dwError = ERROR_SUCCESS;
697 SendAsyncCallback(hIC, hHttpSession, dwContext,
698 INTERNET_STATUS_HANDLE_CREATED, &iar,
699 sizeof(INTERNET_ASYNC_RESULT));
703 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
707 * According to my tests. The name is not resolved until a request is Opened
709 SendAsyncCallback(hIC, hHttpSession, dwContext,
710 INTERNET_STATUS_RESOLVING_NAME,
711 lpwhs->lpszServerName,
712 strlen(lpwhs->lpszServerName)+1);
713 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
714 &lpwhs->phostent, &lpwhs->socketAddress))
716 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
717 return NULL;
720 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
721 INTERNET_STATUS_NAME_RESOLVED,
722 &(lpwhs->socketAddress),
723 sizeof(struct sockaddr_in));
725 TRACE("<-- %p\n", handle);
726 return handle;
730 /***********************************************************************
731 * HttpQueryInfoA (WININET.@)
733 * Queries for information about an HTTP request
735 * RETURNS
736 * TRUE on success
737 * FALSE on failure
740 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
741 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
743 LPHTTPHEADERA lphttpHdr = NULL;
744 BOOL bSuccess = FALSE;
745 LPWININETHTTPREQA lpwhr;
747 if (TRACE_ON(wininet)) {
748 #define FE(x) { x, #x }
749 static const wininet_flag_info query_flags[] = {
750 FE(HTTP_QUERY_MIME_VERSION),
751 FE(HTTP_QUERY_CONTENT_TYPE),
752 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
753 FE(HTTP_QUERY_CONTENT_ID),
754 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
755 FE(HTTP_QUERY_CONTENT_LENGTH),
756 FE(HTTP_QUERY_CONTENT_LANGUAGE),
757 FE(HTTP_QUERY_ALLOW),
758 FE(HTTP_QUERY_PUBLIC),
759 FE(HTTP_QUERY_DATE),
760 FE(HTTP_QUERY_EXPIRES),
761 FE(HTTP_QUERY_LAST_MODIFIED),
762 FE(HTTP_QUERY_MESSAGE_ID),
763 FE(HTTP_QUERY_URI),
764 FE(HTTP_QUERY_DERIVED_FROM),
765 FE(HTTP_QUERY_COST),
766 FE(HTTP_QUERY_LINK),
767 FE(HTTP_QUERY_PRAGMA),
768 FE(HTTP_QUERY_VERSION),
769 FE(HTTP_QUERY_STATUS_CODE),
770 FE(HTTP_QUERY_STATUS_TEXT),
771 FE(HTTP_QUERY_RAW_HEADERS),
772 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
773 FE(HTTP_QUERY_CONNECTION),
774 FE(HTTP_QUERY_ACCEPT),
775 FE(HTTP_QUERY_ACCEPT_CHARSET),
776 FE(HTTP_QUERY_ACCEPT_ENCODING),
777 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
778 FE(HTTP_QUERY_AUTHORIZATION),
779 FE(HTTP_QUERY_CONTENT_ENCODING),
780 FE(HTTP_QUERY_FORWARDED),
781 FE(HTTP_QUERY_FROM),
782 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
783 FE(HTTP_QUERY_LOCATION),
784 FE(HTTP_QUERY_ORIG_URI),
785 FE(HTTP_QUERY_REFERER),
786 FE(HTTP_QUERY_RETRY_AFTER),
787 FE(HTTP_QUERY_SERVER),
788 FE(HTTP_QUERY_TITLE),
789 FE(HTTP_QUERY_USER_AGENT),
790 FE(HTTP_QUERY_WWW_AUTHENTICATE),
791 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
792 FE(HTTP_QUERY_ACCEPT_RANGES),
793 FE(HTTP_QUERY_SET_COOKIE),
794 FE(HTTP_QUERY_COOKIE),
795 FE(HTTP_QUERY_REQUEST_METHOD),
796 FE(HTTP_QUERY_REFRESH),
797 FE(HTTP_QUERY_CONTENT_DISPOSITION),
798 FE(HTTP_QUERY_AGE),
799 FE(HTTP_QUERY_CACHE_CONTROL),
800 FE(HTTP_QUERY_CONTENT_BASE),
801 FE(HTTP_QUERY_CONTENT_LOCATION),
802 FE(HTTP_QUERY_CONTENT_MD5),
803 FE(HTTP_QUERY_CONTENT_RANGE),
804 FE(HTTP_QUERY_ETAG),
805 FE(HTTP_QUERY_HOST),
806 FE(HTTP_QUERY_IF_MATCH),
807 FE(HTTP_QUERY_IF_NONE_MATCH),
808 FE(HTTP_QUERY_IF_RANGE),
809 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
810 FE(HTTP_QUERY_MAX_FORWARDS),
811 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
812 FE(HTTP_QUERY_RANGE),
813 FE(HTTP_QUERY_TRANSFER_ENCODING),
814 FE(HTTP_QUERY_UPGRADE),
815 FE(HTTP_QUERY_VARY),
816 FE(HTTP_QUERY_VIA),
817 FE(HTTP_QUERY_WARNING),
818 FE(HTTP_QUERY_CUSTOM)
820 static const wininet_flag_info modifier_flags[] = {
821 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
822 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
823 FE(HTTP_QUERY_FLAG_NUMBER),
824 FE(HTTP_QUERY_FLAG_COALESCE)
826 #undef FE
827 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
828 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
829 int i;
831 TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
832 TRACE(" Attribute:");
833 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
834 if (query_flags[i].val == info) {
835 DPRINTF(" %s", query_flags[i].name);
836 break;
839 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
840 DPRINTF(" Unknown (%08lx)", info);
843 DPRINTF(" Modifier:");
844 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
845 if (modifier_flags[i].val & info_mod) {
846 DPRINTF(" %s", modifier_flags[i].name);
847 info_mod &= ~ modifier_flags[i].val;
851 if (info_mod) {
852 DPRINTF(" Unknown (%08lx)", info_mod);
854 DPRINTF("\n");
857 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
858 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
860 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
861 goto lend;
864 /* Find requested header structure */
865 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
867 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
869 if (index < 0)
870 goto lend;
872 lphttpHdr = &lpwhr->pCustHeaders[index];
874 else
876 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
878 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
880 INT i, delim, size = 0, cnt = 0;
882 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
884 /* Calculate length of custom reuqest headers */
885 for (i = 0; i < lpwhr->nCustHeaders; i++)
887 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
888 lpwhr->pCustHeaders[i].lpszValue)
890 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
891 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
895 /* Calculate the length of stadard request headers */
896 for (i = 0; i <= HTTP_QUERY_MAX; i++)
898 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
899 lpwhr->StdHeaders[i].lpszValue)
901 size += strlen(lpwhr->StdHeaders[i].lpszField) +
902 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
905 size += delim;
907 if (size + 1 > *lpdwBufferLength)
909 *lpdwBufferLength = size + 1;
910 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
911 goto lend;
914 /* Append standard request heades */
915 for (i = 0; i <= HTTP_QUERY_MAX; i++)
917 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
918 lpwhr->StdHeaders[i].lpszField &&
919 lpwhr->StdHeaders[i].lpszValue)
921 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
922 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
926 /* Append custom request heades */
927 for (i = 0; i < lpwhr->nCustHeaders; i++)
929 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
930 lpwhr->pCustHeaders[i].lpszField &&
931 lpwhr->pCustHeaders[i].lpszValue)
933 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
934 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
935 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
939 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
941 *lpdwBufferLength = cnt + delim;
942 bSuccess = TRUE;
943 goto lend;
945 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
947 lphttpHdr = &lpwhr->StdHeaders[index];
949 else
950 goto lend;
953 /* Ensure header satisifies requested attributes */
954 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
955 (~lphttpHdr->wFlags & HDR_ISREQUEST))
956 goto lend;
958 /* coalesce value to reuqested type */
959 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
961 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
962 bSuccess = TRUE;
964 TRACE(" returning number : %d\n", *(int *)lpBuffer);
966 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
968 time_t tmpTime;
969 struct tm tmpTM;
970 SYSTEMTIME *STHook;
972 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
974 tmpTM = *gmtime(&tmpTime);
975 STHook = (SYSTEMTIME *) lpBuffer;
976 if(STHook==NULL)
977 goto lend;
979 STHook->wDay = tmpTM.tm_mday;
980 STHook->wHour = tmpTM.tm_hour;
981 STHook->wMilliseconds = 0;
982 STHook->wMinute = tmpTM.tm_min;
983 STHook->wDayOfWeek = tmpTM.tm_wday;
984 STHook->wMonth = tmpTM.tm_mon + 1;
985 STHook->wSecond = tmpTM.tm_sec;
986 STHook->wYear = tmpTM.tm_year;
988 bSuccess = TRUE;
990 TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
991 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
992 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
994 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
996 if (*lpdwIndex >= lphttpHdr->wCount)
998 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
1000 else
1002 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
1003 (*lpdwIndex)++;
1006 else
1008 INT len = strlen(lphttpHdr->lpszValue);
1010 if (len + 1 > *lpdwBufferLength)
1012 *lpdwBufferLength = len + 1;
1013 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1014 goto lend;
1017 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
1018 ((char*)lpBuffer)[len]=0;
1019 *lpdwBufferLength = len;
1020 bSuccess = TRUE;
1022 TRACE(" returning string : '%s'\n", debugstr_a(lpBuffer));
1025 lend:
1026 TRACE("%d <--\n", bSuccess);
1027 return bSuccess;
1030 /***********************************************************************
1031 * HttpQueryInfoW (WININET.@)
1033 * Queries for information about an HTTP request
1035 * RETURNS
1036 * TRUE on success
1037 * FALSE on failure
1040 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1041 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1043 BOOL result;
1044 DWORD charLen=*lpdwBufferLength;
1045 char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
1046 result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
1047 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1048 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1050 memcpy(lpBuffer,tempBuffer,charLen);
1052 else
1054 int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
1055 *lpdwBufferLength=nChars;
1057 HeapFree(GetProcessHeap(), 0, tempBuffer);
1058 return result;
1061 /***********************************************************************
1062 * HttpSendRequestExA (WININET.@)
1064 * Sends the specified request to the HTTP server and allows chunked
1065 * transfers
1067 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1068 LPINTERNET_BUFFERSA lpBuffersIn,
1069 LPINTERNET_BUFFERSA lpBuffersOut,
1070 DWORD dwFlags, DWORD dwContext)
1072 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1073 lpBuffersOut, dwFlags, dwContext);
1074 return FALSE;
1077 /***********************************************************************
1078 * HttpSendRequestA (WININET.@)
1080 * Sends the specified request to the HTTP server
1082 * RETURNS
1083 * TRUE on success
1084 * FALSE on failure
1087 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1088 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1090 LPWININETHTTPREQA lpwhr;
1091 LPWININETHTTPSESSIONA lpwhs = NULL;
1092 LPWININETAPPINFOW hIC = NULL;
1094 TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1095 lpszHeaders, debugstr_a(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1097 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1098 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1100 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1101 return FALSE;
1104 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1105 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1107 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1108 return FALSE;
1111 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1112 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1114 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1115 return FALSE;
1118 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1120 WORKREQUEST workRequest;
1121 struct WORKREQ_HTTPSENDREQUESTA *req;
1123 workRequest.asyncall = HTTPSENDREQUESTA;
1124 workRequest.handle = hHttpRequest;
1125 req = &workRequest.u.HttpSendRequestA;
1126 if (lpszHeaders)
1127 req->lpszHeader = WININET_strdup(lpszHeaders);
1128 else
1129 req->lpszHeader = 0;
1130 req->dwHeaderLength = dwHeaderLength;
1131 req->lpOptional = lpOptional;
1132 req->dwOptionalLength = dwOptionalLength;
1134 INTERNET_AsyncCall(&workRequest);
1136 * This is from windows.
1138 SetLastError(ERROR_IO_PENDING);
1139 return 0;
1141 else
1143 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
1144 dwHeaderLength, lpOptional, dwOptionalLength);
1148 /***********************************************************************
1149 * HttpSendRequestW (WININET.@)
1151 * Sends the specified request to the HTTP server
1153 * RETURNS
1154 * TRUE on success
1155 * FALSE on failure
1158 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1159 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1161 BOOL result;
1162 char* szHeaders=NULL;
1163 DWORD nLen=dwHeaderLength;
1164 if(lpszHeaders!=NULL)
1166 nLen=WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0,NULL,NULL);
1167 szHeaders=HeapAlloc(GetProcessHeap(),0,nLen);
1168 WideCharToMultiByte(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen,NULL,NULL);
1170 result=HttpSendRequestA(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1171 if(szHeaders!=NULL)
1172 HeapFree(GetProcessHeap(),0,szHeaders);
1173 return result;
1176 /***********************************************************************
1177 * HTTP_HandleRedirect (internal)
1179 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
1180 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1182 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1183 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1184 char path[2048];
1185 HINTERNET handle;
1187 if(lpszUrl[0]=='/')
1189 /* if it's an absolute path, keep the same session info */
1190 strcpy(path,lpszUrl);
1192 else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1194 TRACE("Redirect through proxy\n");
1195 strcpy(path,lpszUrl);
1197 else
1199 URL_COMPONENTSA urlComponents;
1200 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
1201 char password[1024], extra[1024];
1202 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
1203 urlComponents.lpszScheme = protocol;
1204 urlComponents.dwSchemeLength = 32;
1205 urlComponents.lpszHostName = hostName;
1206 urlComponents.dwHostNameLength = MAXHOSTNAME;
1207 urlComponents.lpszUserName = userName;
1208 urlComponents.dwUserNameLength = 1024;
1209 urlComponents.lpszPassword = password;
1210 urlComponents.dwPasswordLength = 1024;
1211 urlComponents.lpszUrlPath = path;
1212 urlComponents.dwUrlPathLength = 2048;
1213 urlComponents.lpszExtraInfo = extra;
1214 urlComponents.dwExtraInfoLength = 1024;
1215 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
1216 return FALSE;
1218 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1219 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1221 #if 0
1223 * This upsets redirects to binary files on sourceforge.net
1224 * and gives an html page instead of the target file
1225 * Examination of the HTTP request sent by native wininet.dll
1226 * reveals that it doesn't send a referrer in that case.
1227 * Maybe there's a flag that enables this, or maybe a referrer
1228 * shouldn't be added in case of a redirect.
1231 /* consider the current host as the referrer */
1232 if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
1233 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1234 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1235 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1236 #endif
1238 if (NULL != lpwhs->lpszServerName)
1239 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1240 lpwhs->lpszServerName = WININET_strdup(hostName);
1241 if (NULL != lpwhs->lpszUserName)
1242 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1243 lpwhs->lpszUserName = WININET_strdup(userName);
1244 lpwhs->nServerPort = urlComponents.nPort;
1246 if (NULL != lpwhr->lpszHostName)
1247 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1248 lpwhr->lpszHostName=WININET_strdup(hostName);
1250 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1251 INTERNET_STATUS_RESOLVING_NAME,
1252 lpwhs->lpszServerName,
1253 strlen(lpwhs->lpszServerName)+1);
1255 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1256 &lpwhs->phostent, &lpwhs->socketAddress))
1258 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1259 return FALSE;
1262 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1263 INTERNET_STATUS_NAME_RESOLVED,
1264 &(lpwhs->socketAddress),
1265 sizeof(struct sockaddr_in));
1269 if(lpwhr->lpszPath)
1270 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1271 lpwhr->lpszPath=NULL;
1272 if (strlen(path))
1274 DWORD needed = 0;
1275 HRESULT rc;
1276 rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1277 if (rc != E_POINTER)
1278 needed = strlen(path)+1;
1279 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
1280 rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
1281 URL_ESCAPE_SPACES_ONLY);
1282 if (rc)
1284 ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
1285 strcpy(lpwhr->lpszPath,path);
1289 handle = WININET_FindHandle( &lpwhr->hdr );
1290 return HttpSendRequestA(handle, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1293 /***********************************************************************
1294 * HTTP_HttpSendRequestA (internal)
1296 * Sends the specified request to the HTTP server
1298 * RETURNS
1299 * TRUE on success
1300 * FALSE on failure
1303 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1304 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1306 INT cnt;
1307 INT i;
1308 BOOL bSuccess = FALSE;
1309 LPSTR requestString = NULL;
1310 LPSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */
1311 INT requestStringLen;
1312 INT responseLen;
1313 INT headerLength = 0;
1314 LPWININETHTTPREQA lpwhr;
1315 LPWININETHTTPSESSIONA lpwhs = NULL;
1316 LPWININETAPPINFOW hIC = NULL;
1317 BOOL loop_next = FALSE;
1318 int CustHeaderIndex;
1320 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
1322 /* Verify our tree of internet handles */
1323 lpwhr = (LPWININETHTTPREQA) WININET_GetObject( hHttpRequest );
1324 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1326 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1327 return FALSE;
1330 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1331 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1333 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1334 return FALSE;
1337 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1338 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1340 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1341 return FALSE;
1344 /* Clear any error information */
1345 INTERNET_SetLastError(0);
1348 /* We must have a verb */
1349 if (NULL == lpwhr->lpszVerb)
1351 goto lend;
1354 /* if we are using optional stuff, we must add the fixed header of that option length */
1355 if (lpOptional && dwOptionalLength)
1357 char contentLengthStr[sizeof("Content-Length: ") + 20 /* int */ + 2 /* \n\r */];
1358 sprintf(contentLengthStr, "Content-Length: %li\r\n", dwOptionalLength);
1359 HttpAddRequestHeadersA(hHttpRequest, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1364 TRACE("Going to url %s %s\n", debugstr_a(lpwhr->lpszHostName), debugstr_a(lpwhr->lpszPath));
1365 loop_next = FALSE;
1367 /* If we don't have a path we set it to root */
1368 if (NULL == lpwhr->lpszPath)
1369 lpwhr->lpszPath = WININET_strdup("/");
1370 else /* remove \r and \n*/
1372 int nLen = strlen(lpwhr->lpszPath);
1373 while ((nLen > 0) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
1374 lpwhr->lpszPath[--nLen]='\0';
1376 if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
1377 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1379 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
1380 *fixurl = '/';
1381 strcpy(fixurl + 1, lpwhr->lpszPath);
1382 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1383 lpwhr->lpszPath = fixurl;
1386 /* Calculate length of request string */
1387 requestStringLen =
1388 strlen(lpwhr->lpszVerb) +
1389 strlen(lpwhr->lpszPath) +
1390 strlen(HTTPHEADER) +
1391 5; /* " \r\n\r\n" */
1393 /* add "\r\n" to end of lpszHeaders if needed */
1394 if (lpszHeaders)
1396 int len = strlen(lpszHeaders);
1398 /* Check if the string is terminated with \r\n, but not if
1399 * the string is less that 2 characters long, because then
1400 * we would be looking at memory before the beginning of
1401 * the string. Besides, if it is less than 2 characters
1402 * long, then clearly, its not terminated with \r\n.
1404 if ((len > 2) && (memcmp(lpszHeaders + (len - 2), "\r\n", 2) == 0))
1406 lpszHeaders_r_n = WININET_strdup(lpszHeaders);
1408 else
1410 TRACE("Adding \r\n to lpszHeaders.\n");
1411 lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0, strlen(lpszHeaders) + 3 );
1412 strcpy( lpszHeaders_r_n, lpszHeaders );
1413 strcpy( lpszHeaders_r_n + strlen(lpszHeaders), "\r\n" );
1417 /* Add length of passed headers */
1418 if (lpszHeaders)
1420 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders_r_n) : dwHeaderLength;
1421 requestStringLen += headerLength + 2; /* \r\n */
1425 /* if there isa proxy username and password, add it to the headers */
1426 if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) )
1428 HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword );
1431 /* Calculate length of custom request headers */
1432 for (i = 0; i < lpwhr->nCustHeaders; i++)
1434 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1436 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
1437 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
1441 /* Calculate the length of standard request headers */
1442 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1444 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1446 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
1447 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
1451 if (lpwhr->lpszHostName)
1452 requestStringLen += (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName));
1454 /* if there is optional data to send, add the length */
1455 if (lpOptional)
1457 requestStringLen += dwOptionalLength;
1458 } else {
1459 requestStringLen += 2;
1462 /* Allocate string to hold entire request */
1463 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
1464 if (NULL == requestString)
1466 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1467 goto lend;
1470 /* Build request string */
1471 cnt = sprintf(requestString, "%s %s%s",
1472 lpwhr->lpszVerb,
1473 lpwhr->lpszPath,
1474 HTTPHEADER);
1476 /* Append standard request headers */
1477 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1479 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1481 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1482 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1483 TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
1487 /* Append custom request heades */
1488 for (i = 0; i < lpwhr->nCustHeaders; i++)
1490 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1492 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1493 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1494 TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
1498 if (lpwhr->lpszHostName)
1499 cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName);
1501 /* Append passed request headers */
1502 if (lpszHeaders_r_n)
1504 strcpy(requestString + cnt, "\r\n");
1505 cnt += 2;
1506 strcpy(requestString + cnt, lpszHeaders_r_n);
1507 cnt += headerLength;
1508 /* only add \r\n if not already present */
1509 if (memcmp((requestString + cnt) - 2, "\r\n", 2) != 0)
1511 strcpy(requestString + cnt, "\r\n");
1512 cnt += 2;
1516 /* Set (header) termination string for request */
1517 if (memcmp((requestString + cnt) - 4, "\r\n\r\n", 4) != 0)
1518 { /* only add it if the request string doesn't already
1519 have the thing.. (could happen if the custom header
1520 added it */
1521 strcpy(requestString + cnt, "\r\n");
1522 cnt += 2;
1524 else
1525 requestStringLen -= 2;
1527 /* if optional data, append it */
1528 if (lpOptional)
1530 memcpy(requestString + cnt, lpOptional, dwOptionalLength);
1531 cnt += dwOptionalLength;
1532 /* we also have to decrease the expected string length by two,
1533 * since we won't be adding on those following \r\n's */
1534 requestStringLen -= 2;
1536 else
1537 { /* if there is no optional data, add on another \r\n just to be safe */
1538 /* termination for request */
1539 strcpy(requestString + cnt, "\r\n");
1540 cnt += 2;
1543 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1544 /* Send the request and store the results */
1545 if (!HTTP_OpenConnection(lpwhr))
1546 goto lend;
1548 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1549 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1551 NETCON_send(&lpwhr->netConnection, requestString, requestStringLen,
1552 0, &cnt);
1555 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1556 INTERNET_STATUS_REQUEST_SENT,
1557 &requestStringLen,sizeof(DWORD));
1559 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1560 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1562 if (cnt < 0)
1563 goto lend;
1565 responseLen = HTTP_GetResponseHeaders(lpwhr);
1566 if (responseLen)
1567 bSuccess = TRUE;
1569 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1570 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1571 sizeof(DWORD));
1573 /* process headers here. Is this right? */
1574 CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, "Set-Cookie");
1575 if (CustHeaderIndex >= 0)
1577 LPHTTPHEADERA setCookieHeader;
1578 int nPosStart = 0, nPosEnd = 0;
1580 setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1582 while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1584 LPSTR buf_cookie, cookie_name, cookie_data;
1585 LPSTR buf_url;
1586 LPSTR domain = NULL;
1587 int nEqualPos = 0;
1588 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1589 setCookieHeader->lpszValue[nPosEnd] != '\0')
1591 nPosEnd++;
1593 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1595 /* fixme: not case sensitive, strcasestr is gnu only */
1596 int nDomainPosEnd = 0;
1597 int nDomainPosStart = 0, nDomainLength = 0;
1598 LPSTR lpszDomain = strstr(&setCookieHeader->lpszValue[nPosEnd], "domain=");
1599 if (lpszDomain)
1600 { /* they have specified their own domain, lets use it */
1601 while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1602 lpszDomain[nDomainPosEnd] != '\0')
1604 nDomainPosEnd++;
1606 nDomainPosStart = strlen("domain=");
1607 nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1608 domain = HeapAlloc(GetProcessHeap(), 0, nDomainLength + 1);
1609 strncpy(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1610 domain[nDomainLength] = '\0';
1613 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1614 buf_cookie = HeapAlloc(GetProcessHeap(), 0, (nPosEnd - nPosStart) + 1);
1615 strncpy(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1616 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1617 TRACE("%s\n", buf_cookie);
1618 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1620 nEqualPos++;
1622 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1624 HeapFree(GetProcessHeap(), 0, buf_cookie);
1625 break;
1628 cookie_name = HeapAlloc(GetProcessHeap(), 0, nEqualPos + 1);
1629 strncpy(cookie_name, buf_cookie, nEqualPos);
1630 cookie_name[nEqualPos] = '\0';
1631 cookie_data = &buf_cookie[nEqualPos + 1];
1634 buf_url = HeapAlloc(GetProcessHeap(), 0, strlen((domain ? domain : lpwhr->lpszHostName)) + strlen(lpwhr->lpszPath) + 9);
1635 sprintf(buf_url, "http://%s/", (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1636 InternetSetCookieA(buf_url, cookie_name, cookie_data);
1638 HeapFree(GetProcessHeap(), 0, buf_url);
1639 HeapFree(GetProcessHeap(), 0, buf_cookie);
1640 HeapFree(GetProcessHeap(), 0, cookie_name);
1641 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1642 nPosStart = nPosEnd;
1646 while (loop_next);
1648 lend:
1650 if (requestString)
1651 HeapFree(GetProcessHeap(), 0, requestString);
1653 if (lpszHeaders)
1654 HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n);
1656 /* TODO: send notification for P3P header */
1658 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1660 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1661 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1662 (dwCode==302 || dwCode==301))
1664 char szNewLocation[2048];
1665 DWORD dwBufferSize=2048;
1666 dwIndex=0;
1667 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1669 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1670 INTERNET_STATUS_REDIRECT, szNewLocation,
1671 dwBufferSize);
1672 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1673 dwHeaderLength, lpOptional, dwOptionalLength);
1678 if (hIC->lpfnStatusCB)
1680 INTERNET_ASYNC_RESULT iar;
1682 iar.dwResult = (DWORD)bSuccess;
1683 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1685 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1686 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1687 sizeof(INTERNET_ASYNC_RESULT));
1690 TRACE("<--\n");
1691 return bSuccess;
1695 /***********************************************************************
1696 * HTTP_Connect (internal)
1698 * Create http session handle
1700 * RETURNS
1701 * HINTERNET a session handle on success
1702 * NULL on failure
1705 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1706 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1707 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1709 BOOL bSuccess = FALSE;
1710 LPWININETAPPINFOW hIC = NULL;
1711 LPWININETHTTPSESSIONA lpwhs = NULL;
1712 HINTERNET handle = NULL;
1714 TRACE("-->\n");
1716 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1717 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1718 goto lerror;
1720 hIC->hdr.dwContext = dwContext;
1722 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1723 if (NULL == lpwhs)
1725 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1726 goto lerror;
1729 handle = WININET_AllocHandle( &lpwhs->hdr );
1730 if (NULL == handle)
1732 ERR("Failed to alloc handle\n");
1733 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1734 goto lerror;
1738 * According to my tests. The name is not resolved until a request is sent
1741 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1742 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1744 lpwhs->hdr.htype = WH_HHTTPSESSION;
1745 lpwhs->hdr.lpwhparent = &hIC->hdr;
1746 lpwhs->hdr.dwFlags = dwFlags;
1747 lpwhs->hdr.dwContext = dwContext;
1748 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1749 if(strchrW(hIC->lpszProxy, ' '))
1750 FIXME("Several proxies not implemented.\n");
1751 if(hIC->lpszProxyBypass)
1752 FIXME("Proxy bypass is ignored.\n");
1754 if (NULL != lpszServerName)
1755 lpwhs->lpszServerName = WININET_strdup(lpszServerName);
1756 if (NULL != lpszUserName)
1757 lpwhs->lpszUserName = WININET_strdup(lpszUserName);
1758 lpwhs->nServerPort = nServerPort;
1760 if (hIC->lpfnStatusCB)
1762 INTERNET_ASYNC_RESULT iar;
1764 iar.dwResult = (DWORD)handle;
1765 iar.dwError = ERROR_SUCCESS;
1767 SendAsyncCallback(hIC, hInternet, dwContext,
1768 INTERNET_STATUS_HANDLE_CREATED, &iar,
1769 sizeof(INTERNET_ASYNC_RESULT));
1772 bSuccess = TRUE;
1774 lerror:
1775 if (!bSuccess && lpwhs)
1777 HeapFree(GetProcessHeap(), 0, lpwhs);
1778 WININET_FreeHandle( handle );
1779 lpwhs = NULL;
1783 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1784 * windows
1787 TRACE("%p --> %p\n", hInternet, handle);
1788 return handle;
1792 /***********************************************************************
1793 * HTTP_OpenConnection (internal)
1795 * Connect to a web server
1797 * RETURNS
1799 * TRUE on success
1800 * FALSE on failure
1802 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1804 BOOL bSuccess = FALSE;
1805 LPWININETHTTPSESSIONA lpwhs;
1806 LPWININETAPPINFOW hIC = NULL;
1808 TRACE("-->\n");
1811 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1813 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1814 goto lend;
1817 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1819 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1820 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1821 INTERNET_STATUS_CONNECTING_TO_SERVER,
1822 &(lpwhs->socketAddress),
1823 sizeof(struct sockaddr_in));
1825 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1826 SOCK_STREAM, 0))
1828 WARN("Socket creation failed\n");
1829 goto lend;
1832 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1833 sizeof(lpwhs->socketAddress)))
1835 WARN("Unable to connect to host (%s)\n", strerror(errno));
1836 goto lend;
1839 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1840 INTERNET_STATUS_CONNECTED_TO_SERVER,
1841 &(lpwhs->socketAddress),
1842 sizeof(struct sockaddr_in));
1844 bSuccess = TRUE;
1846 lend:
1847 TRACE("%d <--\n", bSuccess);
1848 return bSuccess;
1852 /***********************************************************************
1853 * HTTP_GetResponseHeaders (internal)
1855 * Read server response
1857 * RETURNS
1859 * TRUE on success
1860 * FALSE on error
1862 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1864 INT cbreaks = 0;
1865 CHAR buffer[MAX_REPLY_LEN];
1866 DWORD buflen = MAX_REPLY_LEN;
1867 BOOL bSuccess = FALSE;
1868 INT rc = 0;
1869 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1871 TRACE("-->\n");
1873 if (!NETCON_connected(&lpwhr->netConnection))
1874 goto lend;
1877 * HACK peek at the buffer
1879 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1882 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1884 buflen = MAX_REPLY_LEN;
1885 memset(buffer, 0, MAX_REPLY_LEN);
1886 if (!NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1887 goto lend;
1889 if (strncmp(buffer, "HTTP", 4) != 0)
1890 goto lend;
1892 buffer[12]='\0';
1893 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1895 /* Parse each response line */
1898 buflen = MAX_REPLY_LEN;
1899 if (NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen))
1901 TRACE("got line %s, now interpretting\n", debugstr_a(buffer));
1902 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1903 break;
1905 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1907 else
1909 cbreaks++;
1910 if (cbreaks >= 2)
1911 break;
1913 }while(1);
1915 bSuccess = TRUE;
1917 lend:
1919 TRACE("<--\n");
1920 if (bSuccess)
1921 return rc;
1922 else
1923 return FALSE;
1927 /***********************************************************************
1928 * HTTP_InterpretHttpHeader (internal)
1930 * Parse server response
1932 * RETURNS
1934 * TRUE on success
1935 * FALSE on error
1937 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1939 LPCSTR lpsztmp;
1940 INT srclen;
1942 srclen = 0;
1944 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1945 lpszSrc++;
1947 lpsztmp = lpszSrc;
1948 while(*lpsztmp != '\0')
1950 if (*lpsztmp != ' ')
1951 srclen = lpsztmp - lpszSrc + 1;
1953 lpsztmp++;
1956 *len = min(*len, srclen);
1957 strncpy(lpszStart, lpszSrc, *len);
1958 lpszStart[*len] = '\0';
1960 return *len;
1964 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1966 CHAR *pd;
1967 BOOL bSuccess = FALSE;
1969 TRACE("\n");
1971 *field = '\0';
1972 *value = '\0';
1974 pd = strchr(buffer, ':');
1975 if (pd)
1977 *pd = '\0';
1978 if (stripSpaces(buffer, field, &fieldlen) > 0)
1980 if (stripSpaces(pd+1, value, &valuelen) > 0)
1981 bSuccess = TRUE;
1985 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1986 return bSuccess;
1990 /***********************************************************************
1991 * HTTP_GetStdHeaderIndex (internal)
1993 * Lookup field index in standard http header array
1995 * FIXME: This should be stuffed into a hash table
1997 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1999 INT index = -1;
2001 if (!strcasecmp(lpszField, "Content-Length"))
2002 index = HTTP_QUERY_CONTENT_LENGTH;
2003 else if (!strcasecmp(lpszField,"Status"))
2004 index = HTTP_QUERY_STATUS_CODE;
2005 else if (!strcasecmp(lpszField,"Content-Type"))
2006 index = HTTP_QUERY_CONTENT_TYPE;
2007 else if (!strcasecmp(lpszField,"Last-Modified"))
2008 index = HTTP_QUERY_LAST_MODIFIED;
2009 else if (!strcasecmp(lpszField,"Location"))
2010 index = HTTP_QUERY_LOCATION;
2011 else if (!strcasecmp(lpszField,"Accept"))
2012 index = HTTP_QUERY_ACCEPT;
2013 else if (!strcasecmp(lpszField,"Referer"))
2014 index = HTTP_QUERY_REFERER;
2015 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
2016 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
2017 else if (!strcasecmp(lpszField,"Date"))
2018 index = HTTP_QUERY_DATE;
2019 else if (!strcasecmp(lpszField,"Server"))
2020 index = HTTP_QUERY_SERVER;
2021 else if (!strcasecmp(lpszField,"Connection"))
2022 index = HTTP_QUERY_CONNECTION;
2023 else if (!strcasecmp(lpszField,"ETag"))
2024 index = HTTP_QUERY_ETAG;
2025 else if (!strcasecmp(lpszField,"Accept-Ranges"))
2026 index = HTTP_QUERY_ACCEPT_RANGES;
2027 else if (!strcasecmp(lpszField,"Expires"))
2028 index = HTTP_QUERY_EXPIRES;
2029 else if (!strcasecmp(lpszField,"Mime-Version"))
2030 index = HTTP_QUERY_MIME_VERSION;
2031 else if (!strcasecmp(lpszField,"Pragma"))
2032 index = HTTP_QUERY_PRAGMA;
2033 else if (!strcasecmp(lpszField,"Cache-Control"))
2034 index = HTTP_QUERY_CACHE_CONTROL;
2035 else if (!strcasecmp(lpszField,"Content-Length"))
2036 index = HTTP_QUERY_CONTENT_LENGTH;
2037 else if (!strcasecmp(lpszField,"User-Agent"))
2038 index = HTTP_QUERY_USER_AGENT;
2039 else if (!strcasecmp(lpszField,"Proxy-Authenticate"))
2040 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2041 else
2043 TRACE("Couldn't find %s in standard header table\n", lpszField);
2046 return index;
2050 /***********************************************************************
2051 * HTTP_ProcessHeader (internal)
2053 * Stuff header into header tables according to <dwModifier>
2057 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2059 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
2061 LPHTTPHEADERA lphttpHdr = NULL;
2062 BOOL bSuccess = FALSE;
2063 INT index;
2065 TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
2067 /* Adjust modifier flags */
2068 if (dwModifier & COALESCEFLASG)
2069 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2071 /* Try to get index into standard header array */
2072 index = HTTP_GetStdHeaderIndex(field);
2073 if (index >= 0)
2075 lphttpHdr = &lpwhr->StdHeaders[index];
2077 else /* Find or create new custom header */
2079 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2080 if (index >= 0)
2082 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2084 return FALSE;
2086 lphttpHdr = &lpwhr->pCustHeaders[index];
2088 else
2090 HTTPHEADERA hdr;
2092 hdr.lpszField = (LPSTR)field;
2093 hdr.lpszValue = (LPSTR)value;
2094 hdr.wFlags = hdr.wCount = 0;
2096 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2097 hdr.wFlags |= HDR_ISREQUEST;
2099 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2103 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2104 lphttpHdr->wFlags |= HDR_ISREQUEST;
2105 else
2106 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2108 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2110 INT slen;
2112 if (!lpwhr->StdHeaders[index].lpszField)
2114 lphttpHdr->lpszField = WININET_strdup(field);
2116 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2117 lphttpHdr->wFlags |= HDR_ISREQUEST;
2120 slen = strlen(value) + 1;
2121 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
2122 if (lphttpHdr->lpszValue)
2124 memcpy(lphttpHdr->lpszValue, value, slen);
2125 bSuccess = TRUE;
2127 else
2129 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2132 else if (lphttpHdr->lpszValue)
2134 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2136 LPSTR lpsztmp;
2137 INT len;
2139 len = strlen(value);
2141 if (len <= 0)
2143 /* if custom header delete from array */
2144 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2145 lphttpHdr->lpszValue = NULL;
2146 bSuccess = TRUE;
2148 else
2150 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2151 if (lpsztmp)
2153 lphttpHdr->lpszValue = lpsztmp;
2154 strcpy(lpsztmp, value);
2155 bSuccess = TRUE;
2157 else
2159 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2160 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2164 else if (dwModifier & COALESCEFLASG)
2166 LPSTR lpsztmp;
2167 CHAR ch = 0;
2168 INT len = 0;
2169 INT origlen = strlen(lphttpHdr->lpszValue);
2170 INT valuelen = strlen(value);
2172 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2174 ch = ',';
2175 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2177 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2179 ch = ';';
2180 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2183 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2185 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
2186 if (lpsztmp)
2188 lphttpHdr->lpszValue = lpsztmp;
2189 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2190 if (ch > 0)
2192 lphttpHdr->lpszValue[origlen] = ch;
2193 origlen++;
2196 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
2197 lphttpHdr->lpszValue[len] = '\0';
2198 bSuccess = TRUE;
2200 else
2202 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2203 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2207 TRACE("<-- %d\n",bSuccess);
2208 return bSuccess;
2212 /***********************************************************************
2213 * HTTP_CloseConnection (internal)
2215 * Close socket connection
2218 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
2222 LPWININETHTTPSESSIONA lpwhs = NULL;
2223 LPWININETAPPINFOW hIC = NULL;
2224 HINTERNET handle;
2226 TRACE("%p\n",lpwhr);
2228 handle = WININET_FindHandle( &lpwhr->hdr );
2229 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2230 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2232 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2233 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2235 if (NETCON_connected(&lpwhr->netConnection))
2237 NETCON_close(&lpwhr->netConnection);
2240 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2241 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2245 /***********************************************************************
2246 * HTTP_CloseHTTPRequestHandle (internal)
2248 * Deallocate request handle
2251 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
2253 int i;
2254 LPWININETHTTPSESSIONA lpwhs = NULL;
2255 LPWININETAPPINFOW hIC = NULL;
2256 HINTERNET handle;
2258 TRACE("\n");
2260 if (NETCON_connected(&lpwhr->netConnection))
2261 HTTP_CloseConnection(lpwhr);
2263 handle = WININET_FindHandle( &lpwhr->hdr );
2264 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
2265 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2267 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2268 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2269 sizeof(HINTERNET));
2271 if (lpwhr->lpszPath)
2272 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2273 if (lpwhr->lpszVerb)
2274 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2275 if (lpwhr->lpszHostName)
2276 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2278 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2280 if (lpwhr->StdHeaders[i].lpszField)
2281 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2282 if (lpwhr->StdHeaders[i].lpszValue)
2283 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2286 for (i = 0; i < lpwhr->nCustHeaders; i++)
2288 if (lpwhr->pCustHeaders[i].lpszField)
2289 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2290 if (lpwhr->pCustHeaders[i].lpszValue)
2291 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2294 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2295 HeapFree(GetProcessHeap(), 0, lpwhr);
2299 /***********************************************************************
2300 * HTTP_CloseHTTPSessionHandle (internal)
2302 * Deallocate session handle
2305 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
2307 LPWININETAPPINFOW hIC = NULL;
2308 HINTERNET handle;
2310 TRACE("%p\n", lpwhs);
2312 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2314 handle = WININET_FindHandle( &lpwhs->hdr );
2315 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2316 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2317 sizeof(HINTERNET));
2319 if (lpwhs->lpszServerName)
2320 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2321 if (lpwhs->lpszUserName)
2322 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2323 HeapFree(GetProcessHeap(), 0, lpwhs);
2327 /***********************************************************************
2328 * HTTP_GetCustomHeaderIndex (internal)
2330 * Return index of custom header from header array
2333 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
2335 INT index;
2337 TRACE("%s\n", lpszField);
2339 for (index = 0; index < lpwhr->nCustHeaders; index++)
2341 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
2342 break;
2346 if (index >= lpwhr->nCustHeaders)
2347 index = -1;
2349 TRACE("Return: %d\n", index);
2350 return index;
2354 /***********************************************************************
2355 * HTTP_InsertCustomHeader (internal)
2357 * Insert header into array
2360 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
2362 INT count;
2363 LPHTTPHEADERA lph = NULL;
2364 BOOL r = FALSE;
2366 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
2367 count = lpwhr->nCustHeaders + 1;
2368 if (count > 1)
2369 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
2370 else
2371 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
2373 if (NULL != lph)
2375 lpwhr->pCustHeaders = lph;
2376 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdup(lpHdr->lpszField);
2377 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdup(lpHdr->lpszValue);
2378 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2379 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2380 lpwhr->nCustHeaders++;
2381 r = TRUE;
2383 else
2385 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2388 return r;
2392 /***********************************************************************
2393 * HTTP_DeleteCustomHeader (internal)
2395 * Delete header from array
2396 * If this function is called, the indexs may change.
2398 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index)
2400 if( lpwhr->nCustHeaders <= 0 )
2401 return FALSE;
2402 if( lpwhr->nCustHeaders >= index )
2403 return FALSE;
2404 lpwhr->nCustHeaders--;
2406 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2407 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERA) );
2408 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERA) );
2410 return TRUE;
2413 /***********************************************************************
2414 * IsHostInProxyBypassList (@)
2416 * Undocumented
2419 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2421 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
2422 return FALSE;