2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
45 #define NO_SHLWAPI_STREAM
49 #include "wine/debug.h"
50 #include "wine/unicode.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
54 #define HTTPHEADER " HTTP/1.0"
55 #define HTTPHOSTHEADER "\r\nHost: "
56 #define MAXHOSTNAME 100
57 #define MAX_FIELD_VALUE_LEN 256
58 #define MAX_FIELD_LEN 256
61 #define HTTP_REFERER "Referer"
62 #define HTTP_ACCEPT "Accept"
63 #define HTTP_USERAGENT "User-Agent"
65 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
66 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
67 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
68 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
69 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
70 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
71 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
74 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
75 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
76 void *Buffer, int BytesToWrite);
77 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
78 void *Buffer, int BytesToRead);
79 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
80 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
81 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
82 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
83 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
84 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
85 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
87 inline static LPSTR HTTP_strdup( LPCSTR str )
89 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
90 if (ret) strcpy( ret, str );
94 /***********************************************************************
95 * HttpAddRequestHeadersA (WININET.@)
97 * Adds one or more HTTP header to the request handler
104 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
105 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
110 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
111 BOOL bSuccess = FALSE;
112 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
116 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
118 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
124 buffer = HTTP_strdup(lpszHeader);
131 while (*lpszEnd != '\0')
133 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
138 if (*lpszEnd == '\0')
143 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
144 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
146 lpszStart = lpszEnd + 2; /* Jump over \0\n */
150 HeapFree(GetProcessHeap(), 0, buffer);
154 /***********************************************************************
155 * HttpEndRequestA (WININET.@)
157 * Ends an HTTP request that was started by HttpSendRequestEx
164 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
165 DWORD dwFlags, DWORD dwContext)
171 /***********************************************************************
172 * HttpEndRequestW (WININET.@)
174 * Ends an HTTP request that was started by HttpSendRequestEx
181 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
182 DWORD dwFlags, DWORD dwContext)
188 /***********************************************************************
189 * HttpOpenRequestA (WININET.@)
191 * Open a HTTP request handle
194 * HINTERNET a HTTP request handle on success
198 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
199 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
200 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
201 DWORD dwFlags, DWORD dwContext)
203 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
204 LPWININETAPPINFOA hIC = NULL;
206 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, dwFlags, dwContext);
207 if(lpszAcceptTypes!=NULL)
210 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
211 TRACE("\taccept type: %s\n",lpszAcceptTypes[i]);
214 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
216 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
219 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
222 * My tests seem to show that the windows version does not
223 * become asynchronous until after this point. And anyhow
224 * if this call was asynchronous then how would you get the
225 * necessary HINTERNET pointer returned by this function.
227 * I am leaving this here just in case I am wrong
229 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
233 WORKREQUEST workRequest;
235 workRequest.asyncall = HTTPOPENREQUESTA;
236 workRequest.HFTPSESSION = (DWORD)hHttpSession;
237 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
238 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
240 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
242 workRequest.LPSZVERSION = 0;
244 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
246 workRequest.LPSZREFERRER = 0;
247 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
248 workRequest.DWFLAGS = dwFlags;
249 workRequest.DWCONTEXT = dwContext;
251 INTERNET_AsyncCall(&workRequest);
256 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
257 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
261 /***********************************************************************
262 * HttpOpenRequestW (WININET.@)
264 * Open a HTTP request handle
267 * HINTERNET a HTTP request handle on success
271 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
272 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
273 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
274 DWORD dwFlags, DWORD dwContext)
277 szObjectName[INTERNET_MAX_PATH_LENGTH];
278 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", debugstr_w(lpszVerb), debugstr_w(lpszObjectName), debugstr_w(lpszVersion), debugstr_w(lpszReferrer), dwFlags, dwContext);
281 WideCharToMultiByte(CP_ACP,0,lpszVerb,-1,szVerb,20,NULL,NULL);
284 if(lpszObjectName!=NULL)
285 WideCharToMultiByte(CP_ACP,0,lpszObjectName,-1,szObjectName,INTERNET_MAX_PATH_LENGTH,NULL,NULL);
288 TRACE("object name=%s\n",szObjectName);
289 FIXME("lpszVersion, lpszReferrer and lpszAcceptTypes ignored\n");
290 return HttpOpenRequestA(hHttpSession, szVerb[0]?szVerb:NULL, szObjectName, NULL, NULL, NULL, dwFlags, dwContext);
293 /***********************************************************************
294 * HTTP_HttpOpenRequestA (internal)
296 * Open a HTTP request handle
299 * HINTERNET a HTTP request handle on success
303 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
304 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
305 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
306 DWORD dwFlags, DWORD dwContext)
308 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
309 LPWININETAPPINFOA hIC = NULL;
310 LPWININETHTTPREQA lpwhr;
314 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
316 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
320 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
322 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
325 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
326 return (HINTERNET) NULL;
329 lpwhr->hdr.htype = WH_HHTTPREQ;
330 lpwhr->hdr.lpwhparent = hHttpSession;
331 lpwhr->hdr.dwFlags = dwFlags;
332 lpwhr->hdr.dwContext = dwContext;
333 lpwhr->nSocketFD = -1;
335 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
338 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
340 needed = strlen(lpszObjectName)+1;
341 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
342 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
343 URL_ESCAPE_SPACES_ONLY);
346 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
347 strcpy(lpwhr->lpszPath,lpszObjectName);
351 if (NULL != hIC->lpszAgent && strlen(hIC->lpszAgent))
352 HTTP_ProcessHeader(lpwhr, HTTP_USERAGENT, hIC->lpszAgent, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
354 if (NULL != lpszReferrer && strlen(lpszReferrer))
355 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
357 if(lpszAcceptTypes!=NULL)
360 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
361 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
364 if (NULL == lpszVerb)
365 lpwhr->lpszVerb = HTTP_strdup("GET");
366 else if (strlen(lpszVerb))
367 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
369 if (NULL != lpszReferrer)
371 char buf[MAXHOSTNAME];
372 URL_COMPONENTSA UrlComponents;
374 UrlComponents.lpszExtraInfo = NULL;
375 UrlComponents.lpszPassword = NULL;
376 UrlComponents.lpszScheme = NULL;
377 UrlComponents.lpszUrlPath = NULL;
378 UrlComponents.lpszUserName = NULL;
379 UrlComponents.lpszHostName = buf;
380 UrlComponents.dwHostNameLength = MAXHOSTNAME;
382 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
383 if (strlen(UrlComponents.lpszHostName))
384 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
385 } else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) {
386 char buf[MAXHOSTNAME];
387 char proxy[MAXHOSTNAME + 13]; /* 13 == "http://" + sizeof(port#) + ":/\0" */
388 URL_COMPONENTSA UrlComponents;
390 UrlComponents.lpszExtraInfo = NULL;
391 UrlComponents.lpszPassword = NULL;
392 UrlComponents.lpszScheme = NULL;
393 UrlComponents.lpszUrlPath = NULL;
394 UrlComponents.lpszUserName = NULL;
395 UrlComponents.lpszHostName = buf;
396 UrlComponents.dwHostNameLength = MAXHOSTNAME;
398 sprintf(proxy, "http://%s/", hIC->lpszProxy);
399 InternetCrackUrlA(proxy, 0, 0, &UrlComponents);
400 if (strlen(UrlComponents.lpszHostName)) {
401 /* for constant 13 see above */
402 char* url = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + strlen(lpwhr->lpszPath) + 13);
404 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
405 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
407 if(lpwhr->lpszHostName != 0) {
408 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
409 lpwhr->lpszHostName = 0;
411 sprintf(url, "http://%s:%d/%s", lpwhs->lpszServerName, lpwhs->nServerPort, lpwhr->lpszPath);
413 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
414 lpwhr->lpszPath = url;
415 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
416 lpwhs->lpszServerName = HTTP_strdup(UrlComponents.lpszHostName);
417 lpwhs->nServerPort = UrlComponents.nPort;
420 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
423 if (hIC->lpfnStatusCB)
425 INTERNET_ASYNC_RESULT iar;
427 iar.dwResult = (DWORD)lpwhr;
428 iar.dwError = ERROR_SUCCESS;
430 SendAsyncCallback(hIC, hHttpSession, dwContext,
431 INTERNET_STATUS_HANDLE_CREATED, &iar,
432 sizeof(INTERNET_ASYNC_RESULT));
436 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
440 * According to my tests. The name is not resolved until a request is Opened
442 SendAsyncCallback(hIC, hHttpSession, dwContext,
443 INTERNET_STATUS_RESOLVING_NAME,
444 lpwhs->lpszServerName,
445 strlen(lpwhs->lpszServerName)+1);
447 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
448 &lpwhs->phostent, &lpwhs->socketAddress))
450 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
454 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
455 INTERNET_STATUS_NAME_RESOLVED,
456 &(lpwhs->socketAddress),
457 sizeof(struct sockaddr_in));
460 return (HINTERNET) lpwhr;
464 /***********************************************************************
465 * HttpQueryInfoA (WININET.@)
467 * Queries for information about an HTTP request
474 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
475 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
477 LPHTTPHEADERA lphttpHdr = NULL;
478 BOOL bSuccess = FALSE;
479 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
481 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
483 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
485 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
489 /* Find requested header structure */
490 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
492 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
497 lphttpHdr = &lpwhr->pCustHeaders[index];
501 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
503 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
505 INT i, delim, size = 0, cnt = 0;
507 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
509 /* Calculate length of custom reuqest headers */
510 for (i = 0; i < lpwhr->nCustHeaders; i++)
512 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
513 lpwhr->pCustHeaders[i].lpszValue)
515 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
516 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
520 /* Calculate the length of stadard request headers */
521 for (i = 0; i <= HTTP_QUERY_MAX; i++)
523 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
524 lpwhr->StdHeaders[i].lpszValue)
526 size += strlen(lpwhr->StdHeaders[i].lpszField) +
527 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
532 if (size + 1 > *lpdwBufferLength)
534 *lpdwBufferLength = size + 1;
535 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
539 /* Append standard request heades */
540 for (i = 0; i <= HTTP_QUERY_MAX; i++)
542 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
543 lpwhr->StdHeaders[i].lpszField &&
544 lpwhr->StdHeaders[i].lpszValue)
546 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
547 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
551 /* Append custom request heades */
552 for (i = 0; i < lpwhr->nCustHeaders; i++)
554 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
555 lpwhr->pCustHeaders[i].lpszField &&
556 lpwhr->pCustHeaders[i].lpszValue)
558 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
559 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
560 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
564 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
566 *lpdwBufferLength = cnt + delim;
570 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
572 lphttpHdr = &lpwhr->StdHeaders[index];
578 /* Ensure header satisifies requested attributes */
579 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
580 (~lphttpHdr->wFlags & HDR_ISREQUEST))
583 /* coalesce value to reuqested type */
584 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
586 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
589 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
595 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
597 tmpTM = *gmtime(&tmpTime);
598 STHook = (SYSTEMTIME *) lpBuffer;
602 STHook->wDay = tmpTM.tm_mday;
603 STHook->wHour = tmpTM.tm_hour;
604 STHook->wMilliseconds = 0;
605 STHook->wMinute = tmpTM.tm_min;
606 STHook->wDayOfWeek = tmpTM.tm_wday;
607 STHook->wMonth = tmpTM.tm_mon + 1;
608 STHook->wSecond = tmpTM.tm_sec;
609 STHook->wYear = tmpTM.tm_year;
613 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
615 if (*lpdwIndex >= lphttpHdr->wCount)
617 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
621 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
627 INT len = strlen(lphttpHdr->lpszValue);
629 if (len + 1 > *lpdwBufferLength)
631 *lpdwBufferLength = len + 1;
632 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
636 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
637 ((char*)lpBuffer)[len]=0;
638 *lpdwBufferLength = len;
643 TRACE("%d <--\n", bSuccess);
647 /***********************************************************************
648 * HttpQueryInfoW (WININET.@)
650 * Queries for information about an HTTP request
657 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
658 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
661 DWORD charLen=*lpdwBufferLength;
662 char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
663 result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
664 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
665 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
667 memcpy(lpBuffer,tempBuffer,charLen);
671 int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
672 *lpdwBufferLength=nChars;
674 HeapFree(GetProcessHeap(), 0, tempBuffer);
678 /***********************************************************************
679 * HttpSendRequestExA (WININET.@)
681 * Sends the specified request to the HTTP server and allows chunked
684 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
685 LPINTERNET_BUFFERSA lpBuffersIn,
686 LPINTERNET_BUFFERSA lpBuffersOut,
687 DWORD dwFlags, DWORD dwContext)
689 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
690 lpBuffersOut, dwFlags, dwContext);
694 /***********************************************************************
695 * HttpSendRequestA (WININET.@)
697 * Sends the specified request to the HTTP server
704 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
705 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
707 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
708 LPWININETHTTPSESSIONA lpwhs = NULL;
709 LPWININETAPPINFOA hIC = NULL;
711 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
713 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
715 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
719 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
720 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
722 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
726 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
727 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
729 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
733 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
735 WORKREQUEST workRequest;
737 workRequest.asyncall = HTTPSENDREQUESTA;
738 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
740 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
742 workRequest.LPSZHEADER = 0;
743 workRequest.DWHEADERLENGTH = dwHeaderLength;
744 workRequest.LPOPTIONAL = (DWORD)lpOptional;
745 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
747 INTERNET_AsyncCall(&workRequest);
749 * This is from windows.
751 SetLastError(ERROR_IO_PENDING);
756 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
757 dwHeaderLength, lpOptional, dwOptionalLength);
761 /***********************************************************************
762 * HttpSendRequestW (WININET.@)
764 * Sends the specified request to the HTTP server
771 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
772 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
775 char* szHeaders=NULL;
776 DWORD nLen=dwHeaderLength;
777 if(lpszHeaders!=NULL)
780 nLen=strlenW(lpszHeaders);
781 szHeaders=(char*)malloc(nLen+1);
782 WideCharToMultiByte(CP_ACP,0,lpszHeaders,nLen,szHeaders,nLen,NULL,NULL);
784 result=HttpSendRequestA(hHttpRequest, szHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
790 /***********************************************************************
791 * HTTP_HandleRedirect (internal)
793 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
794 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
796 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
797 LPWININETAPPINFOA hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
801 /* if it's an absolute path, keep the same session info */
802 strcpy(path,lpszUrl);
806 URL_COMPONENTSA urlComponents;
807 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
808 char password[1024], extra[1024];
809 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
810 urlComponents.lpszScheme = protocol;
811 urlComponents.dwSchemeLength = 32;
812 urlComponents.lpszHostName = hostName;
813 urlComponents.dwHostNameLength = MAXHOSTNAME;
814 urlComponents.lpszUserName = userName;
815 urlComponents.dwUserNameLength = 1024;
816 urlComponents.lpszPassword = password;
817 urlComponents.dwPasswordLength = 1024;
818 urlComponents.lpszUrlPath = path;
819 urlComponents.dwUrlPathLength = 2048;
820 urlComponents.lpszExtraInfo = extra;
821 urlComponents.dwExtraInfoLength = 1024;
822 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
825 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
826 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
828 /* consider the current host as the referef */
829 if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
830 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
832 if (NULL != lpwhs->lpszServerName)
833 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
834 lpwhs->lpszServerName = HTTP_strdup(hostName);
835 if (NULL != lpwhs->lpszUserName)
836 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
837 lpwhs->lpszUserName = HTTP_strdup(userName);
838 lpwhs->nServerPort = urlComponents.nPort;
840 if (NULL != lpwhr->lpszHostName)
841 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
842 lpwhr->lpszHostName=HTTP_strdup(hostName);
844 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
845 INTERNET_STATUS_RESOLVING_NAME,
846 lpwhs->lpszServerName,
847 strlen(lpwhs->lpszServerName)+1);
849 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
850 &lpwhs->phostent, &lpwhs->socketAddress))
852 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
856 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
857 INTERNET_STATUS_NAME_RESOLVED,
858 &(lpwhs->socketAddress),
859 sizeof(struct sockaddr_in));
864 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
865 lpwhr->lpszPath=NULL;
870 rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
872 needed = strlen(path)+1;
873 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
874 rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
875 URL_ESCAPE_SPACES_ONLY);
878 ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
879 strcpy(lpwhr->lpszPath,path);
883 return HttpSendRequestA((HINTERNET)lpwhr, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
886 /***********************************************************************
887 * HTTP_HttpSendRequestA (internal)
889 * Sends the specified request to the HTTP server
896 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
897 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
901 BOOL bSuccess = FALSE;
902 LPSTR requestString = NULL;
903 INT requestStringLen;
905 INT headerLength = 0;
906 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
907 LPWININETHTTPSESSIONA lpwhs = NULL;
908 LPWININETAPPINFOA hIC = NULL;
910 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
912 /* Verify our tree of internet handles */
913 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
915 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
919 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
920 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
922 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
926 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
927 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
929 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
933 /* Clear any error information */
934 INTERNET_SetLastError(0);
937 /* We must have a verb */
938 if (NULL == lpwhr->lpszVerb)
943 /* If we don't have a path we set it to root */
944 if (NULL == lpwhr->lpszPath)
945 lpwhr->lpszPath = HTTP_strdup("/");
947 if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
948 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
950 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
952 strcpy(fixurl + 1, lpwhr->lpszPath);
953 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
954 lpwhr->lpszPath = fixurl;
957 /* Calculate length of request string */
959 strlen(lpwhr->lpszVerb) +
960 strlen(lpwhr->lpszPath) +
961 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
965 /* Add length of passed headers */
968 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
969 requestStringLen += headerLength + 2; /* \r\n */
972 /* Calculate length of custom request headers */
973 for (i = 0; i < lpwhr->nCustHeaders; i++)
975 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
977 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
978 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
982 /* Calculate the length of standard request headers */
983 for (i = 0; i <= HTTP_QUERY_MAX; i++)
985 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
987 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
988 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
992 /* Allocate string to hold entire request */
993 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
994 if (NULL == requestString)
996 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1000 /* Build request string */
1001 cnt = sprintf(requestString, "%s %s%s%s",
1004 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
1005 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
1007 /* Append standard request headers */
1008 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1010 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1012 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1013 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1014 TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
1018 /* Append custom request heades */
1019 for (i = 0; i < lpwhr->nCustHeaders; i++)
1021 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1023 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1024 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1025 TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
1029 /* Append passed request headers */
1032 strcpy(requestString + cnt, "\r\n");
1034 strcpy(requestString + cnt, lpszHeaders);
1035 cnt += headerLength;
1038 /* Set termination string for request */
1039 strcpy(requestString + cnt, "\r\n\r\n");
1041 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1042 /* Send the request and store the results */
1043 if (!HTTP_OpenConnection(lpwhr))
1046 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1047 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1049 cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0);
1051 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1052 INTERNET_STATUS_REQUEST_SENT,
1053 &requestStringLen,sizeof(DWORD));
1055 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1056 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1061 responseLen = HTTP_GetResponseHeaders(lpwhr);
1065 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1066 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1072 HeapFree(GetProcessHeap(), 0, requestString);
1074 /* TODO: send notification for P3P header */
1076 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1078 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1079 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1080 (dwCode==302 || dwCode==301))
1082 char szNewLocation[2048];
1083 DWORD dwBufferSize=2048;
1085 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1087 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1088 INTERNET_STATUS_REDIRECT, szNewLocation,
1090 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1091 dwHeaderLength, lpOptional, dwOptionalLength);
1096 if (hIC->lpfnStatusCB)
1098 INTERNET_ASYNC_RESULT iar;
1100 iar.dwResult = (DWORD)bSuccess;
1101 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1103 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1104 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1105 sizeof(INTERNET_ASYNC_RESULT));
1113 /***********************************************************************
1114 * HTTP_Connect (internal)
1116 * Create http session handle
1119 * HINTERNET a session handle on success
1123 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1124 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1125 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1127 BOOL bSuccess = FALSE;
1128 LPWININETAPPINFOA hIC = NULL;
1129 LPWININETHTTPSESSIONA lpwhs = NULL;
1133 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1136 hIC = (LPWININETAPPINFOA) hInternet;
1137 hIC->hdr.dwContext = dwContext;
1139 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1142 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1147 * According to my tests. The name is not resolved until a request is sent
1150 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1151 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1153 lpwhs->hdr.htype = WH_HHTTPSESSION;
1154 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1155 lpwhs->hdr.dwFlags = dwFlags;
1156 lpwhs->hdr.dwContext = dwContext;
1157 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1158 if(strchr(hIC->lpszProxy, ' '))
1159 FIXME("Several proxies not implemented.\n");
1160 if(hIC->lpszProxyBypass)
1161 FIXME("Proxy bypass is ignored.\n");
1163 if (NULL != lpszServerName)
1164 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
1165 if (NULL != lpszUserName)
1166 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
1167 lpwhs->nServerPort = nServerPort;
1169 if (hIC->lpfnStatusCB)
1171 INTERNET_ASYNC_RESULT iar;
1173 iar.dwResult = (DWORD)lpwhs;
1174 iar.dwError = ERROR_SUCCESS;
1176 SendAsyncCallback(hIC, hInternet, dwContext,
1177 INTERNET_STATUS_HANDLE_CREATED, &iar,
1178 sizeof(INTERNET_ASYNC_RESULT));
1184 if (!bSuccess && lpwhs)
1186 HeapFree(GetProcessHeap(), 0, lpwhs);
1191 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1196 return (HINTERNET)lpwhs;
1200 /***********************************************************************
1201 * HTTP_OpenConnection (internal)
1203 * Connect to a web server
1210 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1212 BOOL bSuccess = FALSE;
1214 LPWININETHTTPSESSIONA lpwhs;
1215 LPWININETAPPINFOA hIC = NULL;
1220 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1222 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1226 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1228 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1229 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1230 INTERNET_STATUS_CONNECTING_TO_SERVER,
1231 &(lpwhs->socketAddress),
1232 sizeof(struct sockaddr_in));
1234 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
1235 if (lpwhr->nSocketFD == -1)
1237 WARN("Socket creation failed\n");
1241 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
1242 sizeof(lpwhs->socketAddress));
1246 WARN("Unable to connect to host (%s)\n", strerror(errno));
1250 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1251 INTERNET_STATUS_CONNECTED_TO_SERVER,
1252 &(lpwhs->socketAddress),
1253 sizeof(struct sockaddr_in));
1258 TRACE("%d <--\n", bSuccess);
1263 /***********************************************************************
1264 * HTTP_GetResponseHeaders (internal)
1266 * Read server response
1273 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1276 CHAR buffer[MAX_REPLY_LEN];
1277 DWORD buflen = MAX_REPLY_LEN;
1278 BOOL bSuccess = FALSE;
1280 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1284 if (lpwhr->nSocketFD == -1)
1288 * HACK peek at the buffer
1290 rc = recv(lpwhr->nSocketFD,buffer,buflen,MSG_PEEK);
1293 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1295 buflen = MAX_REPLY_LEN;
1296 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1299 if (strncmp(buffer, "HTTP", 4) != 0)
1303 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1305 /* Parse each response line */
1308 buflen = MAX_REPLY_LEN;
1309 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1311 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1314 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1336 /***********************************************************************
1337 * HTTP_InterpretHttpHeader (internal)
1339 * Parse server response
1346 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1353 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1357 while(*lpsztmp != '\0')
1359 if (*lpsztmp != ' ')
1360 srclen = lpsztmp - lpszSrc + 1;
1365 *len = min(*len, srclen);
1366 strncpy(lpszStart, lpszSrc, *len);
1367 lpszStart[*len] = '\0';
1373 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1376 BOOL bSuccess = FALSE;
1383 pd = strchr(buffer, ':');
1387 if (stripSpaces(buffer, field, &fieldlen) > 0)
1389 if (stripSpaces(pd+1, value, &valuelen) > 0)
1394 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1399 /***********************************************************************
1400 * HTTP_GetStdHeaderIndex (internal)
1402 * Lookup field index in standard http header array
1404 * FIXME: This should be stuffed into a hash table
1406 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1410 if (!strcasecmp(lpszField, "Content-Length"))
1411 index = HTTP_QUERY_CONTENT_LENGTH;
1412 else if (!strcasecmp(lpszField,"Status"))
1413 index = HTTP_QUERY_STATUS_CODE;
1414 else if (!strcasecmp(lpszField,"Content-Type"))
1415 index = HTTP_QUERY_CONTENT_TYPE;
1416 else if (!strcasecmp(lpszField,"Last-Modified"))
1417 index = HTTP_QUERY_LAST_MODIFIED;
1418 else if (!strcasecmp(lpszField,"Location"))
1419 index = HTTP_QUERY_LOCATION;
1420 else if (!strcasecmp(lpszField,"Accept"))
1421 index = HTTP_QUERY_ACCEPT;
1422 else if (!strcasecmp(lpszField,"Referer"))
1423 index = HTTP_QUERY_REFERER;
1424 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1425 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1426 else if (!strcasecmp(lpszField,"Date"))
1427 index = HTTP_QUERY_DATE;
1428 else if (!strcasecmp(lpszField,"Server"))
1429 index = HTTP_QUERY_SERVER;
1430 else if (!strcasecmp(lpszField,"Connection"))
1431 index = HTTP_QUERY_CONNECTION;
1432 else if (!strcasecmp(lpszField,"ETag"))
1433 index = HTTP_QUERY_ETAG;
1434 else if (!strcasecmp(lpszField,"Accept-Ranges"))
1435 index = HTTP_QUERY_ACCEPT_RANGES;
1436 else if (!strcasecmp(lpszField,"Expires"))
1437 index = HTTP_QUERY_EXPIRES;
1438 else if (!strcasecmp(lpszField,"Mime-Version"))
1439 index = HTTP_QUERY_MIME_VERSION;
1440 else if (!strcasecmp(lpszField,"Pragma"))
1441 index = HTTP_QUERY_PRAGMA;
1442 else if (!strcasecmp(lpszField,"Cache-Control"))
1443 index = HTTP_QUERY_CACHE_CONTROL;
1444 else if (!strcasecmp(lpszField,"Content-Length"))
1445 index = HTTP_QUERY_CONTENT_LENGTH;
1446 else if (!strcasecmp(lpszField,"User-Agent"))
1447 index = HTTP_QUERY_USER_AGENT;
1450 TRACE("Couldn't find %s in standard header table\n", lpszField);
1457 /***********************************************************************
1458 * HTTP_ProcessHeader (internal)
1460 * Stuff header into header tables according to <dwModifier>
1464 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1466 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1468 LPHTTPHEADERA lphttpHdr = NULL;
1469 BOOL bSuccess = FALSE;
1472 TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1474 /* Adjust modifier flags */
1475 if (dwModifier & COALESCEFLASG)
1476 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1478 /* Try to get index into standard header array */
1479 index = HTTP_GetStdHeaderIndex(field);
1482 lphttpHdr = &lpwhr->StdHeaders[index];
1484 else /* Find or create new custom header */
1486 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1489 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1493 lphttpHdr = &lpwhr->pCustHeaders[index];
1499 hdr.lpszField = (LPSTR)field;
1500 hdr.lpszValue = (LPSTR)value;
1501 hdr.wFlags = hdr.wCount = 0;
1503 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1504 hdr.wFlags |= HDR_ISREQUEST;
1506 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1511 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1512 lphttpHdr->wFlags |= HDR_ISREQUEST;
1514 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1516 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1520 if (!lpwhr->StdHeaders[index].lpszField)
1522 lphttpHdr->lpszField = HTTP_strdup(field);
1524 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1525 lphttpHdr->wFlags |= HDR_ISREQUEST;
1528 slen = strlen(value) + 1;
1529 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1530 if (lphttpHdr->lpszValue)
1532 memcpy(lphttpHdr->lpszValue, value, slen);
1537 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1540 else if (lphttpHdr->lpszValue)
1542 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1547 len = strlen(value);
1551 /* if custom header delete from array */
1552 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1553 lphttpHdr->lpszValue = NULL;
1558 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1561 lphttpHdr->lpszValue = lpsztmp;
1562 strcpy(lpsztmp, value);
1567 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1568 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1572 else if (dwModifier & COALESCEFLASG)
1577 INT origlen = strlen(lphttpHdr->lpszValue);
1578 INT valuelen = strlen(value);
1580 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1583 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1585 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1588 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1591 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
1593 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1596 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1599 lphttpHdr->lpszValue[origlen] = ch;
1603 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1604 lphttpHdr->lpszValue[len] = '\0';
1609 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1610 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1614 TRACE("<-- %d\n",bSuccess);
1619 /***********************************************************************
1620 * HTTP_CloseConnection (internal)
1622 * Close socket connection
1625 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1629 LPWININETHTTPSESSIONA lpwhs = NULL;
1630 LPWININETAPPINFOA hIC = NULL;
1632 TRACE("%p\n",lpwhr);
1634 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1635 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1637 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1638 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1640 if (lpwhr->nSocketFD != -1)
1642 close(lpwhr->nSocketFD);
1643 lpwhr->nSocketFD = -1;
1646 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1647 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1651 /***********************************************************************
1652 * HTTP_CloseHTTPRequestHandle (internal)
1654 * Deallocate request handle
1657 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1660 LPWININETHTTPSESSIONA lpwhs = NULL;
1661 LPWININETAPPINFOA hIC = NULL;
1665 if (lpwhr->nSocketFD != -1)
1666 HTTP_CloseConnection(lpwhr);
1668 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1669 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1671 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1672 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
1675 if (lpwhr->lpszPath)
1676 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1677 if (lpwhr->lpszVerb)
1678 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1679 if (lpwhr->lpszHostName)
1680 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1682 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1684 if (lpwhr->StdHeaders[i].lpszField)
1685 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1686 if (lpwhr->StdHeaders[i].lpszValue)
1687 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1690 for (i = 0; i < lpwhr->nCustHeaders; i++)
1692 if (lpwhr->pCustHeaders[i].lpszField)
1693 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1694 if (lpwhr->pCustHeaders[i].lpszValue)
1695 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1698 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1699 HeapFree(GetProcessHeap(), 0, lpwhr);
1703 /***********************************************************************
1704 * HTTP_CloseHTTPSessionHandle (internal)
1706 * Deallocate session handle
1709 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1711 LPWININETAPPINFOA hIC = NULL;
1714 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1716 SendAsyncCallback(hIC, lpwhs, lpwhs->hdr.dwContext,
1717 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
1720 if (lpwhs->lpszServerName)
1721 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1722 if (lpwhs->lpszUserName)
1723 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1724 HeapFree(GetProcessHeap(), 0, lpwhs);
1728 /***********************************************************************
1729 * HTTP_GetCustomHeaderIndex (internal)
1731 * Return index of custom header from header array
1734 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1738 TRACE("%s\n", lpszField);
1740 for (index = 0; index < lpwhr->nCustHeaders; index++)
1742 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1747 if (index >= lpwhr->nCustHeaders)
1750 TRACE("Return: %d\n", index);
1755 /***********************************************************************
1756 * HTTP_InsertCustomHeader (internal)
1758 * Insert header into array
1761 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1764 LPHTTPHEADERA lph = NULL;
1766 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1767 count = lpwhr->nCustHeaders + 1;
1769 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1771 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1775 lpwhr->pCustHeaders = lph;
1776 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1777 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1778 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1779 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1780 lpwhr->nCustHeaders++;
1784 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1788 TRACE("%d <--\n", count-1);
1793 /***********************************************************************
1794 * HTTP_DeleteCustomHeader (internal)
1796 * Delete header from array
1799 BOOL HTTP_DeleteCustomHeader(INT index)
1805 /***********************************************************************
1806 * IsHostInProxyBypassList (@)
1811 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
1813 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);