diff --git a/dlls/wininet/Makefile.in b/dlls/wininet/Makefile.in index 1bab6178a59..1d7967702fa 100644 --- a/dlls/wininet/Makefile.in +++ b/dlls/wininet/Makefile.in @@ -8,6 +8,7 @@ SOVERSION = 1.0 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 031ff31111f..b6f1ca984c6 100644 --- a/dlls/wininet/ftp.c +++ b/dlls/wininet/ftp.c @@ -21,10 +21,13 @@ #include #include -#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 @@ DEFAULT_DEBUG_CHANNEL(wininet); #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_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp); 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 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, 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 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 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 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 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 @@ INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, 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 @@ INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, 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 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN 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 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) 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 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) 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 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes 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 @@ HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName, 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 @@ INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse, 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 @@ BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIE 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 @@ BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIE pszToken = strtok(NULL, " \t"); if(pszToken != NULL) { - curFileProp->lpszName = strdup(pszToken); + curFileProp->lpszName = HEAP_strdupA(GetProcessHeap(),0,pszToken); TRACE(": %s\n", curFileProp->lpszName); } @@ -2370,71 +2371,6 @@ BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp) } -/*********************************************************************** - * 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) * diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c new file mode 100644 index 00000000000..35e68d0bb40 --- /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 +#include +#include +#include +#include +#include +#include + +#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 + * + */ + +#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 16e5dbef0a5..2b2f8c0606b 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -15,12 +15,15 @@ # include #endif #include +#include #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 @@ DEFAULT_DEBUG_CHANNEL(wininet); #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 @@ typedef struct 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 @@ WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 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 @@ WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) CloseHandle(hQuitEvent); CloseHandle(hWorkEvent); - DeleteCriticalSection(&csQueue); break; } @@ -152,11 +159,11 @@ INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, 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 @@ INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, break; case INTERNET_SERVICE_HTTP: + rc = HTTP_Connect(hInternet, lpszServerName, nServerPort, + lpszUserName, lpszPassword, dwFlags, dwContext); break; case INTERNET_SERVICE_GOPHER: @@ -362,10 +371,34 @@ lend: } +/*********************************************************************** + * 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 @@ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet) 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; @@ -406,11 +447,47 @@ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet) } +/*********************************************************************** + * 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 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, * :[//][/path][;][?][#] * */ - 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 */ + lpszParam = strpbrk(lpszap, ";?"); + if (lpszParam != NULL) { - /* Get scheme first... */ - nSchemeLen = cp - lpszUrl; - szScheme = strdup( lpszUrl ); - szScheme[ nSchemeLen ] = '\0'; - - /* Eat ':' in protocol... */ - cp++; - - /* Parse ... */ - 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 :[//] */ { - 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 ...*/ - 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; /* [[<:password>]@][:] */ - /* 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 */ } - /* <:port>...*/ - /* Then get the port if it exists... */ - lpszPort = strpbrk( szHost, ":" ); - nPortLen = 0; - if( lpszPort != NULL ) - { - char* szPort = lpszPort + 1; - if( szPort != NULL ) + /* Parse <: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: + * + * :[//][/path][;][?][#] + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + 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; } @@ -757,6 +831,60 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, } +/*********************************************************************** + * 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) * @@ -767,31 +895,24 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, * 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 @@ VOID INTERNET_ExecuteWork() 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 @@ LPSTR INTERNET_GetResponseBuffer() 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 feb7fbf4ca2..b6cd68a6d6e 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 @@ typedef struct 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 @@ typedef enum FTPREMOVEDIRECTORYA, FTPRENAMEFILEA, INTERNETFINDNEXTA, + HTTPSENDREQUESTA, + HTTPOPENREQUESTA, } ASYNC_FUNC; typedef struct WORKREQ @@ -126,6 +137,8 @@ typedef struct WORKREQ #define LPSZSRCFILE param2 #define LPSZDIRECTORY param2 #define LPSZSEARCHFILE param2 +#define LPSZHEADER param2 +#define LPSZVERB param2 DWORD param3; #define LPSZNEWREMOTEFILE param3 @@ -134,18 +147,27 @@ typedef struct WORKREQ #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 @@ HINTERNET FTP_Connect(HINTERNET hInterent, LPCSTR lpszServerName, 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 @@ void INTERNET_SetLastError(DWORD dwError); 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 @@ BOOLAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN 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 a09b66fc3e8..21e050c0279 100644 --- a/dlls/wininet/utility.c +++ b/dlls/wininet/utility.c @@ -111,10 +111,12 @@ time_t ConvertTimeString(LPCSTR asctime) 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 6ee7e52d7c7..35845052937 100644 --- a/dlls/wininet/wininet.spec +++ b/dlls/wininet/wininet.spec @@ -69,15 +69,15 @@ init WININET_LibMain @ 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 @@ init WININET_LibMain @ 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