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
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
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
49 #define NO_SHLWAPI_STREAM
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
58 const WCHAR g_szHttp[] = {' ','H','T','T','P','/','1','.','0',0 };
59 const WCHAR g_szHost[] = {'\r','\n','H','o','s','t',':',' ',0 };
60 const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0};
61 const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0};
62 const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0};
65 #define HTTPHEADER g_szHttp
66 #define HTTPHOSTHEADER g_szHost
67 #define MAXHOSTNAME 100
68 #define MAX_FIELD_VALUE_LEN 256
69 #define MAX_FIELD_LEN 256
71 #define HTTP_REFERER g_szReferer
72 #define HTTP_ACCEPT g_szAccept
73 #define HTTP_USERAGENT g_szUserAgent
75 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
76 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
77 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
78 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
79 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
80 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
81 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
84 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
85 int HTTP_WriteDataToStream(LPWININETHTTPREQW lpwhr,
86 void *Buffer, int BytesToWrite);
87 int HTTP_ReadDataFromStream(LPWININETHTTPREQW lpwhr,
88 void *Buffer, int BytesToRead);
89 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr);
90 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
91 void HTTP_CloseConnection(LPWININETHTTPREQW lpwhr);
92 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen);
93 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField);
94 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
95 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField);
96 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index);
98 /***********************************************************************
99 * HttpAddRequestHeadersW (WININET.@)
101 * Adds one or more HTTP header to the request handler
108 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
109 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
114 WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
115 BOOL bSuccess = FALSE;
116 LPWININETHTTPREQW lpwhr;
118 TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_w(lpszHeader), dwHeaderLength,
121 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
123 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
125 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
132 TRACE("copying header: %s\n", debugstr_w(lpszHeader));
133 buffer = WININET_strdupW(lpszHeader);
140 while (*lpszEnd != '\0')
142 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
147 if (*lpszEnd == '\0')
152 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
153 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
154 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
156 lpszStart = lpszEnd + 2; /* Jump over \0\n */
160 HeapFree(GetProcessHeap(), 0, buffer);
164 /***********************************************************************
165 * HttpAddRequestHeadersA (WININET.@)
167 * Adds one or more HTTP header to the request handler
174 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
175 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
181 TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_a(lpszHeader), dwHeaderLength,
184 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
185 hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
187 if( dwHeaderLength != -1 )
188 dwHeaderLength = len;
190 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
192 HeapFree( GetProcessHeap(), 0, hdr );
197 /***********************************************************************
198 * HttpEndRequestA (WININET.@)
200 * Ends an HTTP request that was started by HttpSendRequestEx
207 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
208 DWORD dwFlags, DWORD dwContext)
214 /***********************************************************************
215 * HttpEndRequestW (WININET.@)
217 * Ends an HTTP request that was started by HttpSendRequestEx
224 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
225 DWORD dwFlags, DWORD dwContext)
231 /***********************************************************************
232 * HttpOpenRequestW (WININET.@)
234 * Open a HTTP request handle
237 * HINTERNET a HTTP request handle on success
241 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
242 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
243 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
244 DWORD dwFlags, DWORD dwContext)
246 LPWININETHTTPSESSIONW lpwhs;
247 LPWININETAPPINFOW hIC = NULL;
248 HINTERNET handle = NULL;
250 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
251 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
252 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
254 if(lpszAcceptTypes!=NULL)
257 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
258 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
261 lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
262 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
264 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
267 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
270 * My tests seem to show that the windows version does not
271 * become asynchronous until after this point. And anyhow
272 * if this call was asynchronous then how would you get the
273 * necessary HINTERNET pointer returned by this function.
275 * I am leaving this here just in case I am wrong
277 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
281 WORKREQUEST workRequest;
282 struct WORKREQ_HTTPOPENREQUESTW *req;
284 workRequest.asyncall = HTTPOPENREQUESTW;
285 workRequest.handle = hHttpSession;
286 req = &workRequest.u.HttpOpenRequestW;
287 req->lpszVerb = WININET_strdupW(lpszVerb);
288 req->lpszObjectName = WININET_strdupW(lpszObjectName);
290 req->lpszVersion = WININET_strdupW(lpszVersion);
292 req->lpszVersion = 0;
294 req->lpszReferrer = WININET_strdupW(lpszReferrer);
296 req->lpszReferrer = 0;
297 req->lpszAcceptTypes = lpszAcceptTypes;
298 req->dwFlags = dwFlags;
299 req->dwContext = dwContext;
301 INTERNET_AsyncCall(&workRequest);
305 handle = HTTP_HttpOpenRequestW(hHttpSession, lpszVerb, lpszObjectName,
306 lpszVersion, lpszReferrer, lpszAcceptTypes,
309 TRACE("returning %p\n", handle);
314 /***********************************************************************
315 * HttpOpenRequestA (WININET.@)
317 * Open a HTTP request handle
320 * HINTERNET a HTTP request handle on success
324 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
325 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
326 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
327 DWORD dwFlags, DWORD dwContext)
329 LPWSTR szVerb = NULL, szObjectName = NULL;
330 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
332 INT acceptTypesCount;
333 HINTERNET rc = FALSE;
334 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
335 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
336 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
341 len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
342 szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
345 MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
350 len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
351 szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
354 MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
359 len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
360 szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
363 MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
368 len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
369 szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
372 MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
375 acceptTypesCount = 0;
378 /* find out how many there are */
379 while (lpszAcceptTypes[acceptTypesCount])
381 szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
382 acceptTypesCount = 0;
383 while (lpszAcceptTypes[acceptTypesCount])
385 len = MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
387 szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
388 if (!szAcceptTypes[acceptTypesCount] )
390 MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
391 -1, szAcceptTypes[acceptTypesCount], len );
394 szAcceptTypes[acceptTypesCount] = NULL;
396 else szAcceptTypes = 0;
398 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
399 szVersion, szReferrer,
400 (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
405 acceptTypesCount = 0;
406 while (szAcceptTypes[acceptTypesCount])
408 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
411 HeapFree(GetProcessHeap(), 0, szAcceptTypes);
413 if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer);
414 if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion);
415 if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName);
416 if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb);
421 /***********************************************************************
424 static UINT HTTP_Base64( LPCWSTR bin, LPWSTR base64 )
427 static LPSTR HTTP_Base64Enc =
428 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
432 /* first 6 bits, all from bin[0] */
433 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
434 x = (bin[0] & 3) << 4;
436 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
439 base64[n++] = HTTP_Base64Enc[x];
444 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
445 x = ( bin[1] & 0x0f ) << 2;
447 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
450 base64[n++] = HTTP_Base64Enc[x];
454 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
456 /* last 6 bits, all from bin [2] */
457 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
464 /***********************************************************************
465 * HTTP_EncodeBasicAuth
467 * Encode the basic authentication string for HTTP 1.1
469 static LPWSTR HTTP_EncodeBasicAuth( LPCWSTR username, LPCWSTR password)
473 const WCHAR szBasic[] = {'B','a','s','i','c',' ',0};
474 const WCHAR szColon[] = {':',0};
476 len = lstrlenW( username ) + 1 + lstrlenW ( password ) + 1;
477 in = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
481 len = lstrlenW(szBasic) +
482 (lstrlenW( username ) + 1 + lstrlenW ( password ))*2 + 1 + 1;
483 out = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
486 lstrcpyW( in, username );
487 lstrcatW( in, szColon );
488 lstrcatW( in, password );
489 lstrcpyW( out, szBasic );
490 HTTP_Base64( in, &out[strlenW(out)] );
492 HeapFree( GetProcessHeap(), 0, in );
497 /***********************************************************************
498 * HTTP_InsertProxyAuthorization
500 * Insert the basic authorization field in the request header
502 BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr,
503 LPCWSTR username, LPCWSTR password )
507 const WCHAR szProxyAuthorization[] = {
508 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
510 hdr.lpszValue = HTTP_EncodeBasicAuth( username, password );
511 hdr.lpszField = (WCHAR *)szProxyAuthorization;
512 hdr.wFlags = HDR_ISREQUEST;
517 TRACE("Inserting %s = %s\n",
518 debugstr_w( hdr.lpszField ), debugstr_w( hdr.lpszValue ) );
520 /* remove the old proxy authorization header */
521 index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField );
523 HTTP_DeleteCustomHeader( lpwhr, index );
525 HTTP_InsertCustomHeader(lpwhr, &hdr);
526 HeapFree( GetProcessHeap(), 0, hdr.lpszValue );
531 /***********************************************************************
534 static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
535 LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
537 WCHAR buf[MAXHOSTNAME];
538 WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
539 WCHAR* url, szNul[] = { 0 };
540 URL_COMPONENTSW UrlComponents;
541 const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }, szSlash[] = { '/',0 } ;
542 const WCHAR szFormat1[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
543 const WCHAR szFormat2[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
546 memset( &UrlComponents, 0, sizeof UrlComponents );
547 UrlComponents.dwStructSize = sizeof UrlComponents;
548 UrlComponents.lpszHostName = buf;
549 UrlComponents.dwHostNameLength = MAXHOSTNAME;
551 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
552 buf,strlenW(szHttp),szHttp,strlenW(szHttp)) )
553 sprintfW(proxy, szFormat1, hIC->lpszProxy);
556 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
558 if( UrlComponents.dwHostNameLength == 0 )
561 if( !lpwhr->lpszPath )
562 lpwhr->lpszPath = szNul;
563 TRACE("server='%s' path='%s'\n",
564 debugstr_w(lpwhs->lpszServerName), debugstr_w(lpwhr->lpszPath));
565 /* for constant 15 see above */
566 len = strlenW(lpwhs->lpszServerName) + strlenW(lpwhr->lpszPath) + 15;
567 url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
569 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
570 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
572 sprintfW(url, szFormat2, lpwhs->lpszServerName, lpwhs->nServerPort);
574 if( lpwhr->lpszPath[0] != '/' )
575 strcatW( url, szSlash );
576 strcatW(url, lpwhr->lpszPath);
577 if(lpwhr->lpszPath != szNul)
578 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
579 lpwhr->lpszPath = url;
580 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
581 lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
582 lpwhs->nServerPort = UrlComponents.nPort;
587 /***********************************************************************
588 * HTTP_HttpOpenRequestW (internal)
590 * Open a HTTP request handle
593 * HINTERNET a HTTP request handle on success
597 HINTERNET WINAPI HTTP_HttpOpenRequestW(HINTERNET hHttpSession,
598 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
599 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
600 DWORD dwFlags, DWORD dwContext)
602 LPWININETHTTPSESSIONW lpwhs;
603 LPWININETAPPINFOW hIC = NULL;
604 LPWININETHTTPREQW lpwhr;
606 LPWSTR lpszUrl = NULL;
609 const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0};
614 lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
615 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
617 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
621 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
623 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
626 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
629 handle = WININET_AllocHandle( &lpwhr->hdr );
632 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
633 HeapFree( GetProcessHeap(), 0, lpwhr );
637 lpwhr->hdr.htype = WH_HHTTPREQ;
638 lpwhr->hdr.lpwhparent = &lpwhs->hdr;
639 lpwhr->hdr.dwFlags = dwFlags;
640 lpwhr->hdr.dwContext = dwContext;
641 NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE);
643 if (NULL != lpszObjectName && strlenW(lpszObjectName)) {
647 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
649 len = strlenW(lpszObjectName)+1;
650 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
651 rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
652 URL_ESCAPE_SPACES_ONLY);
655 ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(lpszObjectName),rc);
656 strcpyW(lpwhr->lpszPath,lpszObjectName);
660 if (NULL != lpszReferrer && strlenW(lpszReferrer))
661 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
663 if(lpszAcceptTypes!=NULL)
666 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
667 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
670 if (NULL == lpszVerb)
672 const WCHAR szGet[] = {'G','E','T',0};
673 lpwhr->lpszVerb = WININET_strdupW(szGet);
675 else if (strlenW(lpszVerb))
676 lpwhr->lpszVerb = WININET_strdupW(lpszVerb);
678 if (NULL != lpszReferrer && strlenW(lpszReferrer))
680 WCHAR buf[MAXHOSTNAME];
681 URL_COMPONENTSW UrlComponents;
683 memset( &UrlComponents, 0, sizeof UrlComponents );
684 UrlComponents.dwStructSize = sizeof UrlComponents;
685 UrlComponents.lpszHostName = buf;
686 UrlComponents.dwHostNameLength = MAXHOSTNAME;
688 InternetCrackUrlW(lpszReferrer, 0, 0, &UrlComponents);
689 if (strlenW(UrlComponents.lpszHostName))
690 lpwhr->lpszHostName = WININET_strdupW(UrlComponents.lpszHostName);
692 lpwhr->lpszHostName = WININET_strdupW(lpwhs->lpszServerName);
694 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
695 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
700 const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0 };
702 len = strlenW(hIC->lpszAgent) + strlenW(user_agent);
703 agent_header = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
704 sprintfW(agent_header, user_agent, hIC->lpszAgent );
706 HttpAddRequestHeadersW(handle, agent_header, strlenW(agent_header),
707 HTTP_ADDREQ_FLAG_ADD);
708 HeapFree(GetProcessHeap(), 0, agent_header);
711 len = strlenW(lpwhr->lpszHostName) + strlenW(szUrlForm);
712 lpszUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
713 sprintfW( lpszUrl, szUrlForm, lpwhr->lpszHostName );
715 if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
718 const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
719 const WCHAR szcrlf[] = {'\r','\n',0};
721 lpszCookies = HeapAlloc(GetProcessHeap(), 0, (nCookieSize + 1 + 8)*sizeof(WCHAR));
723 cnt += sprintfW(lpszCookies, szCookie);
724 InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
725 strcatW(lpszCookies, szcrlf);
727 HttpAddRequestHeadersW(handle, lpszCookies, strlenW(lpszCookies),
728 HTTP_ADDREQ_FLAG_ADD);
729 HeapFree(GetProcessHeap(), 0, lpszCookies);
731 HeapFree(GetProcessHeap(), 0, lpszUrl);
735 if (hIC->lpfnStatusCB)
737 INTERNET_ASYNC_RESULT iar;
739 iar.dwResult = (DWORD)handle;
740 iar.dwError = ERROR_SUCCESS;
742 SendAsyncCallback(hIC, hHttpSession, dwContext,
743 INTERNET_STATUS_HANDLE_CREATED, &iar,
744 sizeof(INTERNET_ASYNC_RESULT));
748 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
752 * According to my tests. The name is not resolved until a request is Opened
754 SendAsyncCallback(hIC, hHttpSession, dwContext,
755 INTERNET_STATUS_RESOLVING_NAME,
756 lpwhs->lpszServerName,
757 strlenW(lpwhs->lpszServerName)+1);
758 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
759 &lpwhs->phostent, &lpwhs->socketAddress))
761 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
765 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
766 INTERNET_STATUS_NAME_RESOLVED,
767 &(lpwhs->socketAddress),
768 sizeof(struct sockaddr_in));
770 TRACE("<-- %p\n", handle);
775 /***********************************************************************
776 * HttpQueryInfoW (WININET.@)
778 * Queries for information about an HTTP request
785 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
786 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
788 LPHTTPHEADERW lphttpHdr = NULL;
789 BOOL bSuccess = FALSE;
790 LPWININETHTTPREQW lpwhr;
791 const WCHAR szFmt[] = { '%','s',':',' ','%','s','%','s',0 };
792 const WCHAR szcrlf[] = { '\r','\n',0 };
793 const WCHAR sznul[] = { 0 };
795 if (TRACE_ON(wininet)) {
796 #define FE(x) { x, #x }
797 static const wininet_flag_info query_flags[] = {
798 FE(HTTP_QUERY_MIME_VERSION),
799 FE(HTTP_QUERY_CONTENT_TYPE),
800 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
801 FE(HTTP_QUERY_CONTENT_ID),
802 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
803 FE(HTTP_QUERY_CONTENT_LENGTH),
804 FE(HTTP_QUERY_CONTENT_LANGUAGE),
805 FE(HTTP_QUERY_ALLOW),
806 FE(HTTP_QUERY_PUBLIC),
808 FE(HTTP_QUERY_EXPIRES),
809 FE(HTTP_QUERY_LAST_MODIFIED),
810 FE(HTTP_QUERY_MESSAGE_ID),
812 FE(HTTP_QUERY_DERIVED_FROM),
815 FE(HTTP_QUERY_PRAGMA),
816 FE(HTTP_QUERY_VERSION),
817 FE(HTTP_QUERY_STATUS_CODE),
818 FE(HTTP_QUERY_STATUS_TEXT),
819 FE(HTTP_QUERY_RAW_HEADERS),
820 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
821 FE(HTTP_QUERY_CONNECTION),
822 FE(HTTP_QUERY_ACCEPT),
823 FE(HTTP_QUERY_ACCEPT_CHARSET),
824 FE(HTTP_QUERY_ACCEPT_ENCODING),
825 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
826 FE(HTTP_QUERY_AUTHORIZATION),
827 FE(HTTP_QUERY_CONTENT_ENCODING),
828 FE(HTTP_QUERY_FORWARDED),
830 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
831 FE(HTTP_QUERY_LOCATION),
832 FE(HTTP_QUERY_ORIG_URI),
833 FE(HTTP_QUERY_REFERER),
834 FE(HTTP_QUERY_RETRY_AFTER),
835 FE(HTTP_QUERY_SERVER),
836 FE(HTTP_QUERY_TITLE),
837 FE(HTTP_QUERY_USER_AGENT),
838 FE(HTTP_QUERY_WWW_AUTHENTICATE),
839 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
840 FE(HTTP_QUERY_ACCEPT_RANGES),
841 FE(HTTP_QUERY_SET_COOKIE),
842 FE(HTTP_QUERY_COOKIE),
843 FE(HTTP_QUERY_REQUEST_METHOD),
844 FE(HTTP_QUERY_REFRESH),
845 FE(HTTP_QUERY_CONTENT_DISPOSITION),
847 FE(HTTP_QUERY_CACHE_CONTROL),
848 FE(HTTP_QUERY_CONTENT_BASE),
849 FE(HTTP_QUERY_CONTENT_LOCATION),
850 FE(HTTP_QUERY_CONTENT_MD5),
851 FE(HTTP_QUERY_CONTENT_RANGE),
854 FE(HTTP_QUERY_IF_MATCH),
855 FE(HTTP_QUERY_IF_NONE_MATCH),
856 FE(HTTP_QUERY_IF_RANGE),
857 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
858 FE(HTTP_QUERY_MAX_FORWARDS),
859 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
860 FE(HTTP_QUERY_RANGE),
861 FE(HTTP_QUERY_TRANSFER_ENCODING),
862 FE(HTTP_QUERY_UPGRADE),
865 FE(HTTP_QUERY_WARNING),
866 FE(HTTP_QUERY_CUSTOM)
868 static const wininet_flag_info modifier_flags[] = {
869 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
870 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
871 FE(HTTP_QUERY_FLAG_NUMBER),
872 FE(HTTP_QUERY_FLAG_COALESCE)
875 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
876 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
879 TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
880 TRACE(" Attribute:");
881 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
882 if (query_flags[i].val == info) {
883 DPRINTF(" %s", query_flags[i].name);
887 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
888 DPRINTF(" Unknown (%08lx)", info);
891 DPRINTF(" Modifier:");
892 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
893 if (modifier_flags[i].val & info_mod) {
894 DPRINTF(" %s", modifier_flags[i].name);
895 info_mod &= ~ modifier_flags[i].val;
900 DPRINTF(" Unknown (%08lx)", info_mod);
905 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
906 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
908 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
912 /* Find requested header structure */
913 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
915 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPWSTR)lpBuffer);
920 lphttpHdr = &lpwhr->pCustHeaders[index];
924 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
926 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
928 INT i, delim, size = 0, cnt = 0;
930 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
932 /* Calculate length of custom reuqest headers */
933 for (i = 0; i < lpwhr->nCustHeaders; i++)
935 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
936 lpwhr->pCustHeaders[i].lpszValue)
938 size += strlenW(lpwhr->pCustHeaders[i].lpszField) +
939 strlenW(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
943 /* Calculate the length of stadard request headers */
944 for (i = 0; i <= HTTP_QUERY_MAX; i++)
946 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
947 lpwhr->StdHeaders[i].lpszValue)
949 size += strlenW(lpwhr->StdHeaders[i].lpszField) +
950 strlenW(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
955 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
957 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
958 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
962 /* Append standard request heades */
963 for (i = 0; i <= HTTP_QUERY_MAX; i++)
965 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
966 lpwhr->StdHeaders[i].lpszField &&
967 lpwhr->StdHeaders[i].lpszValue)
969 cnt += sprintfW((WCHAR*)lpBuffer + cnt, szFmt,
970 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
971 index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul );
975 /* Append custom request heades */
976 for (i = 0; i < lpwhr->nCustHeaders; i++)
978 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
979 lpwhr->pCustHeaders[i].lpszField &&
980 lpwhr->pCustHeaders[i].lpszValue)
982 cnt += sprintfW((WCHAR*)lpBuffer + cnt, szFmt,
983 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
984 index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul);
988 strcpyW((WCHAR*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul);
990 *lpdwBufferLength = (cnt + delim) * sizeof(WCHAR);
994 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
996 lphttpHdr = &lpwhr->StdHeaders[index];
1002 /* Ensure header satisifies requested attributes */
1003 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
1004 (~lphttpHdr->wFlags & HDR_ISREQUEST))
1007 /* coalesce value to reuqested type */
1008 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
1010 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
1013 TRACE(" returning number : %d\n", *(int *)lpBuffer);
1015 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
1021 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
1023 tmpTM = *gmtime(&tmpTime);
1024 STHook = (SYSTEMTIME *) lpBuffer;
1028 STHook->wDay = tmpTM.tm_mday;
1029 STHook->wHour = tmpTM.tm_hour;
1030 STHook->wMilliseconds = 0;
1031 STHook->wMinute = tmpTM.tm_min;
1032 STHook->wDayOfWeek = tmpTM.tm_wday;
1033 STHook->wMonth = tmpTM.tm_mon + 1;
1034 STHook->wSecond = tmpTM.tm_sec;
1035 STHook->wYear = tmpTM.tm_year;
1039 TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
1040 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
1041 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
1043 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
1045 if (*lpdwIndex >= lphttpHdr->wCount)
1047 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
1051 /* Copy strncpyW(lpBuffer, lphttpHdr[*lpdwIndex], len); */
1057 INT len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
1059 if (len > *lpdwBufferLength)
1061 *lpdwBufferLength = len;
1062 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1066 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
1067 *lpdwBufferLength = len - sizeof(WCHAR);
1070 TRACE(" returning string : '%s'\n", debugstr_w(lpBuffer));
1074 TRACE("%d <--\n", bSuccess);
1078 /***********************************************************************
1079 * HttpQueryInfoA (WININET.@)
1081 * Queries for information about an HTTP request
1088 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1089 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1095 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1096 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1098 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
1099 lpdwBufferLength, lpdwIndex );
1102 len = (*lpdwBufferLength)*sizeof(WCHAR);
1103 bufferW = HeapAlloc( GetProcessHeap(), 0, len );
1104 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
1108 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR),
1109 lpBuffer, *lpdwBufferLength, NULL, NULL );
1110 *lpdwBufferLength = len * sizeof(WCHAR);
1112 HeapFree(GetProcessHeap(), 0, bufferW );
1117 /***********************************************************************
1118 * HttpSendRequestExA (WININET.@)
1120 * Sends the specified request to the HTTP server and allows chunked
1123 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1124 LPINTERNET_BUFFERSA lpBuffersIn,
1125 LPINTERNET_BUFFERSA lpBuffersOut,
1126 DWORD dwFlags, DWORD dwContext)
1128 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1129 lpBuffersOut, dwFlags, dwContext);
1133 /***********************************************************************
1134 * HttpSendRequestA (WININET.@)
1136 * Sends the specified request to the HTTP server
1143 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1144 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1146 LPWININETHTTPREQW lpwhr;
1147 LPWININETHTTPSESSIONW lpwhs = NULL;
1148 LPWININETAPPINFOW hIC = NULL;
1150 TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1151 lpszHeaders, debugstr_w(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1153 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1154 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1156 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1160 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1161 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1163 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1167 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1168 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1170 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1174 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1176 WORKREQUEST workRequest;
1177 struct WORKREQ_HTTPSENDREQUESTW *req;
1179 workRequest.asyncall = HTTPSENDREQUESTW;
1180 workRequest.handle = hHttpRequest;
1181 req = &workRequest.u.HttpSendRequestW;
1183 req->lpszHeader = WININET_strdupW(lpszHeaders);
1185 req->lpszHeader = 0;
1186 req->dwHeaderLength = dwHeaderLength;
1187 req->lpOptional = lpOptional;
1188 req->dwOptionalLength = dwOptionalLength;
1190 INTERNET_AsyncCall(&workRequest);
1192 * This is from windows.
1194 SetLastError(ERROR_IO_PENDING);
1199 return HTTP_HttpSendRequestW(hHttpRequest, lpszHeaders,
1200 dwHeaderLength, lpOptional, dwOptionalLength);
1204 /***********************************************************************
1205 * HttpSendRequestW (WININET.@)
1207 * Sends the specified request to the HTTP server
1214 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1215 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1218 LPWSTR szHeaders=NULL;
1219 DWORD nLen=dwHeaderLength;
1220 if(lpszHeaders!=NULL)
1222 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
1223 szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
1224 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
1226 result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1228 HeapFree(GetProcessHeap(),0,szHeaders);
1232 /***********************************************************************
1233 * HTTP_HandleRedirect (internal)
1235 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl, LPCWSTR lpszHeaders,
1236 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1238 LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1239 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1245 /* if it's an absolute path, keep the same session info */
1246 strcpyW(path,lpszUrl);
1248 else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1250 TRACE("Redirect through proxy\n");
1251 strcpyW(path,lpszUrl);
1255 URL_COMPONENTSW urlComponents;
1256 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
1257 WCHAR password[1024], extra[1024];
1258 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
1259 urlComponents.lpszScheme = protocol;
1260 urlComponents.dwSchemeLength = 32;
1261 urlComponents.lpszHostName = hostName;
1262 urlComponents.dwHostNameLength = MAXHOSTNAME;
1263 urlComponents.lpszUserName = userName;
1264 urlComponents.dwUserNameLength = 1024;
1265 urlComponents.lpszPassword = password;
1266 urlComponents.dwPasswordLength = 1024;
1267 urlComponents.lpszUrlPath = path;
1268 urlComponents.dwUrlPathLength = 2048;
1269 urlComponents.lpszExtraInfo = extra;
1270 urlComponents.dwExtraInfoLength = 1024;
1271 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
1274 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1275 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1279 * This upsets redirects to binary files on sourceforge.net
1280 * and gives an html page instead of the target file
1281 * Examination of the HTTP request sent by native wininet.dll
1282 * reveals that it doesn't send a referrer in that case.
1283 * Maybe there's a flag that enables this, or maybe a referrer
1284 * shouldn't be added in case of a redirect.
1287 /* consider the current host as the referrer */
1288 if (NULL != lpwhs->lpszServerName && strlenW(lpwhs->lpszServerName))
1289 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1290 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1291 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1294 if (NULL != lpwhs->lpszServerName)
1295 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1296 lpwhs->lpszServerName = WININET_strdupW(hostName);
1297 if (NULL != lpwhs->lpszUserName)
1298 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1299 lpwhs->lpszUserName = WININET_strdupW(userName);
1300 lpwhs->nServerPort = urlComponents.nPort;
1302 if (NULL != lpwhr->lpszHostName)
1303 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1304 lpwhr->lpszHostName=WININET_strdupW(hostName);
1306 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1307 INTERNET_STATUS_RESOLVING_NAME,
1308 lpwhs->lpszServerName,
1309 strlenW(lpwhs->lpszServerName)+1);
1311 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1312 &lpwhs->phostent, &lpwhs->socketAddress))
1314 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1318 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1319 INTERNET_STATUS_NAME_RESOLVED,
1320 &(lpwhs->socketAddress),
1321 sizeof(struct sockaddr_in));
1326 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1327 lpwhr->lpszPath=NULL;
1333 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1334 if (rc != E_POINTER)
1335 needed = strlenW(path)+1;
1336 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
1337 rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
1338 URL_ESCAPE_SPACES_ONLY);
1341 ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(path),rc);
1342 strcpyW(lpwhr->lpszPath,path);
1346 handle = WININET_FindHandle( &lpwhr->hdr );
1347 return HttpSendRequestW(handle, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1350 /***********************************************************************
1351 * HTTP_HttpSendRequestW (internal)
1353 * Sends the specified request to the HTTP server
1360 BOOL WINAPI HTTP_HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1361 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1365 BOOL bSuccess = FALSE;
1366 LPWSTR requestString = NULL;
1367 LPWSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */
1368 INT requestStringLen;
1370 INT headerLength = 0;
1371 LPWININETHTTPREQW lpwhr;
1372 LPWININETHTTPSESSIONW lpwhs = NULL;
1373 LPWININETAPPINFOW hIC = NULL;
1374 BOOL loop_next = FALSE;
1375 int CustHeaderIndex;
1377 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
1379 /* Verify our tree of internet handles */
1380 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1381 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1383 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1387 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1388 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1390 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1394 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1395 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1397 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1401 /* Clear any error information */
1402 INTERNET_SetLastError(0);
1405 /* We must have a verb */
1406 if (NULL == lpwhr->lpszVerb)
1411 /* if we are using optional stuff, we must add the fixed header of that option length */
1412 if (lpOptional && dwOptionalLength)
1414 char contentLengthStr[sizeof("Content-Length: ") + 20 /* int */ + 2 /* \n\r */];
1415 sprintf(contentLengthStr, "Content-Length: %li\r\n", dwOptionalLength);
1416 HttpAddRequestHeadersA(hHttpRequest, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1421 const WCHAR szSlash[] = { '/',0 };
1422 const WCHAR szSpace[] = { ' ',0 };
1423 const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
1424 const WCHAR szcrlf[] = {'\r','\n', 0};
1425 const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
1426 const WCHAR szSetCookie[] = {'S','e','t','-','C','o','o','k','i','e',0 };
1428 TRACE("Going to url %s %s\n", debugstr_w(lpwhr->lpszHostName), debugstr_w(lpwhr->lpszPath));
1431 /* If we don't have a path we set it to root */
1432 if (NULL == lpwhr->lpszPath)
1433 lpwhr->lpszPath = WININET_strdupW(szSlash);
1435 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1436 lpwhr->lpszPath, strlenW(szHttp), szHttp, strlenW(szHttp) )
1437 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1439 WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
1440 (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
1442 strcpyW(fixurl + 1, lpwhr->lpszPath);
1443 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1444 lpwhr->lpszPath = fixurl;
1447 /* Calculate length of request string */
1449 strlenW(lpwhr->lpszVerb) +
1450 strlenW(lpwhr->lpszPath) +
1451 strlenW(HTTPHEADER) +
1452 5; /* " \r\n\r\n" */
1454 /* add "\r\n" to end of lpszHeaders if needed */
1457 int len = strlenW(lpszHeaders);
1459 /* Check if the string is terminated with \r\n, but not if
1460 * the string is less that 2 characters long, because then
1461 * we would be looking at memory before the beginning of
1462 * the string. Besides, if it is less than 2 characters
1463 * long, then clearly, its not terminated with \r\n.
1465 if ((len > 2) && (memcmp(lpszHeaders + (len - 2), szcrlf, sizeof szcrlf) == 0))
1467 lpszHeaders_r_n = WININET_strdupW(lpszHeaders);
1471 TRACE("Adding \r\n to lpszHeaders.\n");
1472 lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0,
1473 (len + 3)*sizeof(WCHAR) );
1474 strcpyW( lpszHeaders_r_n, lpszHeaders );
1475 strcatW( lpszHeaders_r_n, szcrlf );
1479 /* Add length of passed headers */
1482 headerLength = -1 == dwHeaderLength ? strlenW(lpszHeaders_r_n) : dwHeaderLength;
1483 requestStringLen += headerLength + 2; /* \r\n */
1487 /* if there isa proxy username and password, add it to the headers */
1488 if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) )
1490 HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword );
1493 /* Calculate length of custom request headers */
1494 for (i = 0; i < lpwhr->nCustHeaders; i++)
1496 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1498 requestStringLen += strlenW(lpwhr->pCustHeaders[i].lpszField) +
1499 strlenW(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
1503 /* Calculate the length of standard request headers */
1504 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1506 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1508 requestStringLen += strlenW(lpwhr->StdHeaders[i].lpszField) +
1509 strlenW(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
1513 if (lpwhr->lpszHostName)
1514 requestStringLen += (strlenW(HTTPHOSTHEADER) + strlenW(lpwhr->lpszHostName));
1516 /* if there is optional data to send, add the length */
1519 requestStringLen += dwOptionalLength;
1522 /* Allocate string to hold entire request */
1523 requestString = HeapAlloc(GetProcessHeap(), 0, (requestStringLen + 1)*sizeof(WCHAR));
1524 if (NULL == requestString)
1526 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1530 /* Build request string */
1531 strcpyW(requestString, lpwhr->lpszVerb);
1532 strcatW(requestString, szSpace);
1533 strcatW(requestString, lpwhr->lpszPath);
1534 strcatW(requestString, HTTPHEADER );
1535 cnt = strlenW(requestString);
1537 /* Append standard request headers */
1538 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1540 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1542 const WCHAR szFmt[] = { '\r','\n','%','s',':',' ','%','s', 0};
1543 cnt += sprintfW(requestString + cnt, szFmt,
1544 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1545 TRACE("Adding header %s (%s)\n",
1546 debugstr_w(lpwhr->StdHeaders[i].lpszField),
1547 debugstr_w(lpwhr->StdHeaders[i].lpszValue));
1551 /* Append custom request heades */
1552 for (i = 0; i < lpwhr->nCustHeaders; i++)
1554 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1556 const WCHAR szFmt[] = { '\r','\n','%','s',':',' ','%','s', 0};
1557 cnt += sprintfW(requestString + cnt, szFmt,
1558 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1559 TRACE("Adding custom header %s (%s)\n",
1560 debugstr_w(lpwhr->pCustHeaders[i].lpszField),
1561 debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
1565 if (lpwhr->lpszHostName)
1567 const WCHAR szFmt[] = { '%','s','%','s',0 };
1568 cnt += sprintfW(requestString + cnt, szFmt, HTTPHOSTHEADER, lpwhr->lpszHostName);
1571 /* Append passed request headers */
1572 if (lpszHeaders_r_n)
1574 strcpyW(requestString + cnt, szcrlf);
1576 strcpyW(requestString + cnt, lpszHeaders_r_n);
1577 cnt += headerLength;
1578 /* only add \r\n if not already present */
1579 if (memcmp((requestString + cnt) - 2, szcrlf, sizeof szcrlf) != 0)
1581 strcpyW(requestString + cnt, szcrlf);
1586 /* Set (header) termination string for request */
1587 if (memcmp((requestString + cnt) - 4, sztwocrlf, sizeof sztwocrlf) != 0)
1588 { /* only add it if the request string doesn't already
1589 have the thing.. (could happen if the custom header
1591 strcpyW(requestString + cnt, szcrlf);
1595 requestStringLen -= 2;
1597 /* if optional data, append it */
1600 memcpy(requestString + cnt, lpOptional, dwOptionalLength*sizeof(WCHAR));
1601 cnt += dwOptionalLength;
1602 /* we also have to decrease the expected string length by two,
1603 * since we won't be adding on those following \r\n's */
1604 requestStringLen -= 2;
1607 { /* if there is no optional data, add on another \r\n just to be safe */
1608 /* termination for request */
1609 strcpyW(requestString + cnt, szcrlf);
1613 TRACE("(%s) len(%d)\n", debugstr_w(requestString), requestStringLen);
1614 /* Send the request and store the results */
1615 if (!HTTP_OpenConnection(lpwhr))
1618 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1619 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1621 /* send the request as ASCII */
1626 ascii_len = WideCharToMultiByte( CP_ACP, 0, requestString,
1627 requestStringLen, NULL, 0, NULL, NULL );
1628 ascii_req = HeapAlloc( GetProcessHeap(), 0, ascii_len );
1629 WideCharToMultiByte( CP_ACP, 0, requestString, requestStringLen,
1630 ascii_req, ascii_len, NULL, NULL );
1631 NETCON_send(&lpwhr->netConnection, ascii_req, ascii_len, 0, &cnt);
1632 HeapFree( GetProcessHeap(), 0, ascii_req );
1636 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1637 INTERNET_STATUS_REQUEST_SENT,
1638 &requestStringLen,sizeof(DWORD));
1640 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1641 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1646 responseLen = HTTP_GetResponseHeaders(lpwhr);
1650 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1651 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1654 /* process headers here. Is this right? */
1655 CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSetCookie);
1656 if (CustHeaderIndex >= 0)
1658 LPHTTPHEADERW setCookieHeader;
1659 int nPosStart = 0, nPosEnd = 0, len;
1660 const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0};
1662 setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1664 while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1666 LPWSTR buf_cookie, cookie_name, cookie_data;
1668 LPWSTR domain = NULL;
1670 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1671 setCookieHeader->lpszValue[nPosEnd] != '\0')
1675 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1677 /* fixme: not case sensitive, strcasestr is gnu only */
1678 int nDomainPosEnd = 0;
1679 int nDomainPosStart = 0, nDomainLength = 0;
1680 const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
1681 LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain);
1683 { /* they have specified their own domain, lets use it */
1684 while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1685 lpszDomain[nDomainPosEnd] != '\0')
1689 nDomainPosStart = strlenW(szDomain);
1690 nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1691 domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR));
1692 strncpyW(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1693 domain[nDomainLength] = '\0';
1696 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1697 buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR));
1698 strncpyW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1699 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1700 TRACE("%s\n", debugstr_w(buf_cookie));
1701 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1705 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1707 HeapFree(GetProcessHeap(), 0, buf_cookie);
1711 cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR));
1712 strncpyW(cookie_name, buf_cookie, nEqualPos);
1713 cookie_name[nEqualPos] = '\0';
1714 cookie_data = &buf_cookie[nEqualPos + 1];
1717 len = strlenW((domain ? domain : lpwhr->lpszHostName)) + strlenW(lpwhr->lpszPath) + 9;
1718 buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1719 sprintfW(buf_url, szFmt, (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1720 InternetSetCookieW(buf_url, cookie_name, cookie_data);
1722 HeapFree(GetProcessHeap(), 0, buf_url);
1723 HeapFree(GetProcessHeap(), 0, buf_cookie);
1724 HeapFree(GetProcessHeap(), 0, cookie_name);
1725 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1726 nPosStart = nPosEnd;
1735 HeapFree(GetProcessHeap(), 0, requestString);
1738 HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n);
1740 /* TODO: send notification for P3P header */
1742 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1744 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1745 if(HttpQueryInfoW(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1746 (dwCode==302 || dwCode==301))
1748 WCHAR szNewLocation[2048];
1749 DWORD dwBufferSize=2048;
1751 if(HttpQueryInfoW(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1753 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1754 INTERNET_STATUS_REDIRECT, szNewLocation,
1756 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1757 dwHeaderLength, lpOptional, dwOptionalLength);
1762 if (hIC->lpfnStatusCB)
1764 INTERNET_ASYNC_RESULT iar;
1766 iar.dwResult = (DWORD)bSuccess;
1767 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1769 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1770 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1771 sizeof(INTERNET_ASYNC_RESULT));
1779 /***********************************************************************
1780 * HTTP_Connect (internal)
1782 * Create http session handle
1785 * HINTERNET a session handle on success
1789 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCWSTR lpszServerName,
1790 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1791 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1793 BOOL bSuccess = FALSE;
1794 LPWININETAPPINFOW hIC = NULL;
1795 LPWININETHTTPSESSIONW lpwhs = NULL;
1796 HINTERNET handle = NULL;
1800 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1801 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1804 hIC->hdr.dwContext = dwContext;
1806 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
1809 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1813 handle = WININET_AllocHandle( &lpwhs->hdr );
1816 ERR("Failed to alloc handle\n");
1817 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1822 * According to my tests. The name is not resolved until a request is sent
1825 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1826 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1828 lpwhs->hdr.htype = WH_HHTTPSESSION;
1829 lpwhs->hdr.lpwhparent = &hIC->hdr;
1830 lpwhs->hdr.dwFlags = dwFlags;
1831 lpwhs->hdr.dwContext = dwContext;
1832 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1833 if(strchrW(hIC->lpszProxy, ' '))
1834 FIXME("Several proxies not implemented.\n");
1835 if(hIC->lpszProxyBypass)
1836 FIXME("Proxy bypass is ignored.\n");
1838 if (NULL != lpszServerName)
1839 lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
1840 if (NULL != lpszUserName)
1841 lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
1842 lpwhs->nServerPort = nServerPort;
1844 if (hIC->lpfnStatusCB)
1846 INTERNET_ASYNC_RESULT iar;
1848 iar.dwResult = (DWORD)handle;
1849 iar.dwError = ERROR_SUCCESS;
1851 SendAsyncCallback(hIC, hInternet, dwContext,
1852 INTERNET_STATUS_HANDLE_CREATED, &iar,
1853 sizeof(INTERNET_ASYNC_RESULT));
1859 if (!bSuccess && lpwhs)
1861 HeapFree(GetProcessHeap(), 0, lpwhs);
1862 WININET_FreeHandle( handle );
1867 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1871 TRACE("%p --> %p\n", hInternet, handle);
1876 /***********************************************************************
1877 * HTTP_OpenConnection (internal)
1879 * Connect to a web server
1886 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
1888 BOOL bSuccess = FALSE;
1889 LPWININETHTTPSESSIONW lpwhs;
1890 LPWININETAPPINFOW hIC = NULL;
1895 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1897 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1901 lpwhs = (LPWININETHTTPSESSIONW)lpwhr->hdr.lpwhparent;
1903 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1904 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1905 INTERNET_STATUS_CONNECTING_TO_SERVER,
1906 &(lpwhs->socketAddress),
1907 sizeof(struct sockaddr_in));
1909 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1912 WARN("Socket creation failed\n");
1916 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1917 sizeof(lpwhs->socketAddress)))
1919 WARN("Unable to connect to host (%s)\n", strerror(errno));
1923 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1924 INTERNET_STATUS_CONNECTED_TO_SERVER,
1925 &(lpwhs->socketAddress),
1926 sizeof(struct sockaddr_in));
1931 TRACE("%d <--\n", bSuccess);
1936 /***********************************************************************
1937 * HTTP_GetResponseHeaders (internal)
1939 * Read server response
1946 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
1949 WCHAR buffer[MAX_REPLY_LEN];
1950 DWORD buflen = MAX_REPLY_LEN;
1951 BOOL bSuccess = FALSE;
1953 WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1954 const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
1955 const WCHAR szHttp[] = { 'H','T','T','P',0 };
1956 char bufferA[MAX_REPLY_LEN];
1960 if (!NETCON_connected(&lpwhr->netConnection))
1964 * HACK peek at the buffer
1966 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1969 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1971 buflen = MAX_REPLY_LEN;
1972 memset(buffer, 0, MAX_REPLY_LEN);
1973 if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1975 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1977 if (strncmpW(buffer, szHttp, 4) != 0)
1981 HTTP_ProcessHeader(lpwhr, szStatus, buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1983 /* Parse each response line */
1986 buflen = MAX_REPLY_LEN;
1987 if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1989 TRACE("got line %s, now interpretting\n", debugstr_a(bufferA));
1990 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1991 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1994 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
2016 /***********************************************************************
2017 * HTTP_InterpretHttpHeader (internal)
2019 * Parse server response
2026 INT stripSpaces(LPCWSTR lpszSrc, LPWSTR lpszStart, INT *len)
2033 while (*lpszSrc == ' ' && *lpszSrc != '\0')
2037 while(*lpsztmp != '\0')
2039 if (*lpsztmp != ' ')
2040 srclen = lpsztmp - lpszSrc + 1;
2045 *len = min(*len, srclen);
2046 strncpyW(lpszStart, lpszSrc, *len);
2047 lpszStart[*len] = '\0';
2053 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen)
2056 BOOL bSuccess = FALSE;
2063 pd = strchrW(buffer, ':');
2067 if (stripSpaces(buffer, field, &fieldlen) > 0)
2069 if (stripSpaces(pd+1, value, &valuelen) > 0)
2074 TRACE("%d: field(%s) Value(%s)\n", bSuccess, debugstr_w(field), debugstr_w(value));
2079 /***********************************************************************
2080 * HTTP_GetStdHeaderIndex (internal)
2082 * Lookup field index in standard http header array
2084 * FIXME: This should be stuffed into a hash table
2086 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField)
2089 const WCHAR szContentLength[] = {
2090 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
2091 const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
2092 const WCHAR szContentType[] = {
2093 'C','o','n','t','e','n','t','-','T','y','p','e',0};
2094 const WCHAR szLastModified[] = {
2095 'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
2096 const WCHAR szLocation[] = {'L','o','c','a','t','i','o','n',0};
2097 const WCHAR szAccept[] = {'A','c','c','e','p','t',0};
2098 const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0};
2099 const WCHAR szContentTrans[] = { 'C','o','n','t','e','n','t','-',
2100 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
2101 const WCHAR szDate[] = { 'D','a','t','e',0};
2102 const WCHAR szServer[] = { 'S','e','r','v','e','r',0};
2103 const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0};
2104 const WCHAR szETag[] = { 'E','T','a','g',0};
2105 const WCHAR szAcceptRanges[] = {
2106 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
2107 const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
2108 const WCHAR szMimeVersion[] = {
2109 'M','i','m','e','-','V','e','r','s','i','o','n', 0};
2110 const WCHAR szPragma[] = { 'P','r','a','g','m','a', 0};
2111 const WCHAR szCacheControl[] = {
2112 'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
2113 const WCHAR szUserAgent[] = { 'U','s','e','r','-','A','g','e','n','t',0};
2114 const WCHAR szProxyAuth[] = {
2115 'P','r','o','x','y','-',
2116 'A','u','t','h','e','n','t','i','c','a','t','e', 0};
2118 if (!strcmpiW(lpszField, szContentLength))
2119 index = HTTP_QUERY_CONTENT_LENGTH;
2120 else if (!strcmpiW(lpszField,szStatus))
2121 index = HTTP_QUERY_STATUS_CODE;
2122 else if (!strcmpiW(lpszField,szContentType))
2123 index = HTTP_QUERY_CONTENT_TYPE;
2124 else if (!strcmpiW(lpszField,szLastModified))
2125 index = HTTP_QUERY_LAST_MODIFIED;
2126 else if (!strcmpiW(lpszField,szLocation))
2127 index = HTTP_QUERY_LOCATION;
2128 else if (!strcmpiW(lpszField,szAccept))
2129 index = HTTP_QUERY_ACCEPT;
2130 else if (!strcmpiW(lpszField,szReferer))
2131 index = HTTP_QUERY_REFERER;
2132 else if (!strcmpiW(lpszField,szContentTrans))
2133 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
2134 else if (!strcmpiW(lpszField,szDate))
2135 index = HTTP_QUERY_DATE;
2136 else if (!strcmpiW(lpszField,szServer))
2137 index = HTTP_QUERY_SERVER;
2138 else if (!strcmpiW(lpszField,szConnection))
2139 index = HTTP_QUERY_CONNECTION;
2140 else if (!strcmpiW(lpszField,szETag))
2141 index = HTTP_QUERY_ETAG;
2142 else if (!strcmpiW(lpszField,szAcceptRanges))
2143 index = HTTP_QUERY_ACCEPT_RANGES;
2144 else if (!strcmpiW(lpszField,szExpires))
2145 index = HTTP_QUERY_EXPIRES;
2146 else if (!strcmpiW(lpszField,szMimeVersion))
2147 index = HTTP_QUERY_MIME_VERSION;
2148 else if (!strcmpiW(lpszField,szPragma))
2149 index = HTTP_QUERY_PRAGMA;
2150 else if (!strcmpiW(lpszField,szCacheControl))
2151 index = HTTP_QUERY_CACHE_CONTROL;
2152 else if (!strcmpiW(lpszField,szUserAgent))
2153 index = HTTP_QUERY_USER_AGENT;
2154 else if (!strcmpiW(lpszField,szProxyAuth))
2155 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2158 TRACE("Couldn't find %s in standard header table\n", debugstr_w(lpszField));
2165 /***********************************************************************
2166 * HTTP_ProcessHeader (internal)
2168 * Stuff header into header tables according to <dwModifier>
2172 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2174 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
2176 LPHTTPHEADERW lphttpHdr = NULL;
2177 BOOL bSuccess = FALSE;
2180 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), (unsigned int)dwModifier);
2182 /* Adjust modifier flags */
2183 if (dwModifier & COALESCEFLASG)
2184 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2186 /* Try to get index into standard header array */
2187 index = HTTP_GetStdHeaderIndex(field);
2190 lphttpHdr = &lpwhr->StdHeaders[index];
2192 else /* Find or create new custom header */
2194 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2197 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2201 lphttpHdr = &lpwhr->pCustHeaders[index];
2207 hdr.lpszField = (LPWSTR)field;
2208 hdr.lpszValue = (LPWSTR)value;
2209 hdr.wFlags = hdr.wCount = 0;
2211 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2212 hdr.wFlags |= HDR_ISREQUEST;
2214 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2218 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2219 lphttpHdr->wFlags |= HDR_ISREQUEST;
2221 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2223 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2227 if (!lpwhr->StdHeaders[index].lpszField)
2229 lphttpHdr->lpszField = WININET_strdupW(field);
2231 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2232 lphttpHdr->wFlags |= HDR_ISREQUEST;
2235 slen = strlenW(value) + 1;
2236 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen*sizeof(WCHAR));
2237 if (lphttpHdr->lpszValue)
2239 strcpyW(lphttpHdr->lpszValue, value);
2244 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2247 else if (lphttpHdr->lpszValue)
2249 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2254 len = strlenW(value);
2258 /* if custom header delete from array */
2259 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2260 lphttpHdr->lpszValue = NULL;
2265 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2268 lphttpHdr->lpszValue = lpsztmp;
2269 strcpyW(lpsztmp, value);
2274 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2275 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2279 else if (dwModifier & COALESCEFLASG)
2284 INT origlen = strlenW(lphttpHdr->lpszValue);
2285 INT valuelen = strlenW(value);
2287 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2290 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2292 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2295 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2298 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2300 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2303 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2306 lphttpHdr->lpszValue[origlen] = ch;
2310 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
2311 lphttpHdr->lpszValue[len] = '\0';
2316 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2317 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2321 TRACE("<-- %d\n",bSuccess);
2326 /***********************************************************************
2327 * HTTP_CloseConnection (internal)
2329 * Close socket connection
2332 VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr)
2336 LPWININETHTTPSESSIONW lpwhs = NULL;
2337 LPWININETAPPINFOW hIC = NULL;
2340 TRACE("%p\n",lpwhr);
2342 handle = WININET_FindHandle( &lpwhr->hdr );
2343 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2344 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2346 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2347 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2349 if (NETCON_connected(&lpwhr->netConnection))
2351 NETCON_close(&lpwhr->netConnection);
2354 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2355 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2359 /***********************************************************************
2360 * HTTP_CloseHTTPRequestHandle (internal)
2362 * Deallocate request handle
2365 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQW lpwhr)
2368 LPWININETHTTPSESSIONW lpwhs = NULL;
2369 LPWININETAPPINFOW hIC = NULL;
2374 if (NETCON_connected(&lpwhr->netConnection))
2375 HTTP_CloseConnection(lpwhr);
2377 handle = WININET_FindHandle( &lpwhr->hdr );
2378 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2379 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2381 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2382 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2385 if (lpwhr->lpszPath)
2386 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2387 if (lpwhr->lpszVerb)
2388 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2389 if (lpwhr->lpszHostName)
2390 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2392 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2394 if (lpwhr->StdHeaders[i].lpszField)
2395 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2396 if (lpwhr->StdHeaders[i].lpszValue)
2397 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2400 for (i = 0; i < lpwhr->nCustHeaders; i++)
2402 if (lpwhr->pCustHeaders[i].lpszField)
2403 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2404 if (lpwhr->pCustHeaders[i].lpszValue)
2405 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2408 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2409 HeapFree(GetProcessHeap(), 0, lpwhr);
2413 /***********************************************************************
2414 * HTTP_CloseHTTPSessionHandle (internal)
2416 * Deallocate session handle
2419 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONW lpwhs)
2421 LPWININETAPPINFOW hIC = NULL;
2424 TRACE("%p\n", lpwhs);
2426 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2428 handle = WININET_FindHandle( &lpwhs->hdr );
2429 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2430 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2433 if (lpwhs->lpszServerName)
2434 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2435 if (lpwhs->lpszUserName)
2436 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2437 HeapFree(GetProcessHeap(), 0, lpwhs);
2441 /***********************************************************************
2442 * HTTP_GetCustomHeaderIndex (internal)
2444 * Return index of custom header from header array
2447 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField)
2451 TRACE("%s\n", debugstr_w(lpszField));
2453 for (index = 0; index < lpwhr->nCustHeaders; index++)
2455 if (!strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
2460 if (index >= lpwhr->nCustHeaders)
2463 TRACE("Return: %d\n", index);
2468 /***********************************************************************
2469 * HTTP_InsertCustomHeader (internal)
2471 * Insert header into array
2474 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
2477 LPHTTPHEADERW lph = NULL;
2480 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
2481 count = lpwhr->nCustHeaders + 1;
2483 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
2485 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
2489 lpwhr->pCustHeaders = lph;
2490 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField);
2491 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
2492 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2493 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2494 lpwhr->nCustHeaders++;
2499 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2506 /***********************************************************************
2507 * HTTP_DeleteCustomHeader (internal)
2509 * Delete header from array
2510 * If this function is called, the indexs may change.
2512 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index)
2514 if( lpwhr->nCustHeaders <= 0 )
2516 if( lpwhr->nCustHeaders >= index )
2518 lpwhr->nCustHeaders--;
2520 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2521 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
2522 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
2527 /***********************************************************************
2528 * IsHostInProxyBypassList (@)
2533 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2535 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);