Ignore the LPSURFACE bit if ALLOCONLOAD is set.
[wine/multimedia.git] / dlls / wininet / http.c
blob73d9dc40d04051393efd8878f1ddfd3dbc0f1a9c
1 /*
2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
7 * Ulrich Czekalla
8 * Aric Stewart
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
25 #include "config.h"
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
30 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <errno.h>
37 #include <string.h>
38 #include <time.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wininet.h"
43 #include "winreg.h"
44 #include "winerror.h"
45 #define NO_SHLWAPI_STREAM
46 #include "shlwapi.h"
48 #include "internet.h"
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 );
91 return ret;
94 /***********************************************************************
95 * HttpAddRequestHeadersA (WININET.@)
97 * Adds one or more HTTP header to the request handler
99 * RETURNS
100 * TRUE on success
101 * FALSE on failure
104 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
105 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
107 LPSTR lpszStart;
108 LPSTR lpszEnd;
109 LPSTR buffer;
110 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
111 BOOL bSuccess = FALSE;
112 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
114 TRACE("\n");
116 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
118 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
119 return FALSE;
122 buffer = HTTP_strdup(lpszHeader);
123 lpszStart = buffer;
127 lpszEnd = lpszStart;
129 while (*lpszEnd != '\0')
131 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
132 break;
133 lpszEnd++;
136 if (*lpszEnd == '\0')
137 break;
139 *lpszEnd = '\0';
141 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
142 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
144 lpszStart = lpszEnd + 2; /* Jump over \0\n */
146 } while (bSuccess);
148 HeapFree(GetProcessHeap(), 0, buffer);
149 return bSuccess;
152 /***********************************************************************
153 * HttpEndRequestA (WININET.@)
155 * Ends an HTTP request that was started by HttpSendRequestEx
157 * RETURNS
158 * TRUE if successful
159 * FALSE on failure
162 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
163 DWORD dwFlags, DWORD dwContext)
165 FIXME("stub\n");
166 return FALSE;
169 /***********************************************************************
170 * HttpEndRequestW (WININET.@)
172 * Ends an HTTP request that was started by HttpSendRequestEx
174 * RETURNS
175 * TRUE if successful
176 * FALSE on failure
179 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
180 DWORD dwFlags, DWORD dwContext)
182 FIXME("stub\n");
183 return FALSE;
186 /***********************************************************************
187 * HttpOpenRequestA (WININET.@)
189 * Open a HTTP request handle
191 * RETURNS
192 * HINTERNET a HTTP request handle on success
193 * NULL on failure
196 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
197 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
198 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
199 DWORD dwFlags, DWORD dwContext)
201 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
202 LPWININETAPPINFOA hIC = NULL;
204 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, dwFlags, dwContext);
205 if(lpszAcceptTypes!=NULL)
207 int i;
208 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
209 TRACE("\taccept type: %s\n",lpszAcceptTypes[i]);
212 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
214 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
215 return FALSE;
217 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
220 * My tests seem to show that the windows version does not
221 * become asynchronous until after this point. And anyhow
222 * if this call was asynchronous then how would you get the
223 * necessary HINTERNET pointer returned by this function.
225 * I am leaving this here just in case I am wrong
227 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
229 if (0)
231 WORKREQUEST workRequest;
233 workRequest.asyncall = HTTPOPENREQUESTA;
234 workRequest.HFTPSESSION = (DWORD)hHttpSession;
235 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
236 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
237 if (lpszVersion)
238 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
239 else
240 workRequest.LPSZVERSION = 0;
241 if (lpszReferrer)
242 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
243 else
244 workRequest.LPSZREFERRER = 0;
245 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
246 workRequest.DWFLAGS = dwFlags;
247 workRequest.DWCONTEXT = dwContext;
249 INTERNET_AsyncCall(&workRequest);
250 return NULL;
252 else
254 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
255 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
259 /***********************************************************************
260 * HttpOpenRequestW (WININET.@)
262 * Open a HTTP request handle
264 * RETURNS
265 * HINTERNET a HTTP request handle on success
266 * NULL on failure
269 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
270 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
271 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
272 DWORD dwFlags, DWORD dwContext)
274 char szVerb[20],
275 szObjectName[INTERNET_MAX_PATH_LENGTH];
276 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", debugstr_w(lpszVerb), debugstr_w(lpszObjectName), debugstr_w(lpszVersion), debugstr_w(lpszReferrer), dwFlags, dwContext);
278 if(lpszVerb!=NULL)
279 WideCharToMultiByte(CP_ACP,0,lpszVerb,-1,szVerb,20,NULL,NULL);
280 else
281 szVerb[0]=0;
282 if(lpszObjectName!=NULL)
283 WideCharToMultiByte(CP_ACP,0,lpszObjectName,-1,szObjectName,INTERNET_MAX_PATH_LENGTH,NULL,NULL);
284 else
285 szObjectName[0]=0;
286 TRACE("object name=%s\n",szObjectName);
287 FIXME("lpszVersion, lpszReferrer and lpszAcceptTypes ignored\n");
288 return HttpOpenRequestA(hHttpSession, szVerb[0]?szVerb:NULL, szObjectName, NULL, NULL, NULL, dwFlags, dwContext);
291 /***********************************************************************
292 * HTTP_HttpOpenRequestA (internal)
294 * Open a HTTP request handle
296 * RETURNS
297 * HINTERNET a HTTP request handle on success
298 * NULL on failure
301 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
302 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
303 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
304 DWORD dwFlags, DWORD dwContext)
306 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
307 LPWININETAPPINFOA hIC = NULL;
308 LPWININETHTTPREQA lpwhr;
310 TRACE("--> \n");
312 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
314 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
315 return FALSE;
318 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
320 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
321 if (NULL == lpwhr)
323 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
324 return (HINTERNET) NULL;
327 lpwhr->hdr.htype = WH_HHTTPREQ;
328 lpwhr->hdr.lpwhparent = hHttpSession;
329 lpwhr->hdr.dwFlags = dwFlags;
330 lpwhr->hdr.dwContext = dwContext;
331 lpwhr->nSocketFD = -1;
333 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
334 DWORD needed = 0;
335 HRESULT rc;
336 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
337 if (rc != E_POINTER)
338 needed = strlen(lpszObjectName)+1;
339 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
340 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
341 URL_ESCAPE_SPACES_ONLY);
342 if (rc)
344 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
345 strcpy(lpwhr->lpszPath,lpszObjectName);
349 if (NULL != hIC->lpszAgent && strlen(hIC->lpszAgent))
350 HTTP_ProcessHeader(lpwhr, HTTP_USERAGENT, hIC->lpszAgent, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
352 if (NULL != lpszReferrer && strlen(lpszReferrer))
353 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
355 if(lpszAcceptTypes!=NULL)
357 int i;
358 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
359 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
362 if (NULL == lpszVerb)
363 lpwhr->lpszVerb = HTTP_strdup("GET");
364 else if (strlen(lpszVerb))
365 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
367 if (NULL != lpszReferrer)
369 char buf[MAXHOSTNAME];
370 URL_COMPONENTSA UrlComponents;
372 UrlComponents.lpszExtraInfo = NULL;
373 UrlComponents.lpszPassword = NULL;
374 UrlComponents.lpszScheme = NULL;
375 UrlComponents.lpszUrlPath = NULL;
376 UrlComponents.lpszUserName = NULL;
377 UrlComponents.lpszHostName = buf;
378 UrlComponents.dwHostNameLength = MAXHOSTNAME;
380 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
381 if (strlen(UrlComponents.lpszHostName))
382 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
383 } else {
384 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
387 if (hIC->lpfnStatusCB)
389 INTERNET_ASYNC_RESULT iar;
391 iar.dwResult = (DWORD)lpwhr;
392 iar.dwError = ERROR_SUCCESS;
394 SendAsyncCallback(hIC, hHttpSession, dwContext,
395 INTERNET_STATUS_HANDLE_CREATED, &iar,
396 sizeof(INTERNET_ASYNC_RESULT));
400 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
404 * According to my tests. The name is not resolved until a request is Opened
406 SendAsyncCallback(hIC, hHttpSession, dwContext,
407 INTERNET_STATUS_RESOLVING_NAME,
408 lpwhs->lpszServerName,
409 strlen(lpwhs->lpszServerName)+1);
411 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
412 &lpwhs->phostent, &lpwhs->socketAddress))
414 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
415 return FALSE;
418 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
419 INTERNET_STATUS_NAME_RESOLVED,
420 &(lpwhs->socketAddress),
421 sizeof(struct sockaddr_in));
423 TRACE("<--\n");
424 return (HINTERNET) lpwhr;
428 /***********************************************************************
429 * HttpQueryInfoA (WININET.@)
431 * Queries for information about an HTTP request
433 * RETURNS
434 * TRUE on success
435 * FALSE on failure
438 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
439 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
441 LPHTTPHEADERA lphttpHdr = NULL;
442 BOOL bSuccess = FALSE;
443 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
445 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
447 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
449 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
450 return FALSE;
453 /* Find requested header structure */
454 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
456 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
458 if (index < 0)
459 goto lend;
461 lphttpHdr = &lpwhr->pCustHeaders[index];
463 else
465 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
467 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
469 INT i, delim, size = 0, cnt = 0;
471 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
473 /* Calculate length of custom reuqest headers */
474 for (i = 0; i < lpwhr->nCustHeaders; i++)
476 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
477 lpwhr->pCustHeaders[i].lpszValue)
479 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
480 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
484 /* Calculate the length of stadard request headers */
485 for (i = 0; i <= HTTP_QUERY_MAX; i++)
487 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
488 lpwhr->StdHeaders[i].lpszValue)
490 size += strlen(lpwhr->StdHeaders[i].lpszField) +
491 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
494 size += delim;
496 if (size + 1 > *lpdwBufferLength)
498 *lpdwBufferLength = size + 1;
499 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
500 goto lend;
503 /* Append standard request heades */
504 for (i = 0; i <= HTTP_QUERY_MAX; i++)
506 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
507 lpwhr->StdHeaders[i].lpszField &&
508 lpwhr->StdHeaders[i].lpszValue)
510 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
511 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
515 /* Append custom request heades */
516 for (i = 0; i < lpwhr->nCustHeaders; i++)
518 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
519 lpwhr->pCustHeaders[i].lpszField &&
520 lpwhr->pCustHeaders[i].lpszValue)
522 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
523 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
524 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
528 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
530 *lpdwBufferLength = cnt + delim;
531 bSuccess = TRUE;
532 goto lend;
534 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
536 lphttpHdr = &lpwhr->StdHeaders[index];
538 else
539 goto lend;
542 /* Ensure header satisifies requested attributes */
543 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
544 (~lphttpHdr->wFlags & HDR_ISREQUEST))
545 goto lend;
547 /* coalesce value to reuqested type */
548 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
550 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
551 bSuccess = TRUE;
553 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
555 time_t tmpTime;
556 struct tm tmpTM;
557 SYSTEMTIME *STHook;
559 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
561 tmpTM = *gmtime(&tmpTime);
562 STHook = (SYSTEMTIME *) lpBuffer;
563 if(STHook==NULL)
564 goto lend;
566 STHook->wDay = tmpTM.tm_mday;
567 STHook->wHour = tmpTM.tm_hour;
568 STHook->wMilliseconds = 0;
569 STHook->wMinute = tmpTM.tm_min;
570 STHook->wDayOfWeek = tmpTM.tm_wday;
571 STHook->wMonth = tmpTM.tm_mon + 1;
572 STHook->wSecond = tmpTM.tm_sec;
573 STHook->wYear = tmpTM.tm_year;
575 bSuccess = TRUE;
577 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
579 if (*lpdwIndex >= lphttpHdr->wCount)
581 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
583 else
585 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
586 (*lpdwIndex)++;
589 else
591 INT len = strlen(lphttpHdr->lpszValue);
593 if (len + 1 > *lpdwBufferLength)
595 *lpdwBufferLength = len + 1;
596 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
597 goto lend;
600 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
601 ((char*)lpBuffer)[len]=0;
602 *lpdwBufferLength = len;
603 bSuccess = TRUE;
606 lend:
607 TRACE("%d <--\n", bSuccess);
608 return bSuccess;
611 /***********************************************************************
612 * HttpQueryInfoW (WININET.@)
614 * Queries for information about an HTTP request
616 * RETURNS
617 * TRUE on success
618 * FALSE on failure
621 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
622 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
624 BOOL result;
625 DWORD charLen=*lpdwBufferLength;
626 char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
627 result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
628 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
629 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
631 memcpy(lpBuffer,tempBuffer,charLen);
633 else
635 int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
636 *lpdwBufferLength=nChars;
638 HeapFree(GetProcessHeap(), 0, tempBuffer);
639 return result;
642 /***********************************************************************
643 * HttpSendRequestExA (WININET.@)
645 * Sends the specified request to the HTTP server and allows chunked
646 * transfers
648 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
649 LPINTERNET_BUFFERSA lpBuffersIn,
650 LPINTERNET_BUFFERSA lpBuffersOut,
651 DWORD dwFlags, DWORD dwContext)
653 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
654 lpBuffersOut, dwFlags, dwContext);
655 return FALSE;
658 /***********************************************************************
659 * HttpSendRequestA (WININET.@)
661 * Sends the specified request to the HTTP server
663 * RETURNS
664 * TRUE on success
665 * FALSE on failure
668 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
669 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
671 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
672 LPWININETHTTPSESSIONA lpwhs = NULL;
673 LPWININETAPPINFOA hIC = NULL;
675 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
677 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
679 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
680 return FALSE;
683 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
684 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
686 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
687 return FALSE;
690 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
691 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
693 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
694 return FALSE;
697 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
699 WORKREQUEST workRequest;
701 workRequest.asyncall = HTTPSENDREQUESTA;
702 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
703 if (lpszHeaders)
704 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
705 else
706 workRequest.LPSZHEADER = 0;
707 workRequest.DWHEADERLENGTH = dwHeaderLength;
708 workRequest.LPOPTIONAL = (DWORD)lpOptional;
709 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
711 INTERNET_AsyncCall(&workRequest);
713 * This is from windows.
715 SetLastError(ERROR_IO_PENDING);
716 return 0;
718 else
720 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
721 dwHeaderLength, lpOptional, dwOptionalLength);
725 /***********************************************************************
726 * HttpSendRequestW (WININET.@)
728 * Sends the specified request to the HTTP server
730 * RETURNS
731 * TRUE on success
732 * FALSE on failure
735 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
736 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
738 BOOL result;
739 char* szHeaders=NULL;
740 DWORD nLen=dwHeaderLength;
741 if(lpszHeaders!=NULL)
743 if(nLen==-1)
744 nLen=strlenW(lpszHeaders);
745 szHeaders=(char*)malloc(nLen+1);
746 WideCharToMultiByte(CP_ACP,0,lpszHeaders,nLen,szHeaders,nLen,NULL,NULL);
748 result=HttpSendRequestA(hHttpRequest, szHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
749 if(szHeaders!=NULL)
750 free(szHeaders);
751 return result;
754 /***********************************************************************
755 * HTTP_HandleRedirect (internal)
757 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
758 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
760 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
761 LPWININETAPPINFOA hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
762 char path[2048];
763 if(lpszUrl[0]=='/')
765 /* if it's an absolute path, keep the same session info */
766 strcpy(path,lpszUrl);
768 else
770 URL_COMPONENTSA urlComponents;
771 char protocol[32], hostName[MAXHOSTNAME], userName[1024];
772 char password[1024], extra[1024];
773 urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
774 urlComponents.lpszScheme = protocol;
775 urlComponents.dwSchemeLength = 32;
776 urlComponents.lpszHostName = hostName;
777 urlComponents.dwHostNameLength = MAXHOSTNAME;
778 urlComponents.lpszUserName = userName;
779 urlComponents.dwUserNameLength = 1024;
780 urlComponents.lpszPassword = password;
781 urlComponents.dwPasswordLength = 1024;
782 urlComponents.lpszUrlPath = path;
783 urlComponents.dwUrlPathLength = 2048;
784 urlComponents.lpszExtraInfo = extra;
785 urlComponents.dwExtraInfoLength = 1024;
786 if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
787 return FALSE;
789 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
790 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
792 /* consider the current host as the referef */
793 if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
794 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
796 if (NULL != lpwhs->lpszServerName)
797 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
798 lpwhs->lpszServerName = HTTP_strdup(hostName);
799 if (NULL != lpwhs->lpszUserName)
800 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
801 lpwhs->lpszUserName = HTTP_strdup(userName);
802 lpwhs->nServerPort = urlComponents.nPort;
804 if (NULL != lpwhr->lpszHostName)
805 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
806 lpwhr->lpszHostName=HTTP_strdup(hostName);
808 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
809 INTERNET_STATUS_RESOLVING_NAME,
810 lpwhs->lpszServerName,
811 strlen(lpwhs->lpszServerName)+1);
813 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
814 &lpwhs->phostent, &lpwhs->socketAddress))
816 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
817 return FALSE;
820 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
821 INTERNET_STATUS_NAME_RESOLVED,
822 &(lpwhs->socketAddress),
823 sizeof(struct sockaddr_in));
827 if(lpwhr->lpszPath)
828 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
829 lpwhr->lpszPath=NULL;
830 if (strlen(path))
832 DWORD needed = 0;
833 HRESULT rc;
834 rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
835 if (rc != E_POINTER)
836 needed = strlen(path)+1;
837 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
838 rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
839 URL_ESCAPE_SPACES_ONLY);
840 if (rc)
842 ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
843 strcpy(lpwhr->lpszPath,path);
847 return HttpSendRequestA((HINTERNET)lpwhr, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
850 /***********************************************************************
851 * HTTP_HttpSendRequestA (internal)
853 * Sends the specified request to the HTTP server
855 * RETURNS
856 * TRUE on success
857 * FALSE on failure
860 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
861 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
863 INT cnt;
864 INT i;
865 BOOL bSuccess = FALSE;
866 LPSTR requestString = NULL;
867 INT requestStringLen;
868 INT responseLen;
869 INT headerLength = 0;
870 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
871 LPWININETHTTPSESSIONA lpwhs = NULL;
872 LPWININETAPPINFOA hIC = NULL;
874 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
876 /* Verify our tree of internet handles */
877 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
879 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
880 return FALSE;
883 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
884 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
886 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
887 return FALSE;
890 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
891 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
893 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
894 return FALSE;
897 /* Clear any error information */
898 INTERNET_SetLastError(0);
901 /* We must have a verb */
902 if (NULL == lpwhr->lpszVerb)
904 goto lend;
907 /* If we don't have a path we set it to root */
908 if (NULL == lpwhr->lpszPath)
909 lpwhr->lpszPath = HTTP_strdup("/");
911 if(lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
913 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
914 *fixurl = '/';
915 strcpy(fixurl + 1, lpwhr->lpszPath);
916 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
917 lpwhr->lpszPath = fixurl;
920 /* Calculate length of request string */
921 requestStringLen =
922 strlen(lpwhr->lpszVerb) +
923 strlen(lpwhr->lpszPath) +
924 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
925 strlen(HTTPHEADER) +
926 5; /* " \r\n\r\n" */
928 /* Add length of passed headers */
929 if (lpszHeaders)
931 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
932 requestStringLen += headerLength + 2; /* \r\n */
935 /* Calculate length of custom request headers */
936 for (i = 0; i < lpwhr->nCustHeaders; i++)
938 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
940 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
941 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
945 /* Calculate the length of standard request headers */
946 for (i = 0; i <= HTTP_QUERY_MAX; i++)
948 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
950 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
951 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
955 /* Allocate string to hold entire request */
956 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
957 if (NULL == requestString)
959 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
960 goto lend;
963 /* Build request string */
964 cnt = sprintf(requestString, "%s %s%s%s",
965 lpwhr->lpszVerb,
966 lpwhr->lpszPath,
967 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
968 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
970 /* Append standard request headers */
971 for (i = 0; i <= HTTP_QUERY_MAX; i++)
973 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
975 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
976 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
977 TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
981 /* Append custom request heades */
982 for (i = 0; i < lpwhr->nCustHeaders; i++)
984 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
986 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
987 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
988 TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
992 /* Append passed request headers */
993 if (lpszHeaders)
995 strcpy(requestString + cnt, "\r\n");
996 cnt += 2;
997 strcpy(requestString + cnt, lpszHeaders);
998 cnt += headerLength;
1001 /* Set termination string for request */
1002 strcpy(requestString + cnt, "\r\n\r\n");
1004 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1005 /* Send the request and store the results */
1006 if (!HTTP_OpenConnection(lpwhr))
1007 goto lend;
1009 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1010 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1012 cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0);
1014 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1015 INTERNET_STATUS_REQUEST_SENT,
1016 &requestStringLen,sizeof(DWORD));
1018 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1019 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1021 if (cnt < 0)
1022 goto lend;
1024 responseLen = HTTP_GetResponseHeaders(lpwhr);
1025 if (responseLen)
1026 bSuccess = TRUE;
1028 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1029 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1030 sizeof(DWORD));
1032 lend:
1034 if (requestString)
1035 HeapFree(GetProcessHeap(), 0, requestString);
1037 /* TODO: send notification for P3P header */
1039 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1041 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1042 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1043 (dwCode==302 || dwCode==301))
1045 char szNewLocation[2048];
1046 DWORD dwBufferSize=2048;
1047 dwIndex=0;
1048 if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1050 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1051 INTERNET_STATUS_REDIRECT, szNewLocation,
1052 dwBufferSize);
1053 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1054 dwHeaderLength, lpOptional, dwOptionalLength);
1059 if (hIC->lpfnStatusCB)
1061 INTERNET_ASYNC_RESULT iar;
1063 iar.dwResult = (DWORD)bSuccess;
1064 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1066 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1067 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1068 sizeof(INTERNET_ASYNC_RESULT));
1071 TRACE("<--\n");
1072 return bSuccess;
1076 /***********************************************************************
1077 * HTTP_Connect (internal)
1079 * Create http session handle
1081 * RETURNS
1082 * HINTERNET a session handle on success
1083 * NULL on failure
1086 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1087 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1088 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1090 BOOL bSuccess = FALSE;
1091 LPWININETAPPINFOA hIC = NULL;
1092 LPWININETHTTPSESSIONA lpwhs = NULL;
1094 TRACE("-->\n");
1096 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1097 goto lerror;
1099 hIC = (LPWININETAPPINFOA) hInternet;
1100 hIC->hdr.dwContext = dwContext;
1102 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1103 if (NULL == lpwhs)
1105 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1106 goto lerror;
1110 * According to my tests. The name is not resolved until a request is sent
1113 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1114 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1116 lpwhs->hdr.htype = WH_HHTTPSESSION;
1117 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1118 lpwhs->hdr.dwFlags = dwFlags;
1119 lpwhs->hdr.dwContext = dwContext;
1120 if (NULL != lpszServerName)
1121 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
1122 if (NULL != lpszUserName)
1123 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
1124 lpwhs->nServerPort = nServerPort;
1126 if (hIC->lpfnStatusCB)
1128 INTERNET_ASYNC_RESULT iar;
1130 iar.dwResult = (DWORD)lpwhs;
1131 iar.dwError = ERROR_SUCCESS;
1133 SendAsyncCallback(hIC, hInternet, dwContext,
1134 INTERNET_STATUS_HANDLE_CREATED, &iar,
1135 sizeof(INTERNET_ASYNC_RESULT));
1138 bSuccess = TRUE;
1140 lerror:
1141 if (!bSuccess && lpwhs)
1143 HeapFree(GetProcessHeap(), 0, lpwhs);
1144 lpwhs = NULL;
1148 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1149 * windows
1152 TRACE("<--\n");
1153 return (HINTERNET)lpwhs;
1157 /***********************************************************************
1158 * HTTP_OpenConnection (internal)
1160 * Connect to a web server
1162 * RETURNS
1164 * TRUE on success
1165 * FALSE on failure
1167 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1169 BOOL bSuccess = FALSE;
1170 INT result;
1171 LPWININETHTTPSESSIONA lpwhs;
1172 LPWININETAPPINFOA hIC = NULL;
1174 TRACE("-->\n");
1177 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1179 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1180 goto lend;
1183 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1185 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1186 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1187 INTERNET_STATUS_CONNECTING_TO_SERVER,
1188 &(lpwhs->socketAddress),
1189 sizeof(struct sockaddr_in));
1191 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
1192 if (lpwhr->nSocketFD == -1)
1194 WARN("Socket creation failed\n");
1195 goto lend;
1198 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
1199 sizeof(lpwhs->socketAddress));
1201 if (result == -1)
1203 WARN("Unable to connect to host (%s)\n", strerror(errno));
1204 goto lend;
1207 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1208 INTERNET_STATUS_CONNECTED_TO_SERVER,
1209 &(lpwhs->socketAddress),
1210 sizeof(struct sockaddr_in));
1212 bSuccess = TRUE;
1214 lend:
1215 TRACE("%d <--\n", bSuccess);
1216 return bSuccess;
1220 /***********************************************************************
1221 * HTTP_GetResponseHeaders (internal)
1223 * Read server response
1225 * RETURNS
1227 * TRUE on success
1228 * FALSE on error
1230 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1232 INT cbreaks = 0;
1233 CHAR buffer[MAX_REPLY_LEN];
1234 DWORD buflen = MAX_REPLY_LEN;
1235 BOOL bSuccess = FALSE;
1236 INT rc = 0;
1237 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1239 TRACE("-->\n");
1241 if (lpwhr->nSocketFD == -1)
1242 goto lend;
1245 * HACK peek at the buffer
1247 rc = recv(lpwhr->nSocketFD,buffer,buflen,MSG_PEEK);
1250 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1252 buflen = MAX_REPLY_LEN;
1253 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1254 goto lend;
1256 if (strncmp(buffer, "HTTP", 4) != 0)
1257 goto lend;
1259 buffer[12]='\0';
1260 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1262 /* Parse each response line */
1265 buflen = MAX_REPLY_LEN;
1266 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1268 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1269 break;
1271 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1273 else
1275 cbreaks++;
1276 if (cbreaks >= 2)
1277 break;
1279 }while(1);
1281 bSuccess = TRUE;
1283 lend:
1285 TRACE("<--\n");
1286 if (bSuccess)
1287 return rc;
1288 else
1289 return FALSE;
1293 /***********************************************************************
1294 * HTTP_InterpretHttpHeader (internal)
1296 * Parse server response
1298 * RETURNS
1300 * TRUE on success
1301 * FALSE on error
1303 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1305 LPCSTR lpsztmp;
1306 INT srclen;
1308 srclen = 0;
1310 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1311 lpszSrc++;
1313 lpsztmp = lpszSrc;
1314 while(*lpsztmp != '\0')
1316 if (*lpsztmp != ' ')
1317 srclen = lpsztmp - lpszSrc + 1;
1319 lpsztmp++;
1322 *len = min(*len, srclen);
1323 strncpy(lpszStart, lpszSrc, *len);
1324 lpszStart[*len] = '\0';
1326 return *len;
1330 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1332 CHAR *pd;
1333 BOOL bSuccess = FALSE;
1335 TRACE("\n");
1337 *field = '\0';
1338 *value = '\0';
1340 pd = strchr(buffer, ':');
1341 if (pd)
1343 *pd = '\0';
1344 if (stripSpaces(buffer, field, &fieldlen) > 0)
1346 if (stripSpaces(pd+1, value, &valuelen) > 0)
1347 bSuccess = TRUE;
1351 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1352 return bSuccess;
1356 /***********************************************************************
1357 * HTTP_GetStdHeaderIndex (internal)
1359 * Lookup field index in standard http header array
1361 * FIXME: This should be stuffed into a hash table
1363 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1365 INT index = -1;
1367 if (!strcasecmp(lpszField, "Content-Length"))
1368 index = HTTP_QUERY_CONTENT_LENGTH;
1369 else if (!strcasecmp(lpszField,"Status"))
1370 index = HTTP_QUERY_STATUS_CODE;
1371 else if (!strcasecmp(lpszField,"Content-Type"))
1372 index = HTTP_QUERY_CONTENT_TYPE;
1373 else if (!strcasecmp(lpszField,"Last-Modified"))
1374 index = HTTP_QUERY_LAST_MODIFIED;
1375 else if (!strcasecmp(lpszField,"Location"))
1376 index = HTTP_QUERY_LOCATION;
1377 else if (!strcasecmp(lpszField,"Accept"))
1378 index = HTTP_QUERY_ACCEPT;
1379 else if (!strcasecmp(lpszField,"Referer"))
1380 index = HTTP_QUERY_REFERER;
1381 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1382 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1383 else if (!strcasecmp(lpszField,"Date"))
1384 index = HTTP_QUERY_DATE;
1385 else if (!strcasecmp(lpszField,"Server"))
1386 index = HTTP_QUERY_SERVER;
1387 else if (!strcasecmp(lpszField,"Connection"))
1388 index = HTTP_QUERY_CONNECTION;
1389 else if (!strcasecmp(lpszField,"ETag"))
1390 index = HTTP_QUERY_ETAG;
1391 else if (!strcasecmp(lpszField,"Accept-Ranges"))
1392 index = HTTP_QUERY_ACCEPT_RANGES;
1393 else if (!strcasecmp(lpszField,"Expires"))
1394 index = HTTP_QUERY_EXPIRES;
1395 else if (!strcasecmp(lpszField,"Mime-Version"))
1396 index = HTTP_QUERY_MIME_VERSION;
1397 else if (!strcasecmp(lpszField,"Pragma"))
1398 index = HTTP_QUERY_PRAGMA;
1399 else if (!strcasecmp(lpszField,"Cache-Control"))
1400 index = HTTP_QUERY_CACHE_CONTROL;
1401 else if (!strcasecmp(lpszField,"Content-Length"))
1402 index = HTTP_QUERY_CONTENT_LENGTH;
1403 else if (!strcasecmp(lpszField,"User-Agent"))
1404 index = HTTP_QUERY_USER_AGENT;
1405 else
1407 TRACE("Couldn't find %s in standard header table\n", lpszField);
1410 return index;
1414 /***********************************************************************
1415 * HTTP_ProcessHeader (internal)
1417 * Stuff header into header tables according to <dwModifier>
1421 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1423 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1425 LPHTTPHEADERA lphttpHdr = NULL;
1426 BOOL bSuccess = FALSE;
1427 INT index;
1429 TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1431 /* Adjust modifier flags */
1432 if (dwModifier & COALESCEFLASG)
1433 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1435 /* Try to get index into standard header array */
1436 index = HTTP_GetStdHeaderIndex(field);
1437 if (index >= 0)
1439 lphttpHdr = &lpwhr->StdHeaders[index];
1441 else /* Find or create new custom header */
1443 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1444 if (index >= 0)
1446 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1448 return FALSE;
1450 lphttpHdr = &lpwhr->pCustHeaders[index];
1452 else
1454 HTTPHEADERA hdr;
1456 hdr.lpszField = (LPSTR)field;
1457 hdr.lpszValue = (LPSTR)value;
1458 hdr.wFlags = hdr.wCount = 0;
1460 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1461 hdr.wFlags |= HDR_ISREQUEST;
1463 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1464 return index >= 0;
1468 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1469 lphttpHdr->wFlags |= HDR_ISREQUEST;
1470 else
1471 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1473 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1475 INT slen;
1477 if (!lpwhr->StdHeaders[index].lpszField)
1479 lphttpHdr->lpszField = HTTP_strdup(field);
1481 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1482 lphttpHdr->wFlags |= HDR_ISREQUEST;
1485 slen = strlen(value) + 1;
1486 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1487 if (lphttpHdr->lpszValue)
1489 memcpy(lphttpHdr->lpszValue, value, slen);
1490 bSuccess = TRUE;
1492 else
1494 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1497 else if (lphttpHdr->lpszValue)
1499 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1501 LPSTR lpsztmp;
1502 INT len;
1504 len = strlen(value);
1506 if (len <= 0)
1508 /* if custom header delete from array */
1509 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1510 lphttpHdr->lpszValue = NULL;
1511 bSuccess = TRUE;
1513 else
1515 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1516 if (lpsztmp)
1518 lphttpHdr->lpszValue = lpsztmp;
1519 strcpy(lpsztmp, value);
1520 bSuccess = TRUE;
1522 else
1524 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1525 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1529 else if (dwModifier & COALESCEFLASG)
1531 LPSTR lpsztmp;
1532 CHAR ch = 0;
1533 INT len = 0;
1534 INT origlen = strlen(lphttpHdr->lpszValue);
1535 INT valuelen = strlen(value);
1537 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1539 ch = ',';
1540 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1542 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1544 ch = ';';
1545 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1548 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
1550 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1551 if (lpsztmp)
1553 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1554 if (ch > 0)
1556 lphttpHdr->lpszValue[origlen] = ch;
1557 origlen++;
1560 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1561 lphttpHdr->lpszValue[len] = '\0';
1562 bSuccess = TRUE;
1564 else
1566 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1567 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1571 TRACE("<-- %d\n",bSuccess);
1572 return bSuccess;
1576 /***********************************************************************
1577 * HTTP_CloseConnection (internal)
1579 * Close socket connection
1582 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1586 LPWININETHTTPSESSIONA lpwhs = NULL;
1587 LPWININETAPPINFOA hIC = NULL;
1589 TRACE("%p\n",lpwhr);
1591 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1592 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1594 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1595 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1597 if (lpwhr->nSocketFD != -1)
1599 close(lpwhr->nSocketFD);
1600 lpwhr->nSocketFD = -1;
1603 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1604 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1608 /***********************************************************************
1609 * HTTP_CloseHTTPRequestHandle (internal)
1611 * Deallocate request handle
1614 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1616 int i;
1617 LPWININETHTTPSESSIONA lpwhs = NULL;
1618 LPWININETAPPINFOA hIC = NULL;
1620 TRACE("\n");
1622 if (lpwhr->nSocketFD != -1)
1623 HTTP_CloseConnection(lpwhr);
1625 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1626 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1628 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1629 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
1630 sizeof(HINTERNET));
1632 if (lpwhr->lpszPath)
1633 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1634 if (lpwhr->lpszVerb)
1635 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1636 if (lpwhr->lpszHostName)
1637 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1639 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1641 if (lpwhr->StdHeaders[i].lpszField)
1642 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1643 if (lpwhr->StdHeaders[i].lpszValue)
1644 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1647 for (i = 0; i < lpwhr->nCustHeaders; i++)
1649 if (lpwhr->pCustHeaders[i].lpszField)
1650 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1651 if (lpwhr->pCustHeaders[i].lpszValue)
1652 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1655 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1656 HeapFree(GetProcessHeap(), 0, lpwhr);
1660 /***********************************************************************
1661 * HTTP_CloseHTTPSessionHandle (internal)
1663 * Deallocate session handle
1666 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1668 LPWININETAPPINFOA hIC = NULL;
1669 TRACE("\n");
1671 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1673 SendAsyncCallback(hIC, lpwhs, lpwhs->hdr.dwContext,
1674 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
1675 sizeof(HINTERNET));
1677 if (lpwhs->lpszServerName)
1678 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1679 if (lpwhs->lpszUserName)
1680 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1681 HeapFree(GetProcessHeap(), 0, lpwhs);
1685 /***********************************************************************
1686 * HTTP_GetCustomHeaderIndex (internal)
1688 * Return index of custom header from header array
1691 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1693 INT index;
1695 TRACE("%s\n", lpszField);
1697 for (index = 0; index < lpwhr->nCustHeaders; index++)
1699 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1700 break;
1704 if (index >= lpwhr->nCustHeaders)
1705 index = -1;
1707 TRACE("Return: %d\n", index);
1708 return index;
1712 /***********************************************************************
1713 * HTTP_InsertCustomHeader (internal)
1715 * Insert header into array
1718 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1720 INT count;
1721 LPHTTPHEADERA lph = NULL;
1723 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1724 count = lpwhr->nCustHeaders + 1;
1725 if (count > 1)
1726 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1727 else
1728 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1730 if (NULL != lph)
1732 lpwhr->pCustHeaders = lph;
1733 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1734 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1735 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1736 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1737 lpwhr->nCustHeaders++;
1739 else
1741 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1742 count = 0;
1745 TRACE("%d <--\n", count-1);
1746 return count - 1;
1750 /***********************************************************************
1751 * HTTP_DeleteCustomHeader (internal)
1753 * Delete header from array
1756 BOOL HTTP_DeleteCustomHeader(INT index)
1758 FIXME("STUB\n");
1759 return FALSE;
1762 /***********************************************************************
1763 * IsHostInProxyBypassList (@)
1765 * Undocumented
1768 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
1770 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
1771 return FALSE;