HTTP protocol now supported, InternetCrackUrl fixed, lots of other
fixes.
diff --git a/dlls/wininet/Makefile.in b/dlls/wininet/Makefile.in
index 1bab617..1d79677 100644
--- a/dlls/wininet/Makefile.in
+++ b/dlls/wininet/Makefile.in
@@ -8,6 +8,7 @@
SPEC_SRCS = wininet.spec
C_SRCS = \
+ http.c \
internet.c \
ftp.c \
utility.c \
diff --git a/dlls/wininet/ftp.c b/dlls/wininet/ftp.c
index 031ff31..b6f1ca9 100644
--- a/dlls/wininet/ftp.c
+++ b/dlls/wininet/ftp.c
@@ -21,10 +21,13 @@
#include <sys/stat.h>
#include <unistd.h>
-#include "windows.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
#include "wininet.h"
#include "winerror.h"
#include "winsock.h"
+#include "heap.h"
#include "debugtools.h"
#include "internet.h"
@@ -35,7 +38,6 @@
#define DATA_PACKET_SIZE 0x2000
#define szCRLF "\r\n"
#define MAX_BACKLOG 5
-#define RESPONSE_TIMEOUT 30
typedef enum {
/* FTP commands with arguments. */
@@ -103,7 +105,6 @@
BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
-LPSTR FTP_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer);
DWORD FTP_SetResponseError(DWORD dwResponse);
/***********************************************************************
@@ -135,8 +136,8 @@
workRequest.asyncall = FTPPUTFILEA;
workRequest.HFTPSESSION = (DWORD)hConnect;
- workRequest.LPSZLOCALFILE = (DWORD)strdup(lpszLocalFile);
- workRequest.LPSZNEWREMOTEFILE = (DWORD)strdup(lpszNewRemoteFile);
+ workRequest.LPSZLOCALFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszLocalFile);
+ workRequest.LPSZNEWREMOTEFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszNewRemoteFile);
workRequest.DWFLAGS = dwFlags;
workRequest.DWCONTEXT = dwContext;
@@ -250,7 +251,7 @@
workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
workRequest.HFTPSESSION = (DWORD)hConnect;
- workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
+ workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
return INTERNET_AsyncCall(&workRequest);
}
@@ -347,7 +348,7 @@
workRequest.asyncall = FTPCREATEDIRECTORYA;
workRequest.HFTPSESSION = (DWORD)hConnect;
- workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
+ workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
return INTERNET_AsyncCall(&workRequest);
}
@@ -443,7 +444,7 @@
workRequest.asyncall = FTPFINDFIRSTFILEA;
workRequest.HFTPSESSION = (DWORD)hConnect;
- workRequest.LPSZSEARCHFILE = (DWORD)strdup(lpszSearchFile);
+ workRequest.LPSZSEARCHFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszSearchFile);
workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
workRequest.DWFLAGS = dwFlags;
workRequest.DWCONTEXT= dwContext;
@@ -706,7 +707,7 @@
workRequest.asyncall = FTPOPENFILEA;
workRequest.HFTPSESSION = (DWORD)hFtpSession;
- workRequest.LPSZFILENAME = (DWORD)strdup(lpszFileName);
+ workRequest.LPSZFILENAME = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszFileName);
workRequest.FDWACCESS = fdwAccess;
workRequest.DWFLAGS = dwFlags;
workRequest.DWCONTEXT = dwContext;
@@ -827,8 +828,8 @@
workRequest.asyncall = FTPGETFILEA;
workRequest.HFTPSESSION = (DWORD)hInternet;
- workRequest.LPSZREMOTEFILE = (DWORD)strdup(lpszRemoteFile);
- workRequest.LPSZNEWFILE = (DWORD)strdup(lpszNewFile);
+ workRequest.LPSZREMOTEFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszRemoteFile);
+ workRequest.LPSZNEWFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszNewFile);
workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
workRequest.DWFLAGS = dwInternetFlags;
@@ -954,7 +955,7 @@
workRequest.asyncall = FTPRENAMEFILEA;
workRequest.HFTPSESSION = (DWORD)hFtpSession;
- workRequest.LPSZFILENAME = (DWORD)strdup(lpszFileName);
+ workRequest.LPSZFILENAME = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszFileName);
return INTERNET_AsyncCall(&workRequest);
}
@@ -1048,7 +1049,7 @@
workRequest.asyncall = FTPREMOVEDIRECTORYA;
workRequest.HFTPSESSION = (DWORD)hFtpSession;
- workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
+ workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
return INTERNET_AsyncCall(&workRequest);
}
@@ -1143,8 +1144,8 @@
workRequest.asyncall = FTPRENAMEFILEA;
workRequest.HFTPSESSION = (DWORD)hFtpSession;
- workRequest.LPSZSRCFILE = (DWORD)strdup(lpszSrc);
- workRequest.LPSZDESTFILE = (DWORD)strdup(lpszDest);
+ workRequest.LPSZSRCFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszSrc);
+ workRequest.LPSZDESTFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDest);
return INTERNET_AsyncCall(&workRequest);
}
@@ -1309,13 +1310,13 @@
if (NULL == lpszUserName)
{
- lpwfs->lpszUserName = strdup("anonymous");
- lpwfs->lpszPassword = strdup("user@server");
+ lpwfs->lpszUserName = HEAP_strdupA(GetProcessHeap(),0,"anonymous");
+ lpwfs->lpszPassword = HEAP_strdupA(GetProcessHeap(),0,"user@server");
}
else
{
- lpwfs->lpszUserName = strdup(lpszUserName);
- lpwfs->lpszPassword = strdup(lpszPassword);
+ lpwfs->lpszUserName = HEAP_strdupA(GetProcessHeap(),0,lpszUserName);
+ lpwfs->lpszPassword = HEAP_strdupA(GetProcessHeap(),0,lpszPassword);
}
if (FTP_ConnectToHost(lpwfs))
@@ -1481,7 +1482,7 @@
while(1)
{
nRecv = dwResponse;
- if (!FTP_GetNextLine(nSocket, lpszResponse, &nRecv))
+ if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
goto lerror;
if (nRecv >= 3 && lpszResponse[3] != '-')
@@ -2177,7 +2178,7 @@
goto lend;
}
- while ((pszLine = FTP_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
+ while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
{
if (sizeFilePropArray <= indexFilePropArray)
{
@@ -2272,7 +2273,7 @@
pszToken = strtok(NULL, " \t");
if(pszToken != NULL)
{
- curFileProp->lpszName = strdup(pszToken);
+ curFileProp->lpszName = HEAP_strdupA(GetProcessHeap(),0,pszToken);
TRACE(": %s\n", curFileProp->lpszName);
}
@@ -2371,71 +2372,6 @@
/***********************************************************************
- * FTP_GetNextLine (internal)
- *
- * Parse next line in directory string listing
- *
- * RETURNS
- * Pointer to begining of next line
- * NULL on failure
- *
- */
-
-LPSTR FTP_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
-{
- struct timeval tv;
- fd_set infd;
- BOOL bSuccess = FALSE;
- INT nRecv = 0;
-
- TRACE("\n");
-
- while (nRecv < *dwBuffer)
- {
- FD_ZERO(&infd);
- FD_SET(nSocket, &infd);
- tv.tv_sec=RESPONSE_TIMEOUT;
- tv.tv_usec=0;
-
- if (select(nSocket+1,&infd,NULL,NULL,&tv))
- {
- if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
- {
- INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
- goto lend;
- }
-
- if (lpszBuffer[nRecv] == '\n')
- {
- bSuccess = TRUE;
- break;
- }
- if (lpszBuffer[nRecv] != '\r')
- nRecv++;
- }
- else
- {
- INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
- goto lend;
- }
- }
-
-lend:
- if (bSuccess)
- {
- lpszBuffer[nRecv] = '\0';
- *dwBuffer = nRecv - 1;
- TRACE(":%d %s\n", nRecv, lpszBuffer);
- return lpszBuffer;
- }
- else
- {
- return NULL;
- }
-}
-
-
-/***********************************************************************
* FTP_SetResponseError (internal)
*
* Set the appropriate error code for a given response from the server
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
new file mode 100644
index 0000000..35e68d0
--- /dev/null
+++ b/dlls/wininet/http.c
@@ -0,0 +1,1306 @@
+/*
+ * Wininet - Http Implementation
+ *
+ * Copyright 1999 Corel Corporation
+ *
+ * Ulrich Czekalla
+ *
+ */
+
+#include "windows.h"
+#include "wininet.h"
+#include "debugtools.h"
+#include "winerror.h"
+#include "heap.h"
+#include "tchar.h"
+#include "winsock.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "internet.h"
+
+DEFAULT_DEBUG_CHANNEL(wininet)
+
+#define HTTPHEADER " HTTP/1.0"
+#define HTTPHOSTHEADER "\r\nHost: "
+#define MAXHOSTNAME 100
+#define MAX_FIELD_VALUE_LEN 256
+#define MAX_FIELD_LEN 256
+
+
+#define HTTP_REFERER "Referer"
+#define HTTP_ACCEPT "Accept"
+
+#define HTTP_ADDHDR_FLAG_ADD 0x20000000
+#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
+#define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
+#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
+#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
+#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
+#define HTTP_ADDHDR_FLAG_REQ 0x02000000
+
+
+BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
+int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
+ void *Buffer, int BytesToWrite);
+int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
+ void *Buffer, int BytesToRead);
+BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
+BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
+void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
+BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
+INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
+INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
+INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
+
+/***********************************************************************
+ * HttpAddRequestHeadersA (WININET.68)
+ *
+ * Adds one or more HTTP header to the request handler
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+INTERNETAPI BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
+ LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
+{
+ LPSTR lpszStart;
+ LPSTR lpszEnd;
+ LPSTR buffer;
+ CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
+ BOOL bSuccess = FALSE;
+ LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
+
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ buffer = HEAP_strdupA(GetProcessHeap(), 0, lpszHeader);
+ lpszStart = buffer;
+
+ do
+ {
+ lpszEnd = lpszStart;
+
+ while (*lpszEnd != '\0')
+ {
+ if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
+ break;
+ lpszEnd++;
+ }
+
+ if (*lpszEnd == '\0')
+ break;
+
+ *lpszEnd = '\0';
+
+ if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
+ bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
+
+ lpszStart = lpszEnd + 2; /* Jump over \0\n */
+
+ } while (bSuccess);
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HttpOpenRequestA (WININET.72)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
+ *
+ */
+INTERNETAPI HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
+ LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+ LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD dwContext)
+{
+ LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
+ LPWININETAPPINFOA hIC = NULL;
+
+ TRACE("\n");
+
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
+
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+ {
+ WORKREQUEST workRequest;
+
+ workRequest.asyncall = HTTPOPENREQUESTA;
+ workRequest.HFTPSESSION = (DWORD)hHttpSession;
+ workRequest.LPSZVERB = (DWORD)HEAP_strdupA(GetProcessHeap(), 0, lpszVerb);
+ workRequest.LPSZOBJECTNAME = (DWORD)HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName);
+ workRequest.LPSZVERSION = (DWORD)HEAP_strdupA(GetProcessHeap(), 0, lpszVersion);
+ workRequest.LPSZREFERRER = (DWORD)HEAP_strdupA(GetProcessHeap(), 0, lpszReferrer);
+ workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
+ workRequest.DWFLAGS = dwFlags;
+ workRequest.DWCONTEXT = dwContext;
+
+ return (HINTERNET)INTERNET_AsyncCall(&workRequest);
+ }
+ else
+ {
+ return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
+ lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
+ }
+}
+
+
+/***********************************************************************
+ * HTTP_HttpOpenRequestA (internal)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
+ *
+ */
+INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
+ LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+ LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD dwContext)
+{
+ LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
+ LPWININETAPPINFOA hIC = NULL;
+ LPWININETHTTPREQA lpwhr;
+
+ TRACE("\n");
+
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
+
+ lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
+ if (NULL == lpwhr)
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ return (HINTERNET) NULL;
+ }
+
+ lpwhr->hdr.htype = WH_HHTTPREQ;
+ lpwhr->hdr.lpwhparent = hHttpSession;
+ lpwhr->hdr.dwFlags = dwFlags;
+ lpwhr->hdr.dwContext = dwContext;
+
+ if (NULL != lpszObjectName && strlen(lpszObjectName))
+ lpwhr->lpszPath = HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName);
+
+ if (NULL != lpszReferrer && strlen(lpszReferrer))
+ HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
+
+ //! FIXME
+ if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
+ HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
+
+ if (NULL == lpszVerb)
+ lpwhr->lpszVerb = HEAP_strdupA(GetProcessHeap(), 0, "GET");
+ else if (strlen(lpszVerb))
+ lpwhr->lpszVerb = HEAP_strdupA(GetProcessHeap(), 0, lpszVerb);
+
+ if (NULL != lpszReferrer)
+ {
+ char buf[MAXHOSTNAME];
+ URL_COMPONENTSA UrlComponents;
+
+ UrlComponents.lpszExtraInfo = NULL;
+ UrlComponents.lpszPassword = NULL;
+ UrlComponents.lpszScheme = NULL;
+ UrlComponents.lpszUrlPath = NULL;
+ UrlComponents.lpszUserName = NULL;
+ UrlComponents.lpszHostName = buf;
+ UrlComponents.dwHostNameLength = MAXHOSTNAME;
+
+ InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
+ if (strlen(UrlComponents.lpszHostName))
+ lpwhr->lpszHostName = HEAP_strdupA(GetProcessHeap(), 0, UrlComponents.lpszHostName);
+ }
+
+ if (hIC->lpfnStatusCB)
+ {
+ INTERNET_ASYNC_RESULT iar;
+
+ iar.dwResult = (DWORD)lpwhr;
+ iar.dwError = ERROR_SUCCESS;
+
+ hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_HANDLE_CREATED,
+ &iar, sizeof(INTERNET_ASYNC_RESULT));
+ }
+
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
+ {
+ INTERNET_ASYNC_RESULT iar;
+
+ iar.dwResult = (DWORD)lpwhr;
+ iar.dwError = lpwhr ? ERROR_SUCCESS : INTERNET_GetLastError();
+ hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
+ &iar, sizeof(INTERNET_ASYNC_RESULT));
+ }
+
+ return (HINTERNET) lpwhr;
+}
+
+
+/***********************************************************************
+ * HttpQueryInfoA (WININET.74)
+ *
+ * Queries for information about an HTTP request
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
+ LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+ LPHTTPHEADERA lphttpHdr = NULL;
+ BOOL bSuccess = FALSE;
+ LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
+
+ TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
+
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ /* Find requested header structure */
+ if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
+ {
+ INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
+
+ if (index < 0)
+ goto lend;
+
+ lphttpHdr = &lpwhr->pCustHeaders[index];
+ }
+ else
+ {
+ INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
+
+ if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
+ {
+ INT i, delim, size = 0, cnt = 0;
+
+ delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
+
+ /* Calculate length of custom reuqest headers */
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
+ {
+ if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
+ lpwhr->pCustHeaders[i].lpszValue)
+ {
+ size += strlen(lpwhr->pCustHeaders[i].lpszField) +
+ strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
+ }
+ }
+
+ /* Calculate the length of stadard request headers */
+ for (i = 0; i <= HTTP_QUERY_MAX; i++)
+ {
+ if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
+ lpwhr->StdHeaders[i].lpszValue)
+ {
+ size += strlen(lpwhr->StdHeaders[i].lpszField) +
+ strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
+ }
+ }
+
+ size += delim;
+
+ if (size + 1 > *lpdwBufferLength)
+ {
+ *lpdwBufferLength = size + 1;
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto lend;
+ }
+
+ /* Append standard request heades */
+ for (i = 0; i <= HTTP_QUERY_MAX; i++)
+ {
+ if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
+ lpwhr->StdHeaders[i].lpszField &&
+ lpwhr->StdHeaders[i].lpszValue)
+ {
+ cnt += sprintf(lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
+ index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
+ }
+ }
+
+ /* Append custom request heades */
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
+ {
+ if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
+ lpwhr->pCustHeaders[i].lpszField &&
+ lpwhr->pCustHeaders[i].lpszValue)
+ {
+ cnt += sprintf(lpBuffer + cnt, "%s: %s%s",
+ lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
+ index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
+ }
+ }
+
+ strcpy(lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
+
+ *lpdwBufferLength = cnt + delim;
+ bSuccess = TRUE;
+ goto lend;
+ }
+ else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
+ {
+ lphttpHdr = &lpwhr->StdHeaders[index];
+ }
+ else
+ goto lend;
+ }
+
+ /* Ensure header satisifies requested attributes */
+ if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
+ (~lphttpHdr->wFlags & HDR_ISREQUEST))
+ goto lend;
+
+ /* coalesce value to reuqested type */
+ if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
+ {
+ *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
+ bSuccess = TRUE;
+ }
+ else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
+ {
+ time_t tmpTime;
+ struct tm tmpTM;
+ SYSTEMTIME *STHook;
+
+ tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
+
+ tmpTM = *gmtime(&tmpTime);
+ STHook = (SYSTEMTIME *) lpBuffer;
+ if(STHook==NULL)
+ goto lend;
+
+ STHook->wDay = tmpTM.tm_mday;
+ STHook->wHour = tmpTM.tm_hour;
+ STHook->wMilliseconds = 0;
+ STHook->wMinute = tmpTM.tm_min;
+ STHook->wDayOfWeek = tmpTM.tm_wday;
+ STHook->wMonth = tmpTM.tm_mon + 1;
+ STHook->wSecond = tmpTM.tm_sec;
+ STHook->wYear = tmpTM.tm_year;
+
+ bSuccess = TRUE;
+ }
+ else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
+ {
+ if (*lpdwIndex >= lphttpHdr->wCount)
+ {
+ INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
+ }
+ else
+ {
+ //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
+ (*lpdwIndex)++;
+ }
+ }
+ else
+ {
+ INT len = strlen(lphttpHdr->lpszValue);
+
+ if (len + 1 > *lpdwBufferLength)
+ {
+ *lpdwBufferLength = len + 1;
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto lend;
+ }
+
+ strncpy(lpBuffer, lphttpHdr->lpszValue, len);
+ *lpdwBufferLength = len;
+ bSuccess = TRUE;
+ }
+
+lend:
+ TRACE("%d <--\n", bSuccess);
+ return bSuccess;
+}
+
+/***********************************************************************
+ * HttpSendRequestA (WININET.76)
+ *
+ * Sends the specified request to the HTTP server
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+{
+ LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
+ LPWININETHTTPSESSIONA lpwhs = NULL;
+ LPWININETAPPINFOA hIC = NULL;
+
+ TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
+
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
+ if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+ {
+ WORKREQUEST workRequest;
+
+ workRequest.asyncall = HTTPSENDREQUESTA;
+ workRequest.HFTPSESSION = (DWORD)hHttpRequest;
+ workRequest.LPSZHEADER = (DWORD)HEAP_strdupA(GetProcessHeap(), 0, lpszHeaders);
+ workRequest.DWHEADERLENGTH = dwHeaderLength;
+ workRequest.LPOPTIONAL = (DWORD)lpOptional;
+ workRequest.DWOPTIONALLENGTH = dwOptionalLength;
+
+ return INTERNET_AsyncCall(&workRequest);
+ }
+ else
+ {
+ return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
+ dwHeaderLength, lpOptional, dwOptionalLength);
+ }
+}
+
+
+/***********************************************************************
+ * HTTP_HttpSendRequestA (internal)
+ *
+ * Sends the specified request to the HTTP server
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+{
+ INT cnt;
+ INT i;
+ BOOL bSuccess = FALSE;
+ LPSTR requestString = NULL;
+ INT requestStringLen;
+ INT headerLength = 0;
+ LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
+ LPWININETHTTPSESSIONA lpwhs = NULL;
+ LPWININETAPPINFOA hIC = NULL;
+
+ TRACE("0x%08lx\n", (ULONG)hHttpRequest);
+
+ /* Verify our tree of internet handles */
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
+ if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ /* Clear any error information */
+ INTERNET_SetLastError(0);
+
+ /* We must have a verb */
+ if (NULL == lpwhr->lpszVerb)
+ {
+ goto lend;
+ }
+
+ /* If we don't have a path we set it to root */
+ if (NULL == lpwhr->lpszPath)
+ lpwhr->lpszPath = HEAP_strdupA(GetProcessHeap(), 0, "/");
+
+ /* Calculate length of request string */
+ requestStringLen =
+ strlen(lpwhr->lpszVerb) +
+ strlen(lpwhr->lpszPath) +
+ (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
+ strlen(HTTPHEADER) +
+ 5; /* " \r\n\r\n" */
+
+ /* Add length of passed headers */
+ if (lpszHeaders)
+ {
+ headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
+ requestStringLen += headerLength + 2; /* \r\n */
+ }
+
+ /* Calculate length of custom reuqest headers */
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
+ {
+ if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
+ {
+ requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
+ strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
+ }
+ }
+
+ /* Calculate the length of stadard request headers */
+ for (i = 0; i <= HTTP_QUERY_MAX; i++)
+ {
+ if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
+ {
+ requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
+ strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
+ }
+ }
+
+ /* Allocate string to hold entire request */
+ requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
+ if (NULL == requestString)
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ goto lend;
+ }
+
+ /* Build request string */
+ cnt = sprintf(requestString, "%s %s%s%s",
+ lpwhr->lpszVerb,
+ lpwhr->lpszPath,
+ lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
+ lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
+
+ /* Append standard request heades */
+ for (i = 0; i <= HTTP_QUERY_MAX; i++)
+ {
+ if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
+ {
+ cnt += sprintf(requestString + cnt, "\r\n%s: %s",
+ lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
+ }
+ }
+
+ /* Append custom request heades */
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
+ {
+ if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
+ {
+ cnt += sprintf(requestString + cnt, "\r\n%s: %s",
+ lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
+ }
+ }
+
+ /* Append passed request headers */
+ if (lpszHeaders)
+ {
+ strcpy(requestString + cnt, "\r\n");
+ cnt += 2;
+ strcpy(requestString + cnt, lpszHeaders);
+ cnt += headerLength;
+ }
+
+ /* Set termination string for request */
+ strcpy(requestString + cnt, "\r\n\r\n");
+
+ if (hIC->lpfnStatusCB)
+ hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
+
+ TRACE("(%s) len(%d)\n", requestString, requestStringLen);
+ /* Send the request and store the results */
+ if (!HTTP_OpenConnection(lpwhr))
+ goto lend;
+
+ cnt = INTERNET_WriteDataToStream(lpwhr->nSocketFD, requestString, requestStringLen);
+
+ if (cnt < 0)
+ goto lend;
+
+ if (HTTP_GetResponseHeaders(lpwhr))
+ bSuccess = TRUE;
+
+lend:
+
+ if (requestString)
+ HeapFree(GetProcessHeap(), 0, requestString);
+
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
+ {
+ INTERNET_ASYNC_RESULT iar;
+
+ iar.dwResult = (DWORD)bSuccess;
+ iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
+ hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
+ &iar, sizeof(INTERNET_ASYNC_RESULT));
+ }
+
+ TRACE("<--\n");
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HTTP_Connect (internal)
+ *
+ * Create http session handle
+ *
+ * RETURNS
+ * HINTERNET a session handle on success
+ * NULL on failure
+ *
+ */
+HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
+ INTERNET_PORT nServerPort, LPCSTR lpszUserName,
+ LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
+{
+ BOOL bSuccess = FALSE;
+ LPWININETAPPINFOA hIC = NULL;
+ LPWININETHTTPSESSIONA lpwhs = NULL;
+
+ TRACE("\n");
+
+ if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
+ goto lerror;
+
+ hIC = (LPWININETAPPINFOA) hInternet;
+
+ lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
+ if (NULL == lpwhs)
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ goto lerror;
+ }
+
+ if (hIC->lpfnStatusCB)
+ hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
+ lpszServerName, strlen(lpszServerName));
+
+ if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
+ nServerPort = INTERNET_DEFAULT_HTTP_PORT;
+
+ if (!GetAddress(lpszServerName, nServerPort, &lpwhs->phostent, &lpwhs->socketAddress))
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
+ goto lerror;
+ }
+
+ if (hIC->lpfnStatusCB)
+ hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
+ lpszServerName, strlen(lpszServerName));
+
+ lpwhs->hdr.htype = WH_HHTTPSESSION;
+ lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
+ lpwhs->hdr.dwFlags = dwFlags;
+ lpwhs->hdr.dwContext = dwContext;
+ if (NULL != lpszServerName)
+ lpwhs->lpszServerName = HEAP_strdupA(GetProcessHeap(), 0, lpszServerName);
+ if (NULL != lpszUserName)
+ lpwhs->lpszUserName = HEAP_strdupA(GetProcessHeap(), 0, lpszUserName);
+ lpwhs->nServerPort = nServerPort;
+
+ if (hIC->lpfnStatusCB)
+ {
+ INTERNET_ASYNC_RESULT iar;
+
+ iar.dwResult = (DWORD)lpwhs;
+ iar.dwError = ERROR_SUCCESS;
+
+ hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
+ &iar, sizeof(INTERNET_ASYNC_RESULT));
+ }
+
+ bSuccess = TRUE;
+
+lerror:
+ if (!bSuccess && lpwhs)
+ {
+ HeapFree(GetProcessHeap(), 0, lpwhs);
+ lpwhs = NULL;
+ }
+
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
+ {
+ INTERNET_ASYNC_RESULT iar;
+
+ iar.dwResult = (DWORD)lpwhs;
+ iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
+ hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
+ &iar, sizeof(INTERNET_ASYNC_RESULT));
+ }
+TRACE("<--\n");
+ return (HINTERNET)lpwhs;
+}
+
+
+/***********************************************************************
+ * HTTP_OpenConnection (internal)
+ *
+ * Connect to a web server
+ *
+ * RETURNS
+ *
+ * TRUE on success
+ * FALSE on failure
+ */
+BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
+{
+ BOOL bSuccess = FALSE;
+ INT result;
+ LPWININETHTTPSESSIONA lpwhs;
+
+ TRACE("\n");
+
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ goto lend;
+ }
+
+ lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
+
+ lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
+ if (INVALID_SOCKET == lpwhr->nSocketFD)
+ {
+ WARN("Socket creation failed\n");
+ goto lend;
+ }
+
+ result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
+ sizeof(lpwhs->socketAddress));
+
+ if (SOCKET_ERROR == result)
+ {
+ WARN("Unable to connect to host: %d\n", errno);
+ goto lend;
+ }
+
+ bSuccess = TRUE;
+
+lend:
+ TRACE(": %d\n", bSuccess);
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HTTP_GetResponseHeaders (internal)
+ *
+ * Read server response
+ *
+ * RETURNS
+ *
+ * TRUE on success
+ * FALSE on error
+ */
+BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
+{
+ INT cbreaks = 0;
+ CHAR buffer[MAX_REPLY_LEN];
+ DWORD buflen = MAX_REPLY_LEN;
+ BOOL bSuccess = FALSE;
+ CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
+
+ TRACE("\n");
+
+ if (INVALID_SOCKET == lpwhr->nSocketFD)
+ goto lend;
+
+ /*
+ * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
+ */
+ if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
+ goto lend;
+
+ if (strncmp(buffer, "HTTP", 4) != 0)
+ goto lend;
+
+ buffer[12]='\0';
+ HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
+
+ /* Parse each response line */
+ do
+ {
+ buflen = MAX_REPLY_LEN;
+ if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
+ {
+ if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
+ break;
+
+ HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
+ }
+ else
+ {
+ cbreaks++;
+ if (cbreaks >= 2)
+ break;
+ }
+ }while(1);
+
+ bSuccess = TRUE;
+
+lend:
+
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HTTP_InterpretHttpHeader (internal)
+ *
+ * Parse server response
+ *
+ * RETURNS
+ *
+ * TRUE on success
+ * FALSE on error
+ */
+INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
+{
+ LPCSTR lpsztmp;
+ INT srclen;
+
+ srclen = 0;
+
+ while (*lpszSrc == ' ' && *lpszSrc != '\0')
+ lpszSrc++;
+
+ lpsztmp = lpszSrc;
+ while(*lpsztmp != '\0')
+ {
+ if (*lpsztmp != ' ')
+ srclen = lpsztmp - lpszSrc + 1;
+
+ lpsztmp++;
+ }
+
+ *len = min(*len, srclen);
+ strncpy(lpszStart, lpszSrc, *len);
+ lpszStart[*len] = '\0';
+
+ return *len;
+}
+
+
+BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
+{
+ CHAR *pd;
+ BOOL bSuccess = FALSE;
+
+ TRACE("\n");
+
+ *field = '\0';
+ *value = '\0';
+
+ pd = strchr(buffer, ':');
+ if (pd)
+ {
+ *pd = '\0';
+ if (stripSpaces(buffer, field, &fieldlen) > 0)
+ {
+ if (stripSpaces(pd+1, value, &valuelen) > 0)
+ bSuccess = TRUE;
+ }
+ }
+
+ TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HTTP_GetStdHeaderIndex (internal)
+ *
+ * Lookup field index in stadard http header array
+ *
+ * FIXME: This should be stuffed into a hash table
+ */
+INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
+{
+ INT index = -1;
+
+ if (!_stricmp(lpszField, "Content-Length"))
+ index = HTTP_QUERY_CONTENT_LENGTH;
+ else if (!_stricmp(lpszField,"Status"))
+ index = HTTP_QUERY_STATUS_CODE;
+ else if (!_stricmp(lpszField,"Content-Type"))
+ index = HTTP_QUERY_CONTENT_TYPE;
+ else if (!_stricmp(lpszField,"Last-Modified"))
+ index = HTTP_QUERY_LAST_MODIFIED;
+ else if (!_stricmp(lpszField,"Location"))
+ index = HTTP_QUERY_LOCATION;
+ else if (!_stricmp(lpszField,"Accept"))
+ index = HTTP_QUERY_ACCEPT;
+ else if (!_stricmp(lpszField,"Referer"))
+ index = HTTP_QUERY_REFERER;
+ else if (!_stricmp(lpszField,"Content-Transfer-Encoding"))
+ index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
+ else
+ {
+ FIXME("Couldn't find %s in standard header table\n", lpszField);
+ }
+
+ return index;
+}
+
+
+/***********************************************************************
+ * HTTP_ProcessHeader (internal)
+ *
+ * Stuff header into header tables according to <dwModifier>
+ *
+ */
+
+#define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+
+BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
+{
+ LPHTTPHEADERA lphttpHdr = NULL;
+ BOOL bSuccess = FALSE;
+ INT index;
+
+ TRACE("%s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
+
+ /* Adjust modifier flags */
+ if (dwModifier & COALESCEFLASG)
+ dwModifier |= HTTP_ADDHDR_FLAG_ADD;
+
+ /* Try to get index into standard header array */
+ index = HTTP_GetStdHeaderIndex(field);
+ if (index >= 0)
+ {
+ lphttpHdr = &lpwhr->StdHeaders[index];
+ }
+ else /* Find or create new custom header */
+ {
+ index = HTTP_GetCustomHeaderIndex(lpwhr, field);
+ if (index >= 0)
+ {
+ if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
+ {
+ return FALSE;
+ }
+ lphttpHdr = &lpwhr->pCustHeaders[index];
+ }
+ else
+ {
+ HTTPHEADERA hdr;
+
+ hdr.lpszField = field;
+ hdr.lpszValue = value;
+ hdr.wFlags = hdr.wCount = 0;
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ hdr.wFlags |= HDR_ISREQUEST;
+
+ index = HTTP_InsertCustomHeader(lpwhr, &hdr);
+ return index >= 0;
+ }
+ }
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ lphttpHdr->wFlags |= HDR_ISREQUEST;
+ else
+ lphttpHdr->wFlags &= ~HDR_ISREQUEST;
+
+ if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
+ {
+ INT slen;
+
+ if (!lpwhr->StdHeaders[index].lpszField)
+ {
+ lphttpHdr->lpszField = HEAP_strdupA(GetProcessHeap(), 0, field);
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ lphttpHdr->wFlags |= HDR_ISREQUEST;
+ }
+
+ slen = strlen(value) + 1;
+ lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
+ if (lphttpHdr->lpszValue)
+ {
+ memcpy(lphttpHdr->lpszValue, value, slen);
+ bSuccess = TRUE;
+ }
+ else
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ }
+ }
+ else if (lphttpHdr->lpszValue)
+ {
+ if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+ {
+ LPSTR lpsztmp;
+ INT len;
+
+ len = strlen(value);
+
+ if (len <= 0)
+ {
+ //! if custom header delete from array
+ HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
+ lphttpHdr->lpszValue = NULL;
+ bSuccess = TRUE;
+ }
+ else
+ {
+ lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
+ if (lpsztmp)
+ {
+ lphttpHdr->lpszValue = lpsztmp;
+ strcpy(lpsztmp, value);
+ bSuccess = TRUE;
+ }
+ else
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ }
+ }
+ }
+ else if (dwModifier & COALESCEFLASG)
+ {
+ LPSTR lpsztmp;
+ CHAR ch = 0;
+ INT len = 0;
+ INT origlen = strlen(lphttpHdr->lpszValue);
+ INT valuelen = strlen(value);
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
+ {
+ ch = ',';
+ lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+ }
+ else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+ {
+ ch = ';';
+ lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+ }
+
+ len = origlen + valuelen + (ch > 0) ? 1 : 0;
+
+ lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
+ if (lpsztmp)
+ {
+ /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
+ if (ch > 0)
+ {
+ lphttpHdr->lpszValue[origlen] = ch;
+ origlen++;
+ }
+
+ memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
+ lphttpHdr->lpszValue[len] = '\0';
+ bSuccess = TRUE;
+ }
+ else
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ }
+ }
+ }
+
+ return bSuccess;
+}
+
+
+/***********************************************************************
+ * HTTP_CloseConnection (internal)
+ *
+ * Close socket connection
+ *
+ */
+VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
+{
+ if (lpwhr->nSocketFD != INVALID_SOCKET)
+ {
+ close(lpwhr->nSocketFD);
+ lpwhr->nSocketFD = INVALID_SOCKET;
+ }
+}
+
+
+/***********************************************************************
+ * HTTP_CloseHTTPRequestHandle (internal)
+ *
+ * Deallocate request handle
+ *
+ */
+void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
+{
+ int i;
+
+ TRACE("\n");
+
+ if (lpwhr->nSocketFD != INVALID_SOCKET)
+ HTTP_CloseConnection(lpwhr);
+
+ if (lpwhr->lpszPath)
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
+ if (lpwhr->lpszVerb)
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+ if (lpwhr->lpszHostName)
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
+
+ for (i = 0; i <= HTTP_QUERY_MAX; i++)
+ {
+ if (lpwhr->StdHeaders[i].lpszField)
+ HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
+ if (lpwhr->StdHeaders[i].lpszValue)
+ HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
+ }
+
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
+ {
+ if (lpwhr->pCustHeaders[i].lpszField)
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
+ if (lpwhr->pCustHeaders[i].lpszValue)
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
+ }
+
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
+ HeapFree(GetProcessHeap(), 0, lpwhr);
+}
+
+
+/***********************************************************************
+ * HTTP_CloseHTTPSessionHandle (internal)
+ *
+ * Deallocate session handle
+ *
+ */
+void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
+{
+ TRACE("\n");
+
+ if (lpwhs->lpszServerName)
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+ if (lpwhs->lpszUserName)
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
+ HeapFree(GetProcessHeap(), 0, lpwhs);
+}
+
+
+/***********************************************************************
+ * HTTP_GetCustomHeaderIndex (internal)
+ *
+ * Return index of custom header from header array
+ *
+ */
+INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
+{
+ INT index;
+
+ TRACE("%s\n", lpszField);
+
+ for (index = 0; index < lpwhr->nCustHeaders; index++)
+ {
+ if (!_stricmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
+ break;
+
+ }
+
+ if (index >= lpwhr->nCustHeaders)
+ index = -1;
+
+ TRACE("Return: %d\n", index);
+ return index;
+}
+
+
+/***********************************************************************
+ * HTTP_InsertCustomHeader (internal)
+ *
+ * Insert header into array
+ *
+ */
+INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
+{
+ INT count;
+ LPHTTPHEADERA lph = NULL;
+
+ TRACE("%s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
+ count = lpwhr->nCustHeaders + 1;
+ if (count > 1)
+ lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
+ else
+ lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
+
+ if (NULL != lph)
+ {
+ lpwhr->pCustHeaders = lph;
+ lpwhr->pCustHeaders[count-1].lpszField = HEAP_strdupA(GetProcessHeap(), 0, lpHdr->lpszField);
+ lpwhr->pCustHeaders[count-1].lpszValue = HEAP_strdupA(GetProcessHeap(), 0, lpHdr->lpszValue);
+ lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
+ lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
+ lpwhr->nCustHeaders++;
+ }
+ else
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ count = 0;
+ }
+
+ TRACE("%d <--\n", count-1);
+ return count - 1;
+}
+
+
+/***********************************************************************
+ * HTTP_DeleteCustomHeader (internal)
+ *
+ * Delete header from array
+ *
+ */
+BOOL HTTP_DeleteCustomHeader(INT index)
+{
+ TRACE("\n");
+ return FALSE;
+}
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c
index 16e5dbe..2b2f8c0 100644
--- a/dlls/wininet/internet.c
+++ b/dlls/wininet/internet.c
@@ -15,12 +15,15 @@
# include <sys/socket.h>
#endif
#include <stdlib.h>
+#include <ctype.h>
#include "windows.h"
#include "wininet.h"
#include "debugtools.h"
#include "winerror.h"
#include "winsock.h"
+#include "tchar.h"
+#include "heap.h"
#include "internet.h"
@@ -28,6 +31,7 @@
#define MAX_IDLE_WORKER 1000*60*1
#define MAX_WORKER_THREADS 10
+#define RESPONSE_TIMEOUT 30
#define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
(LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
@@ -38,7 +42,7 @@
CHAR response[MAX_REPLY_LEN];
} WITHREADERROR, *LPWITHREADERROR;
-INTERNET_SCHEME GetInternetScheme(LPSTR lpszScheme);
+INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp);
BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
VOID INTERNET_ExecuteWork();
@@ -97,7 +101,11 @@
case DLL_THREAD_DETACH:
if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
- HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
+ {
+ LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
+ if (lpwite)
+ HeapFree(GetProcessHeap(), 0, lpwite);
+ }
break;
case DLL_PROCESS_DETACH:
@@ -112,7 +120,6 @@
CloseHandle(hQuitEvent);
CloseHandle(hWorkEvent);
-
DeleteCriticalSection(&csQueue);
break;
}
@@ -152,11 +159,11 @@
lpwai->hdr.lpwhparent = NULL;
lpwai->hdr.dwFlags = dwFlags;
if (NULL != lpszAgent)
- lpwai->lpszAgent = strdup(lpszAgent);
+ lpwai->lpszAgent = HEAP_strdupA(GetProcessHeap(),0,lpszAgent);
if (NULL != lpszProxy)
- lpwai->lpszProxy = strdup(lpszProxy);
+ lpwai->lpszProxy = HEAP_strdupA(GetProcessHeap(),0,lpszProxy);
if (NULL != lpszProxyBypass)
- lpwai->lpszProxyBypass = strdup(lpszProxyBypass);
+ lpwai->lpszProxyBypass = HEAP_strdupA(GetProcessHeap(),0,lpszProxyBypass);
lpwai->dwAccessType = dwAccessType;
}
@@ -242,6 +249,8 @@
break;
case INTERNET_SERVICE_HTTP:
+ rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
+ lpszUserName, lpszPassword, dwFlags, dwContext);
break;
case INTERNET_SERVICE_GOPHER:
@@ -363,9 +372,33 @@
/***********************************************************************
+ * INTERNET_CloseHandle (internal)
+ *
+ * Close internet handle
+ *
+ * RETURNS
+ * Void
+ *
+ */
+VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
+{
+ if (lpwai->lpszAgent)
+ HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
+
+ if (lpwai->lpszProxy)
+ HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
+
+ if (lpwai->lpszProxyBypass)
+ HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
+
+ HeapFree(GetProcessHeap(), 0, lpwai);
+}
+
+
+/***********************************************************************
* InternetCloseHandle (WININET.89)
*
- * Continues a file search from a previous call to FindFirstFile
+ * Generic close handle function
*
* RETURNS
* TRUE on success
@@ -387,9 +420,17 @@
switch (lpwh->htype)
{
case WH_HINIT:
+ INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
+ break;
+
case WH_HHTTPSESSION:
+ HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
+ break;
+
case WH_HHTTPREQ:
+ HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
break;
+
case WH_HFTPSESSION:
retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
break;
@@ -407,10 +448,46 @@
/***********************************************************************
+ * SetUrlComponentValue (Internal)
+ *
+ * Helper function for InternetCrackUrlA
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
+{
+ TRACE("%s (%d)\n", lpszStart, len);
+
+ if (*dwComponentLen != 0)
+ {
+ if (*lppszComponent == NULL)
+ {
+ *lppszComponent = lpszStart;
+ *dwComponentLen = len;
+ }
+ else
+ {
+ INT ncpylen = min((*dwComponentLen)-1, len);
+ strncpy(*lppszComponent, lpszStart, ncpylen);
+ (*lppszComponent)[ncpylen] = '\0';
+ *dwComponentLen = ncpylen;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/***********************************************************************
* InternetCrackUrlA (WININET.95)
*
* Break up URL into its components
*
+ * TODO: Hadnle dwFlags
+ *
* RETURNS
* TRUE on success
* FALSE on failure
@@ -424,165 +501,162 @@
* <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
*
*/
- char* szScheme = NULL;
- char* szUser = NULL;
- char* szPass = NULL;
- char* szHost = NULL;
- char* szUrlPath = NULL;
- char* szParam = NULL;
- char* szNetLoc = NULL;
- int nPort = 80;
- int nSchemeLen = 0;
- int nUserLen = 0;
- int nPassLen = 0;
- int nHostLen = 0;
- int nUrlLen = 0;
-
- /* Find out if the URI is absolute... */
+ LPSTR lpszParam = NULL;
BOOL bIsAbsolute = FALSE;
- char cAlphanum;
- char* ap = (char*)lpszUrl;
- char* cp = NULL;
+ LPSTR lpszap = (char*)lpszUrl;
+ LPSTR lpszcp = NULL;
TRACE("\n");
- while( (cAlphanum = *ap) != '\0' )
+
+ /* Determine if the URI is absolute. */
+ while (*lpszap != '\0')
{
- if( ((cAlphanum >= 'a') && (cAlphanum <= 'z')) ||
- ((cAlphanum >= 'A') && (cAlphanum <= 'Z')) ||
- ((cAlphanum >= '0') && (cAlphanum <= '9')) )
+ if (isalnum(*lpszap))
{
- ap++;
+ lpszap++;
continue;
}
- if( (cAlphanum == ':') && (ap - lpszUrl >= 2) )
+ if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
{
bIsAbsolute = TRUE;
- cp = ap;
- break;
+ lpszcp = lpszap;
}
+ else
+ {
+ lpszcp = lpszUrl; /* Relative url */
+ }
+
break;
}
- /* Absolute URI...
- FIXME!!!! This should work on relative urls too!*/
- if( bIsAbsolute )
+ /* Parse <params> */
+ lpszParam = strpbrk(lpszap, ";?");
+ if (lpszParam != NULL)
{
- /* Get scheme first... */
- nSchemeLen = cp - lpszUrl;
- szScheme = strdup( lpszUrl );
- szScheme[ nSchemeLen ] = '\0';
-
- /* Eat ':' in protocol... */
- cp++;
-
- /* Parse <params>... */
- szParam = strpbrk( lpszUrl, ";" );
- if( szParam != NULL )
+ if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
+ &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
{
- char* sParam;
- /* Eat ';' in Params... */
- szParam++;
- sParam = strdup( szParam );
- *szParam = '\0';
+ return FALSE;
+ }
}
- /* Skip over slashes...*/
- if( *cp == '/' )
+ if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
{
- cp++;
- if( *cp == '/' )
+ LPSTR lpszNetLoc;
+
+ /* Get scheme first. */
+ lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
+ if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
+ &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
+ return FALSE;
+
+ /* Eat ':' in protocol. */
+ lpszcp++;
+
+ /* Skip over slashes. */
+ if (*lpszcp == '/')
+ {
+ lpszcp++;
+ if (*lpszcp == '/')
{
- cp++;
- if( *cp == '/' )
- cp++;
+ lpszcp++;
+ if (*lpszcp == '/')
+ lpszcp++;
}
}
- /* Parse the <net-loc>...*/
- if( GetInternetScheme( szScheme ) == INTERNET_SCHEME_FILE )
+ lpszNetLoc = strpbrk(lpszcp, "/");
+ if (lpszParam)
{
- szUrlPath = strdup( cp );
- nUrlLen = strlen( szUrlPath );
- if( nUrlLen >= 2 && szUrlPath[ 1 ] == '|' )
- szUrlPath[ 1 ] = ':';
- }
+ if (lpszNetLoc)
+ lpszNetLoc = min(lpszNetLoc, lpszParam);
else
+ lpszNetLoc = lpszParam;
+ }
+ else if (!lpszNetLoc)
+ lpszNetLoc = lpszcp + strlen(lpszcp);
+
+ /* Parse net-loc */
+ if (lpszNetLoc)
{
- size_t nNetLocLen;
- szUrlPath = strpbrk(cp, "/");
- if( szUrlPath != NULL )
- nUrlLen = strlen( szUrlPath );
+ LPSTR lpszHost;
+ LPSTR lpszPort;
- /* Find the end of our net-loc... */
- nNetLocLen = strcspn( cp, "/" );
- szNetLoc = strdup( cp );
- szNetLoc[ nNetLocLen ] = '\0';
- if( szNetLoc != NULL )
- {
- char* lpszPort;
- int nPortLen;
/* [<user>[<:password>]@]<host>[:<port>] */
- /* First find the user and password if they exist...*/
+ /* First find the user and password if they exist */
- szHost = strchr( szNetLoc, '@' );
- if( szHost == NULL )
+ lpszHost = strchr(lpszcp, '@');
+ if (lpszHost == NULL || lpszHost > lpszNetLoc)
{
- /* username and password not specified... */
- szHost = szNetLoc;
- nHostLen = nNetLocLen;
+ /* username and password not specified. */
+ SetUrlComponentValue(&lpUrlComponents->lpszUserName,
+ &lpUrlComponents->dwUserNameLength, NULL, 0);
+ SetUrlComponentValue(&lpUrlComponents->lpszPassword,
+ &lpUrlComponents->dwPasswordLength, NULL, 0);
}
- else
+ else /* Parse out username and password */
{
- int nUserPassLen = nNetLocLen - nHostLen - 1;
- char* szUserPass = strdup( szNetLoc );
- /* Get username and/or password... */
- /* Eat '@' in domain... */
- ++szHost;
- nHostLen = strlen( szHost );
+ LPSTR lpszUser = lpszcp;
+ LPSTR lpszPasswd = lpszHost;
- szUserPass[ nUserPassLen ] = '\0';
- if( szUserPass != NULL )
- {
- szPass = strpbrk( szUserPass, ":" );
- if( szPass != NULL )
+ while (lpszcp < lpszHost)
{
- /* Eat ':' in UserPass... */
- ++szPass;
- nPassLen = strlen( szPass );
- nUserLen = nUserPassLen - nPassLen - 1;
- szUser = strdup( szUserPass );
- szUser[ nUserLen ] = '\0';
- }
- else
- {
- /* password not specified... */
- szUser = strdup( szUserPass );
- nUserLen = strlen( szUser );
- }
+ if (*lpszcp == ':')
+ lpszPasswd = lpszcp;
+
+ lpszcp++;
}
+
+ SetUrlComponentValue(&lpUrlComponents->lpszUserName,
+ &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
+
+ SetUrlComponentValue(&lpUrlComponents->lpszPassword,
+ &lpUrlComponents->dwPasswordLength,
+ lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
+ lpszHost - lpszPasswd);
+
+ lpszcp++; /* Advance to beginning of host */
}
- /* <host><:port>...*/
- /* Then get the port if it exists... */
- lpszPort = strpbrk( szHost, ":" );
- nPortLen = 0;
- if( lpszPort != NULL )
- {
- char* szPort = lpszPort + 1;
- if( szPort != NULL )
+ /* Parse <host><:port> */
+
+ lpszHost = lpszcp;
+ lpszPort = lpszNetLoc;
+
+ while (lpszcp < lpszNetLoc)
{
- nPortLen = strlen( szPort );
- nPort = atoi( szPort );
- }
- *lpszPort = '\0';
- nHostLen = strlen(szHost);
+ if (*lpszcp == ':')
+ lpszPort = lpszcp;
+
+ lpszcp++;
}
+
+ SetUrlComponentValue(&lpUrlComponents->lpszHostName,
+ &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
+
+ if (lpszPort != lpszNetLoc)
+ lpUrlComponents->nPort = atoi(++lpszPort);
}
}
+
+ /* Here lpszcp points to:
+ *
+ * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ */
+ if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
+ {
+ if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
+ &lpUrlComponents->dwUrlPathLength, lpszcp,
+ lpszParam ? lpszParam - lpszcp : strlen(lpszcp)))
+ return FALSE;
}
- /* Relative URI... */
else
- return FALSE;
+ {
+ lpUrlComponents->dwUrlPathLength = 0;
+ }
+
+ TRACE("%s: host(%s) path(%s)\n", lpszUrl, lpUrlComponents->lpszHostName, lpUrlComponents->lpszUrlPath);
return TRUE;
}
@@ -758,6 +832,60 @@
/***********************************************************************
+ * InternetQueryOptionA
+ *
+ * Queries an options on the specified handle
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
+ LPVOID lpBuffer, LPDWORD lpdwBufferLength)
+{
+ LPWININETHANDLEHEADER lpwhh;
+ BOOL bSuccess = FALSE;
+
+ TRACE("0x%08lx\n", dwOption);
+
+ if (NULL == hInternet)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ return FALSE;
+ }
+
+ lpwhh = (LPWININETHANDLEHEADER) hInternet;
+
+ switch (dwOption)
+ {
+ case INTERNET_OPTION_HANDLE_TYPE:
+ {
+ ULONG type = lpwhh->htype;
+ TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
+
+ if (*lpdwBufferLength < sizeof(ULONG))
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ else
+ {
+ memcpy(lpBuffer, &type, sizeof(ULONG));
+ *lpdwBufferLength = sizeof(ULONG);
+ bSuccess = TRUE;
+ }
+
+ break;
+ }
+
+ default:
+ FIXME("Stub!");
+ break;
+ }
+
+ return bSuccess;
+}
+
+
+/***********************************************************************
* GetInternetScheme (internal)
*
* Get scheme of url
@@ -767,31 +895,24 @@
* INTERNET_SCHEME_UNKNOWN on failure
*
*/
-INTERNET_SCHEME GetInternetScheme(LPSTR lpszScheme)
+INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
{
if(lpszScheme==NULL)
return INTERNET_SCHEME_UNKNOWN;
- if( (strcmp("ftp", lpszScheme) == 0) ||
- (strcmp("FTP", lpszScheme) == 0) )
+ if (!_strnicmp("ftp", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_FTP;
- else if( (strcmp("gopher", lpszScheme) == 0) ||
- (strcmp("GOPHER", lpszScheme) == 0) )
+ else if (!_strnicmp("gopher", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_GOPHER;
- else if( (strcmp("http", lpszScheme) == 0) ||
- (strcmp("HTTP", lpszScheme) == 0) )
+ else if (!_strnicmp("http", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_HTTP;
- else if( (strcmp("https", lpszScheme) == 0) ||
- (strcmp("HTTPS", lpszScheme) == 0) )
+ else if (!_strnicmp("https", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_HTTPS;
- else if( (strcmp("file", lpszScheme) == 0) ||
- (strcmp("FILE", lpszScheme) == 0) )
+ else if (!_strnicmp("file", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_FILE;
- else if( (strcmp("news", lpszScheme) == 0) ||
- (strcmp("NEWS", lpszScheme) == 0) )
+ else if (!_strnicmp("news", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_NEWS;
- else if( (strcmp("mailto", lpszScheme) == 0) ||
- (strcmp("MAILTO", lpszScheme) == 0) )
+ else if (!_strnicmp("mailto", lpszScheme, nMaxCmp))
return INTERNET_SCHEME_MAILTO;
else
return INTERNET_SCHEME_UNKNOWN;
@@ -1111,6 +1232,31 @@
INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
(LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
break;
+
+ case HTTPSENDREQUESTA:
+ HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
+ (LPCSTR)workRequest.LPSZHEADER,
+ workRequest.DWHEADERLENGTH,
+ (LPVOID)workRequest.LPOPTIONAL,
+ workRequest.DWOPTIONALLENGTH);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
+ break;
+
+ case HTTPOPENREQUESTA:
+ HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
+ (LPCSTR)workRequest.LPSZVERB,
+ (LPCSTR)workRequest.LPSZOBJECTNAME,
+ (LPCSTR)workRequest.LPSZVERSION,
+ (LPCSTR)workRequest.LPSZREFERRER,
+ (LPCSTR*)workRequest.LPSZACCEPTTYPES,
+ workRequest.DWFLAGS,
+ workRequest.DWCONTEXT);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
+ break;
+
}
}
}
@@ -1127,3 +1273,69 @@
LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
return lpwite->response;
}
+
+
+/***********************************************************************
+ * INTERNET_GetNextLine (internal)
+ *
+ * Parse next line in directory string listing
+ *
+ * RETURNS
+ * Pointer to begining of next line
+ * NULL on failure
+ *
+ */
+
+LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
+{
+ struct timeval tv;
+ fd_set infd;
+ BOOL bSuccess = FALSE;
+ INT nRecv = 0;
+
+ TRACE("\n");
+
+ FD_ZERO(&infd);
+ FD_SET(nSocket, &infd);
+ tv.tv_sec=RESPONSE_TIMEOUT;
+ tv.tv_usec=0;
+
+ while (nRecv < *dwBuffer)
+ {
+ if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
+ {
+ if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
+ {
+ INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
+ goto lend;
+ }
+
+ if (lpszBuffer[nRecv] == '\n')
+ {
+ bSuccess = TRUE;
+ break;
+ }
+ if (lpszBuffer[nRecv] != '\r')
+ nRecv++;
+ }
+ else
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
+ goto lend;
+}
+ }
+
+lend:
+ if (bSuccess)
+ {
+ lpszBuffer[nRecv] = '\0';
+ *dwBuffer = nRecv - 1;
+ TRACE(":%d %s\n", nRecv, lpszBuffer);
+ return lpszBuffer;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h
index feb7fbf..b6cd68a 100644
--- a/dlls/wininet/internet.h
+++ b/dlls/wininet/internet.h
@@ -3,13 +3,13 @@
typedef enum
{
- WH_HINIT,
- WH_HFTPSESSION,
- WH_HGOPHERSESSION,
- WH_HHTTPSESSION,
- WH_HHTTPREQ,
- WH_HFILE,
- WH_HFINDNEXT,
+ WH_HINIT = INTERNET_HANDLE_TYPE_INTERNET,
+ WH_HFTPSESSION = INTERNET_HANDLE_TYPE_CONNECT_FTP,
+ WH_HGOPHERSESSION = INTERNET_HANDLE_TYPE_CONNECT_GOPHER,
+ WH_HHTTPSESSION = INTERNET_HANDLE_TYPE_CONNECT_HTTP,
+ WH_HFILE = INTERNET_HANDLE_TYPE_FTP_FILE,
+ WH_HFINDNEXT = INTERNET_HANDLE_TYPE_FTP_FIND,
+ WH_HHTTPREQ = INTERNET_HANDLE_TYPE_HTTP_REQUEST,
} WH_TYPE;
typedef struct _WININETHANDLEHEADER
@@ -43,20 +43,29 @@
struct hostent *phostent;
} WININETHTTPSESSIONA, *LPWININETHTTPSESSIONA;
+#define HDR_ISREQUEST 0x0001
+#define HDR_COMMADELIMITED 0x0002
+#define HDR_SEMIDELIMITED 0x0004
+
+typedef struct
+{
+ LPSTR lpszField;
+ LPSTR lpszValue;
+ WORD wFlags;
+ WORD wCount;
+} HTTPHEADERA, *LPHTTPHEADERA;
+
typedef struct
{
WININETHANDLEHEADER hdr;
LPSTR lpszPath;
- LPSTR lpszReferrer;
- LPSTR lpszAcceptTypes;
LPSTR lpszVerb;
LPSTR lpszHostName;
- LPSTR lpszRedirect;
- int nSocketFD;
- int statusCode;
- int contentLength;
- time_t nSystemTime;
+ INT nSocketFD;
+ HTTPHEADERA StdHeaders[HTTP_QUERY_MAX+1];
+ HTTPHEADERA *pCustHeaders;
+ INT nCustHeaders;
} WININETHTTPREQA, *LPWININETHTTPREQA;
@@ -111,6 +120,8 @@
FTPREMOVEDIRECTORYA,
FTPRENAMEFILEA,
INTERNETFINDNEXTA,
+ HTTPSENDREQUESTA,
+ HTTPOPENREQUESTA,
} ASYNC_FUNC;
typedef struct WORKREQ
@@ -126,6 +137,8 @@
#define LPSZSRCFILE param2
#define LPSZDIRECTORY param2
#define LPSZSEARCHFILE param2
+#define LPSZHEADER param2
+#define LPSZVERB param2
DWORD param3;
#define LPSZNEWREMOTEFILE param3
@@ -134,18 +147,27 @@
#define LPDWDIRECTORY param3
#define FDWACCESS param3
#define LPSZDESTFILE param3
+#define DWHEADERLENGTH param3
+#define LPSZOBJECTNAME param3
DWORD param4;
#define DWFLAGS param4
+#define LPOPTIONAL param4
DWORD param5;
#define DWCONTEXT param5
+#define DWOPTIONALLENGTH param5
DWORD param6;
-#define FFAILIFEXISTS param4
+#define FFAILIFEXISTS param6
+#define LPSZVERSION param6
DWORD param7;
#define DWLOCALFLAGSATTRIBUTE param7
+#define LPSZREFERRER param7
+
+ DWORD param8;
+#define LPSZACCEPTTYPES param8
struct WORKREQ *next;
struct WORKREQ *prev;
@@ -159,6 +181,10 @@
INTERNET_PORT nServerPort, LPCSTR lpszUserName,
LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext);
+HINTERNET HTTP_Connect(HINTERNET hInterent, LPCSTR lpszServerName,
+ INTERNET_PORT nServerPort, LPCSTR lpszUserName,
+ LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext);
+
BOOL GetAddress(LPCSTR lpszServerName, INTERNET_PORT nServerPort,
struct hostent **phe, struct sockaddr_in *psa);
@@ -168,6 +194,7 @@
DWORD INTERNET_GetLastError();
BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest);
LPSTR INTERNET_GetResponseBuffer();
+LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer);
BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn);
@@ -189,6 +216,15 @@
BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
DWORD dwContext);
+BOOLAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength);
+INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
+ LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+ LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD dwContext);
+void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs);
+void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr);
+
#define MAX_REPLY_LEN 0x5B4
diff --git a/dlls/wininet/utility.c b/dlls/wininet/utility.c
index a09b66f..21e050c 100644
--- a/dlls/wininet/utility.c
+++ b/dlls/wininet/utility.c
@@ -111,10 +111,12 @@
BOOL GetAddress(LPCSTR lpszServerName, INTERNET_PORT nServerPort,
struct hostent **phe, struct sockaddr_in *psa)
{
+ TRACE("%s\n", lpszServerName);
+
*phe = gethostbyname(lpszServerName);
if (NULL == *phe)
{
- TRACE("Failed to get hostname %s\n", lpszServerName);
+ TRACE("Failed to get hostname: (%s)\n", lpszServerName);
return FALSE;
}
diff --git a/dlls/wininet/wininet.spec b/dlls/wininet/wininet.spec
index 6ee7e52..3584505 100644
--- a/dlls/wininet/wininet.spec
+++ b/dlls/wininet/wininet.spec
@@ -69,15 +69,15 @@
@ stub GopherGetLocatorTypeW
@ stub GopherOpenFileA
@ stub GopherOpenFileW
-@ stub HttpAddRequestHeadersA
+@ stdcall HttpAddRequestHeadersA(ptr str long long) HttpAddRequestHeadersA
@ stub HttpAddRequestHeadersW
@ stub HttpEndRequestA
@ stub HttpEndRequestW
-@ stub HttpOpenRequestA
+@ stdcall HttpOpenRequestA(ptr str str str str ptr long long) HttpOpenRequestA
@ stub HttpOpenRequestW
-@ stub HttpQueryInfoA
+@ stdcall HttpQueryInfoA(ptr long ptr ptr ptr) HttpQueryInfoA
@ stub HttpQueryInfoW
-@ stub HttpSendRequestA
+@ stdcall HttpSendRequestA(ptr str long ptr long) HttpSendRequestA
@ stub HttpSendRequestExA
@ stub HttpSendRequestExW
@ stub HttpSendRequestW
@@ -120,7 +120,7 @@
@ stub InternetOpenUrlW
@ stub InternetOpenW
@ stub InternetQueryDataAvailable
-@ stub InternetQueryOptionA
+@ stdcall InternetQueryOptionA(ptr long ptr ptr) InternetQueryOptionA
@ stub InternetQueryOptionW
@ stdcall InternetReadFile(ptr ptr long ptr) InternetReadFile
@ stub InternetReadFileExA