2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
15 #include "debugtools.h"
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
35 DEFAULT_DEBUG_CHANNEL(wininet);
37 #define HTTPHEADER " HTTP/1.0"
38 #define HTTPHOSTHEADER "\r\nHost: "
39 #define MAXHOSTNAME 100
40 #define MAX_FIELD_VALUE_LEN 256
41 #define MAX_FIELD_LEN 256
44 #define HTTP_REFERER "Referer"
45 #define HTTP_ACCEPT "Accept"
47 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
48 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
49 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
50 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
51 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
52 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
53 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
56 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
57 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
58 void *Buffer, int BytesToWrite);
59 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
60 void *Buffer, int BytesToRead);
61 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
62 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
63 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
64 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
65 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
66 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
67 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
69 inline static LPSTR HTTP_strdup( LPCSTR str )
71 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
72 if (ret) strcpy( ret, str );
76 /***********************************************************************
77 * HttpAddRequestHeadersA (WININET.68)
79 * Adds one or more HTTP header to the request handler
86 INTERNETAPI BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
87 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
92 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
93 BOOL bSuccess = FALSE;
94 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
96 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
98 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
102 buffer = HTTP_strdup(lpszHeader);
109 while (*lpszEnd != '\0')
111 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
116 if (*lpszEnd == '\0')
121 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
122 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
124 lpszStart = lpszEnd + 2; /* Jump over \0\n */
128 HeapFree(GetProcessHeap(), 0, buffer);
133 /***********************************************************************
134 * HttpOpenRequestA (WININET.72)
136 * Open a HTTP request handle
139 * HINTERNET a HTTP request handle on success
143 INTERNETAPI HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
144 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
145 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
146 DWORD dwFlags, DWORD dwContext)
148 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
149 LPWININETAPPINFOA hIC = NULL;
153 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
155 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
159 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
161 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
163 WORKREQUEST workRequest;
165 workRequest.asyncall = HTTPOPENREQUESTA;
166 workRequest.HFTPSESSION = (DWORD)hHttpSession;
167 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
168 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
169 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
170 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
171 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
172 workRequest.DWFLAGS = dwFlags;
173 workRequest.DWCONTEXT = dwContext;
175 return (HINTERNET)INTERNET_AsyncCall(&workRequest);
179 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
180 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
185 /***********************************************************************
186 * HTTP_HttpOpenRequestA (internal)
188 * Open a HTTP request handle
191 * HINTERNET a HTTP request handle on success
195 INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
196 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
197 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
198 DWORD dwFlags, DWORD dwContext)
200 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
201 LPWININETAPPINFOA hIC = NULL;
202 LPWININETHTTPREQA lpwhr;
206 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
208 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
212 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
214 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
217 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
218 return (HINTERNET) NULL;
221 lpwhr->hdr.htype = WH_HHTTPREQ;
222 lpwhr->hdr.lpwhparent = hHttpSession;
223 lpwhr->hdr.dwFlags = dwFlags;
224 lpwhr->hdr.dwContext = dwContext;
225 lpwhr->nSocketFD = INVALID_SOCKET;
227 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
229 UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
230 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
231 UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
232 URL_ESCAPE_SPACES_ONLY);
235 if (NULL != lpszReferrer && strlen(lpszReferrer))
236 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
239 if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
240 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
242 if (NULL == lpszVerb)
243 lpwhr->lpszVerb = HTTP_strdup("GET");
244 else if (strlen(lpszVerb))
245 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
247 if (NULL != lpszReferrer)
249 char buf[MAXHOSTNAME];
250 URL_COMPONENTSA UrlComponents;
252 UrlComponents.lpszExtraInfo = NULL;
253 UrlComponents.lpszPassword = NULL;
254 UrlComponents.lpszScheme = NULL;
255 UrlComponents.lpszUrlPath = NULL;
256 UrlComponents.lpszUserName = NULL;
257 UrlComponents.lpszHostName = buf;
258 UrlComponents.dwHostNameLength = MAXHOSTNAME;
260 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
261 if (strlen(UrlComponents.lpszHostName))
262 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
264 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
267 if (hIC->lpfnStatusCB)
269 INTERNET_ASYNC_RESULT iar;
271 iar.dwResult = (DWORD)lpwhr;
272 iar.dwError = ERROR_SUCCESS;
274 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_HANDLE_CREATED,
275 &iar, sizeof(INTERNET_ASYNC_RESULT));
278 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
280 INTERNET_ASYNC_RESULT iar;
282 iar.dwResult = (DWORD)lpwhr;
283 iar.dwError = lpwhr ? ERROR_SUCCESS : INTERNET_GetLastError();
284 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
285 &iar, sizeof(INTERNET_ASYNC_RESULT));
288 return (HINTERNET) lpwhr;
292 /***********************************************************************
293 * HttpQueryInfoA (WININET.74)
295 * Queries for information about an HTTP request
302 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
303 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
305 LPHTTPHEADERA lphttpHdr = NULL;
306 BOOL bSuccess = FALSE;
307 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
309 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
311 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
313 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
317 /* Find requested header structure */
318 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
320 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
325 lphttpHdr = &lpwhr->pCustHeaders[index];
329 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
331 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
333 INT i, delim, size = 0, cnt = 0;
335 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
337 /* Calculate length of custom reuqest headers */
338 for (i = 0; i < lpwhr->nCustHeaders; i++)
340 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
341 lpwhr->pCustHeaders[i].lpszValue)
343 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
344 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
348 /* Calculate the length of stadard request headers */
349 for (i = 0; i <= HTTP_QUERY_MAX; i++)
351 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
352 lpwhr->StdHeaders[i].lpszValue)
354 size += strlen(lpwhr->StdHeaders[i].lpszField) +
355 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
361 if (size + 1 > *lpdwBufferLength)
363 *lpdwBufferLength = size + 1;
364 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
368 /* Append standard request heades */
369 for (i = 0; i <= HTTP_QUERY_MAX; i++)
371 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
372 lpwhr->StdHeaders[i].lpszField &&
373 lpwhr->StdHeaders[i].lpszValue)
375 cnt += sprintf(lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
376 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
380 /* Append custom request heades */
381 for (i = 0; i < lpwhr->nCustHeaders; i++)
383 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
384 lpwhr->pCustHeaders[i].lpszField &&
385 lpwhr->pCustHeaders[i].lpszValue)
387 cnt += sprintf(lpBuffer + cnt, "%s: %s%s",
388 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
389 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
393 strcpy(lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
395 *lpdwBufferLength = cnt + delim;
399 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
401 lphttpHdr = &lpwhr->StdHeaders[index];
407 /* Ensure header satisifies requested attributes */
408 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
409 (~lphttpHdr->wFlags & HDR_ISREQUEST))
412 /* coalesce value to reuqested type */
413 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
415 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
418 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
424 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
426 tmpTM = *gmtime(&tmpTime);
427 STHook = (SYSTEMTIME *) lpBuffer;
431 STHook->wDay = tmpTM.tm_mday;
432 STHook->wHour = tmpTM.tm_hour;
433 STHook->wMilliseconds = 0;
434 STHook->wMinute = tmpTM.tm_min;
435 STHook->wDayOfWeek = tmpTM.tm_wday;
436 STHook->wMonth = tmpTM.tm_mon + 1;
437 STHook->wSecond = tmpTM.tm_sec;
438 STHook->wYear = tmpTM.tm_year;
442 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
444 if (*lpdwIndex >= lphttpHdr->wCount)
446 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
450 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
456 INT len = strlen(lphttpHdr->lpszValue);
458 if (len + 1 > *lpdwBufferLength)
460 *lpdwBufferLength = len + 1;
461 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
465 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
466 *lpdwBufferLength = len;
471 TRACE("%d <--\n", bSuccess);
476 /***********************************************************************
477 * HttpSendRequestExA (WININET)
479 * Sends the specified request to the HTTP server and allows chunked
482 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
483 LPINTERNET_BUFFERSA lpBuffersIn,
484 LPINTERNET_BUFFERSA lpBuffersOut,
485 DWORD dwFlags, DWORD dwContext)
487 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
488 lpBuffersOut, dwFlags, dwContext);
492 /***********************************************************************
493 * HttpSendRequestA (WININET.76)
495 * Sends the specified request to the HTTP server
502 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
503 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
505 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
506 LPWININETHTTPSESSIONA lpwhs = NULL;
507 LPWININETAPPINFOA hIC = NULL;
509 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
511 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
513 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
517 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
518 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
520 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
524 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
525 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
527 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
531 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
533 WORKREQUEST workRequest;
535 workRequest.asyncall = HTTPSENDREQUESTA;
536 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
537 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
538 workRequest.DWHEADERLENGTH = dwHeaderLength;
539 workRequest.LPOPTIONAL = (DWORD)lpOptional;
540 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
542 return INTERNET_AsyncCall(&workRequest);
546 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
547 dwHeaderLength, lpOptional, dwOptionalLength);
552 /***********************************************************************
553 * HTTP_HttpSendRequestA (internal)
555 * Sends the specified request to the HTTP server
562 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
563 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
567 BOOL bSuccess = FALSE;
568 LPSTR requestString = NULL;
569 INT requestStringLen;
570 INT headerLength = 0;
571 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
572 LPWININETHTTPSESSIONA lpwhs = NULL;
573 LPWININETAPPINFOA hIC = NULL;
575 TRACE("0x%08lx\n", (ULONG)hHttpRequest);
577 /* Verify our tree of internet handles */
578 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
580 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
584 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
585 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
587 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
591 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
592 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
594 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
598 /* Clear any error information */
599 INTERNET_SetLastError(0);
601 /* We must have a verb */
602 if (NULL == lpwhr->lpszVerb)
607 /* If we don't have a path we set it to root */
608 if (NULL == lpwhr->lpszPath)
609 lpwhr->lpszPath = HTTP_strdup("/");
611 /* Calculate length of request string */
613 strlen(lpwhr->lpszVerb) +
614 strlen(lpwhr->lpszPath) +
615 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
619 /* Add length of passed headers */
622 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
623 requestStringLen += headerLength + 2; /* \r\n */
626 /* Calculate length of custom request headers */
627 for (i = 0; i < lpwhr->nCustHeaders; i++)
629 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
631 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
632 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
636 /* Calculate the length of standard request headers */
637 for (i = 0; i <= HTTP_QUERY_MAX; i++)
639 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
641 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
642 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
646 /* Allocate string to hold entire request */
647 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
648 if (NULL == requestString)
650 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
654 /* Build request string */
655 cnt = sprintf(requestString, "%s %s%s%s",
658 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
659 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
661 /* Append standard request headers */
662 for (i = 0; i <= HTTP_QUERY_MAX; i++)
664 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
666 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
667 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
671 /* Append custom request heades */
672 for (i = 0; i < lpwhr->nCustHeaders; i++)
674 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
676 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
677 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
681 /* Append passed request headers */
684 strcpy(requestString + cnt, "\r\n");
686 strcpy(requestString + cnt, lpszHeaders);
690 /* Set termination string for request */
691 strcpy(requestString + cnt, "\r\n\r\n");
693 if (hIC->lpfnStatusCB)
694 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
696 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
697 /* Send the request and store the results */
698 if (!HTTP_OpenConnection(lpwhr))
701 cnt = INTERNET_WriteDataToStream(lpwhr->nSocketFD, requestString, requestStringLen);
706 if (HTTP_GetResponseHeaders(lpwhr))
712 HeapFree(GetProcessHeap(), 0, requestString);
714 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
716 INTERNET_ASYNC_RESULT iar;
718 iar.dwResult = (DWORD)bSuccess;
719 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
720 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
721 &iar, sizeof(INTERNET_ASYNC_RESULT));
729 /***********************************************************************
730 * HTTP_Connect (internal)
732 * Create http session handle
735 * HINTERNET a session handle on success
739 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
740 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
741 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
743 BOOL bSuccess = FALSE;
744 LPWININETAPPINFOA hIC = NULL;
745 LPWININETHTTPSESSIONA lpwhs = NULL;
749 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
752 hIC = (LPWININETAPPINFOA) hInternet;
754 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
757 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
761 if (hIC->lpfnStatusCB)
762 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
763 (LPVOID)lpszServerName, strlen(lpszServerName));
765 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
766 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
768 if (!GetAddress(lpszServerName, nServerPort, &lpwhs->phostent, &lpwhs->socketAddress))
770 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
774 if (hIC->lpfnStatusCB)
775 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
776 (LPVOID)lpszServerName, strlen(lpszServerName));
778 lpwhs->hdr.htype = WH_HHTTPSESSION;
779 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
780 lpwhs->hdr.dwFlags = dwFlags;
781 lpwhs->hdr.dwContext = dwContext;
782 if (NULL != lpszServerName)
783 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
784 if (NULL != lpszUserName)
785 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
786 lpwhs->nServerPort = nServerPort;
788 if (hIC->lpfnStatusCB)
790 INTERNET_ASYNC_RESULT iar;
792 iar.dwResult = (DWORD)lpwhs;
793 iar.dwError = ERROR_SUCCESS;
795 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
796 &iar, sizeof(INTERNET_ASYNC_RESULT));
802 if (!bSuccess && lpwhs)
804 HeapFree(GetProcessHeap(), 0, lpwhs);
808 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
810 INTERNET_ASYNC_RESULT iar;
812 iar.dwResult = (DWORD)lpwhs;
813 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
814 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
815 &iar, sizeof(INTERNET_ASYNC_RESULT));
818 return (HINTERNET)lpwhs;
822 /***********************************************************************
823 * HTTP_OpenConnection (internal)
825 * Connect to a web server
832 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
834 BOOL bSuccess = FALSE;
836 LPWININETHTTPSESSIONA lpwhs;
840 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
842 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
846 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
848 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
849 if (INVALID_SOCKET == lpwhr->nSocketFD)
851 WARN("Socket creation failed\n");
855 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
856 sizeof(lpwhs->socketAddress));
858 if (SOCKET_ERROR == result)
860 WARN("Unable to connect to host (%s)\n", strerror(errno));
867 TRACE(": %d\n", bSuccess);
872 /***********************************************************************
873 * HTTP_GetResponseHeaders (internal)
875 * Read server response
882 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
885 CHAR buffer[MAX_REPLY_LEN];
886 DWORD buflen = MAX_REPLY_LEN;
887 BOOL bSuccess = FALSE;
888 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
892 if (INVALID_SOCKET == lpwhr->nSocketFD)
896 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
898 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
901 if (strncmp(buffer, "HTTP", 4) != 0)
905 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
907 /* Parse each response line */
910 buflen = MAX_REPLY_LEN;
911 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
913 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
916 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
934 /***********************************************************************
935 * HTTP_InterpretHttpHeader (internal)
937 * Parse server response
944 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
951 while (*lpszSrc == ' ' && *lpszSrc != '\0')
955 while(*lpsztmp != '\0')
958 srclen = lpsztmp - lpszSrc + 1;
963 *len = min(*len, srclen);
964 strncpy(lpszStart, lpszSrc, *len);
965 lpszStart[*len] = '\0';
971 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
974 BOOL bSuccess = FALSE;
981 pd = strchr(buffer, ':');
985 if (stripSpaces(buffer, field, &fieldlen) > 0)
987 if (stripSpaces(pd+1, value, &valuelen) > 0)
992 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
997 /***********************************************************************
998 * HTTP_GetStdHeaderIndex (internal)
1000 * Lookup field index in standard http header array
1002 * FIXME: This should be stuffed into a hash table
1004 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1008 if (!strcasecmp(lpszField, "Content-Length"))
1009 index = HTTP_QUERY_CONTENT_LENGTH;
1010 else if (!strcasecmp(lpszField,"Status"))
1011 index = HTTP_QUERY_STATUS_CODE;
1012 else if (!strcasecmp(lpszField,"Content-Type"))
1013 index = HTTP_QUERY_CONTENT_TYPE;
1014 else if (!strcasecmp(lpszField,"Last-Modified"))
1015 index = HTTP_QUERY_LAST_MODIFIED;
1016 else if (!strcasecmp(lpszField,"Location"))
1017 index = HTTP_QUERY_LOCATION;
1018 else if (!strcasecmp(lpszField,"Accept"))
1019 index = HTTP_QUERY_ACCEPT;
1020 else if (!strcasecmp(lpszField,"Referer"))
1021 index = HTTP_QUERY_REFERER;
1022 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1023 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1024 else if (!strcasecmp(lpszField,"Date"))
1025 index = HTTP_QUERY_DATE;
1026 else if (!strcasecmp(lpszField,"Server"))
1027 index = HTTP_QUERY_SERVER;
1028 else if (!strcasecmp(lpszField,"Connection"))
1029 index = HTTP_QUERY_CONNECTION;
1030 else if (!strcasecmp(lpszField,"ETag"))
1031 index = HTTP_QUERY_ETAG;
1032 else if (!strcasecmp(lpszField,"Accept-Ranges"))
1033 index = HTTP_QUERY_ACCEPT_RANGES;
1034 else if (!strcasecmp(lpszField,"Expires"))
1035 index = HTTP_QUERY_EXPIRES;
1036 else if (!strcasecmp(lpszField,"Mime-Version"))
1037 index = HTTP_QUERY_MIME_VERSION;
1040 FIXME("Couldn't find %s in standard header table\n", lpszField);
1047 /***********************************************************************
1048 * HTTP_ProcessHeader (internal)
1050 * Stuff header into header tables according to <dwModifier>
1054 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1056 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1058 LPHTTPHEADERA lphttpHdr = NULL;
1059 BOOL bSuccess = FALSE;
1062 TRACE("%s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1064 /* Adjust modifier flags */
1065 if (dwModifier & COALESCEFLASG)
1066 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1068 /* Try to get index into standard header array */
1069 index = HTTP_GetStdHeaderIndex(field);
1072 lphttpHdr = &lpwhr->StdHeaders[index];
1074 else /* Find or create new custom header */
1076 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1079 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1083 lphttpHdr = &lpwhr->pCustHeaders[index];
1089 hdr.lpszField = (LPSTR)field;
1090 hdr.lpszValue = (LPSTR)value;
1091 hdr.wFlags = hdr.wCount = 0;
1093 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1094 hdr.wFlags |= HDR_ISREQUEST;
1096 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1101 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1102 lphttpHdr->wFlags |= HDR_ISREQUEST;
1104 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1106 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1110 if (!lpwhr->StdHeaders[index].lpszField)
1112 lphttpHdr->lpszField = HTTP_strdup(field);
1114 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1115 lphttpHdr->wFlags |= HDR_ISREQUEST;
1118 slen = strlen(value) + 1;
1119 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1120 if (lphttpHdr->lpszValue)
1122 memcpy(lphttpHdr->lpszValue, value, slen);
1127 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1130 else if (lphttpHdr->lpszValue)
1132 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1137 len = strlen(value);
1141 //! if custom header delete from array
1142 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1143 lphttpHdr->lpszValue = NULL;
1148 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1151 lphttpHdr->lpszValue = lpsztmp;
1152 strcpy(lpsztmp, value);
1157 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1161 else if (dwModifier & COALESCEFLASG)
1166 INT origlen = strlen(lphttpHdr->lpszValue);
1167 INT valuelen = strlen(value);
1169 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1172 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1174 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1177 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1180 len = origlen + valuelen + (ch > 0) ? 1 : 0;
1182 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1185 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1188 lphttpHdr->lpszValue[origlen] = ch;
1192 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1193 lphttpHdr->lpszValue[len] = '\0';
1198 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1207 /***********************************************************************
1208 * HTTP_CloseConnection (internal)
1210 * Close socket connection
1213 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1215 if (lpwhr->nSocketFD != INVALID_SOCKET)
1217 close(lpwhr->nSocketFD);
1218 lpwhr->nSocketFD = INVALID_SOCKET;
1223 /***********************************************************************
1224 * HTTP_CloseHTTPRequestHandle (internal)
1226 * Deallocate request handle
1229 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1235 if (lpwhr->nSocketFD != INVALID_SOCKET)
1236 HTTP_CloseConnection(lpwhr);
1238 if (lpwhr->lpszPath)
1239 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1240 if (lpwhr->lpszVerb)
1241 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1242 if (lpwhr->lpszHostName)
1243 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1245 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1247 if (lpwhr->StdHeaders[i].lpszField)
1248 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1249 if (lpwhr->StdHeaders[i].lpszValue)
1250 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1253 for (i = 0; i < lpwhr->nCustHeaders; i++)
1255 if (lpwhr->pCustHeaders[i].lpszField)
1256 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1257 if (lpwhr->pCustHeaders[i].lpszValue)
1258 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1261 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1262 HeapFree(GetProcessHeap(), 0, lpwhr);
1266 /***********************************************************************
1267 * HTTP_CloseHTTPSessionHandle (internal)
1269 * Deallocate session handle
1272 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1276 if (lpwhs->lpszServerName)
1277 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1278 if (lpwhs->lpszUserName)
1279 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1280 HeapFree(GetProcessHeap(), 0, lpwhs);
1284 /***********************************************************************
1285 * HTTP_GetCustomHeaderIndex (internal)
1287 * Return index of custom header from header array
1290 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1294 TRACE("%s\n", lpszField);
1296 for (index = 0; index < lpwhr->nCustHeaders; index++)
1298 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1303 if (index >= lpwhr->nCustHeaders)
1306 TRACE("Return: %d\n", index);
1311 /***********************************************************************
1312 * HTTP_InsertCustomHeader (internal)
1314 * Insert header into array
1317 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1320 LPHTTPHEADERA lph = NULL;
1322 TRACE("%s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1323 count = lpwhr->nCustHeaders + 1;
1325 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1327 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1331 lpwhr->pCustHeaders = lph;
1332 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1333 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1334 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1335 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1336 lpwhr->nCustHeaders++;
1340 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1344 TRACE("%d <--\n", count-1);
1349 /***********************************************************************
1350 * HTTP_DeleteCustomHeader (internal)
1352 * Delete header from array
1355 BOOL HTTP_DeleteCustomHeader(INT index)