/* GSWHTTPRequest.c - GSWeb: Adaptors: HTTP Request Copyright (C) 1999, 2000, 2001, 2003-2004 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: July 1999 This file is part of the GNUstep Web Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "config.h" #include "GSWUtil.h" #include "GSWStats.h" #include "GSWDict.h" #include "GSWURLUtil.h" #include "GSWAppRequestStruct.h" #include "GSWAppConnect.h" #include "GSWHTTPRequest.h" #include "GSWHTTPResponse.h" #include "GSWAppRequest.h" #include "GSWHTTPHeaders.h" static ERequestMethod GetHTTPRequestMethod(); static char *GSWHTTPRequest_PackageHeaders(GSWHTTPRequest *p_pHTTPRequest, char *pszBuffer, int p_iBufferSize); static void GSWHTTPRequest_AddHeaderElem(GSWDictElem *p_pElem, void* p_pHTTPRequest); //GSWHTTPRequest * //-------------------------------------------------------------------- GSWHTTPRequest * GSWHTTPRequest_New(CONST char *p_pszMethod, char *p_pszURI, GSWTimeStats *p_pStats, void *p_pLogServerData) { GSWHTTPRequest *pHTTPRequest=calloc(1,sizeof(GSWHTTPRequest)); GSWDebugLog(p_pLogServerData,"Start GSWHTTPRequest_New"); pHTTPRequest->eMethod = GetHTTPRequestMethod(p_pszMethod); pHTTPRequest->pszRequest = p_pszURI; // It will be freed pHTTPRequest->pStats=p_pStats; GSWDebugLog(p_pLogServerData,"Stop GSWHTTPRequest_New"); return pHTTPRequest; }; //-------------------------------------------------------------------- void GSWHTTPRequest_Free(GSWHTTPRequest *p_pHTTPRequest, void *p_pLogServerData) { GSWDebugLog(p_pLogServerData,"Start GSWHTTPRequest_Free"); if (p_pHTTPRequest) { if (p_pHTTPRequest->pHeaders) { GSWDict_Free(p_pHTTPRequest->pHeaders); p_pHTTPRequest->pHeaders=NULL; }; if (p_pHTTPRequest->pszRequest) { free(p_pHTTPRequest->pszRequest); p_pHTTPRequest->pszRequest=NULL; }; if (p_pHTTPRequest->pContent) { free(p_pHTTPRequest->pContent); p_pHTTPRequest->pContent=NULL; }; free(p_pHTTPRequest); p_pHTTPRequest=NULL; }; GSWDebugLog(p_pLogServerData,"Stop GSWHTTPRequest_Free"); }; //-------------------------------------------------------------------- CONST char * GSWHTTPRequest_ValidateMethod(GSWHTTPRequest *p_pHTTPRequest, void *p_pLogServerData) { CONST char *pszMsg=NULL; GSWDebugLog(p_pLogServerData,"Start GSWHTTPRequest_ValidateMethod"); if (!p_pHTTPRequest) { GSWLog(GSW_CRITICAL,p_pLogServerData, "No Request in GSWHTTPRequest_ValidateMethod"); pszMsg="No Request in GSWHTTPRequest_ValidateMethod"; } else { switch(p_pHTTPRequest->eMethod) { case ERequestMethod_None: pszMsg="GSWeb Application must be launched by HTTP Server"; break; case ERequestMethod_Unknown: case ERequestMethod_Head: case ERequestMethod_Put: pszMsg="Invalid Method"; break; case ERequestMethod_Get: case ERequestMethod_Post: default: pszMsg=NULL; }; }; GSWDebugLog(p_pLogServerData,"Stop GSWHTTPRequest_ValidateMethod"); return pszMsg; }; //-------------------------------------------------------------------- void GSWHTTPRequest_HTTPToAppRequest(GSWHTTPRequest *p_pHTTPRequest, GSWAppRequest *p_pAppRequest, GSWURLComponents *p_pURLComponents, CONST char *p_pszHTTPVersion, void *p_pLogServerData) { char szInstanceBuffer[65]=""; char *pszDefaultHTTPVersion = "HTTP/1.0"; int iHTTPVersionLength = 0; GSWApp* pApp=p_pAppRequest->pAppInstance->pApp; GSWDebugLog(p_pLogServerData,"Start GSWHTTPRequest_HTTPToAppRequest"); iHTTPVersionLength = (p_pszHTTPVersion ? strlen(p_pszHTTPVersion) : strlen(pszDefaultHTTPVersion)); GSWAssert(p_pAppRequest,p_pLogServerData,"No p_pAppRequest"); if (p_pAppRequest->iInstance > 0) /* should be -1 !!! */ sprintf(szInstanceBuffer,"%d",p_pAppRequest->iInstance); GSWAssert(p_pURLComponents,p_pLogServerData,"No p_pURLComponents"); p_pURLComponents->stAppName.pszStart = p_pAppRequest->pszName; p_pURLComponents->stAppName.iLength = strlen(p_pAppRequest->pszName); p_pURLComponents->stAppNumber.pszStart = szInstanceBuffer; p_pURLComponents->stAppNumber.iLength = strlen(szInstanceBuffer); p_pURLComponents->stAppHost.pszStart = p_pAppRequest->pszHost; p_pURLComponents->stAppHost.iLength = strlen(p_pAppRequest->pszHost); GSWAssert(p_pHTTPRequest,p_pLogServerData,"No p_pHTTPRequest"); if (p_pHTTPRequest->pszRequest) { free(p_pHTTPRequest->pszRequest); p_pHTTPRequest->pszRequest=NULL; }; p_pHTTPRequest->pszRequest=malloc(8+ (GSWComposeURLLen(p_pURLComponents, p_pLogServerData)+1)+ iHTTPVersionLength); if (p_pHTTPRequest->uContentLength>0) { strcpy(p_pHTTPRequest->pszRequest,"POST "); GSWHTTPRequest_AddHeader(p_pHTTPRequest,g_szHeader_GSWeb_RequestMethod, "POST"); } else { strcpy(p_pHTTPRequest->pszRequest,"GET "); GSWHTTPRequest_AddHeader(p_pHTTPRequest,g_szHeader_GSWeb_RequestMethod, "GET"); }; GSWComposeURL(p_pHTTPRequest->pszRequest+strlen(p_pHTTPRequest->pszRequest), p_pURLComponents, p_pLogServerData); strcat(p_pHTTPRequest->pszRequest," "); if (p_pszHTTPVersion) strcat(p_pHTTPRequest->pszRequest,p_pszHTTPVersion); else strcat(p_pHTTPRequest->pszRequest,pszDefaultHTTPVersion); strcat(p_pHTTPRequest->pszRequest,"\n"); // Add Application Headers GSWDebugLog(p_pLogServerData,"App Specific Headers"); GSWDict_DebugLog(&pApp->stHeadersDict,p_pLogServerData); GSWDict_PerformForAllElem(&pApp->stHeadersDict, GSWHTTPRequest_AddHeaderElem, (void*)p_pHTTPRequest); GSWDebugLogCond(p_pHTTPRequest->pHeaders, p_pLogServerData,"HTTP Request Headers"); GSWDict_Log(p_pHTTPRequest->pHeaders,p_pLogServerData); GSWLog(GSW_INFO,p_pLogServerData,"App Request: %s", p_pHTTPRequest->pszRequest); GSWDebugLog(p_pLogServerData,"Stop GSWHTTPRequest_HTTPToAppRequest"); }; //-------------------------------------------------------------------- static void GSWHTTPRequest_AddHeaderElem(GSWDictElem *p_pElem, void* p_pHTTPRequest) //GSWHTTPRequest * { GSWHTTPRequest_AddHeader(p_pHTTPRequest, p_pElem->pszKey, p_pElem->pValue); }; //-------------------------------------------------------------------- void GSWHTTPRequest_AddHeader(GSWHTTPRequest *p_pHTTPRequest, CONST char *p_pszKey, CONST char *p_pszValue) { CONST char *pszCustomKey=GSWebHeaderForHTTPHeader(p_pszKey); CONST char *pszHeaderKey=(pszCustomKey) ? pszCustomKey : p_pszKey; if (!p_pHTTPRequest->pHeaders) p_pHTTPRequest->pHeaders = GSWDict_New(64); // Search Content Length if (p_pHTTPRequest->eMethod==ERequestMethod_Post && p_pHTTPRequest->uContentLength==0 && strcasecmp(pszHeaderKey,g_szHeader_ContentLength)==0) p_pHTTPRequest->uContentLength = atoi(p_pszValue); GSWDict_AddString(p_pHTTPRequest->pHeaders,pszHeaderKey,p_pszValue,FALSE); }; //-------------------------------------------------------------------- CONST char * GSWHTTPRequest_HeaderForKey(GSWHTTPRequest *p_pHTTPRequest, CONST char *p_pszKey) { if (p_pHTTPRequest->pHeaders) return GSWDict_ValueForKey(p_pHTTPRequest->pHeaders,p_pszKey); else return NULL; }; //-------------------------------------------------------------------- static void GetHeaderLength(GSWDictElem *p_pElem, void *p_piAddTo) { int *piAddTo=(int *)p_piAddTo; // +2=": " // +1="\n" (*piAddTo)+=strlen(p_pElem->pszKey)+strlen((char *)(p_pElem->pValue))+2+1+1; } //-------------------------------------------------------------------- static void FormatHeader(GSWDictElem *p_pElem, void *p_ppszBuffer) { char **ppszBuffer=(char **)p_ppszBuffer; strcpy(*ppszBuffer,p_pElem->pszKey); strcat(*ppszBuffer, ": "); strcat(*ppszBuffer,(char *)p_pElem->pValue); (*ppszBuffer)+= strlen(*ppszBuffer); **ppszBuffer = '\n'; (*ppszBuffer)++; }; //-------------------------------------------------------------------- // Handle Request (send it to Application) BOOL GSWHTTPRequest_SendRequest(GSWHTTPRequest *p_pHTTPRequest, AppConnectHandle p_socket, void *p_pLogServerData) { BOOL fOk = TRUE; char *pszBuffer=NULL; char *pszTmp=NULL; int iLength = 0; int iHeaderLength = 0; int iRequestLength = 0; int iContentLength = 0; GSWDebugLog(p_pLogServerData,"Start GSWHTTPRequest_SendRequest"); p_pHTTPRequest->pStats->_prepareToSendRequestTS=GSWTime_now(); iRequestLength = strlen(p_pHTTPRequest->pszRequest); iContentLength = p_pHTTPRequest->uContentLength; GSWDebugLog(p_pLogServerData,"Request:%s",p_pHTTPRequest->pszRequest); GSWDebugLog(p_pLogServerData,"iContentLength:%d",iContentLength); GSWDict_PerformForAllElem(p_pHTTPRequest->pHeaders, GetHeaderLength, &iHeaderLength); iHeaderLength++; // Last /n iLength=iRequestLength+iHeaderLength+iContentLength; GSWDebugLog(p_pLogServerData,"iHeaderLength:%d",iHeaderLength); GSWDebugLog(p_pLogServerData,"iLength:%d",iLength); pszBuffer = malloc(iLength+1); strncpy(pszBuffer, p_pHTTPRequest->pszRequest, iRequestLength); pszTmp = pszBuffer+iRequestLength; GSWDict_PerformForAllElem(p_pHTTPRequest->pHeaders, FormatHeader, (void *)&pszTmp); *pszTmp++ = '\n'; if (iContentLength>0) { memcpy(pszTmp,p_pHTTPRequest->pContent,iContentLength); pszTmp+=iContentLength; }; *pszTmp = '\0'; GSWDebugLog(p_pLogServerData, "Sending AppRequest Content: %s\n(%d Bytes)", p_pHTTPRequest->pszRequest, iContentLength); // Just To be sure of the length iLength = pszTmp - pszBuffer; GSWDebugLog(p_pLogServerData,"pszBuffer:%s",pszBuffer); GSWDebugLog(p_pLogServerData,"iLength:%d",iLength); p_pHTTPRequest->pStats->_beginSendRequestTS=GSWTime_now(); fOk = GSWApp_SendBlock(p_socket,pszBuffer,iLength,p_pLogServerData); p_pHTTPRequest->pStats->_endSendRequestTS=GSWTime_now(); free(pszBuffer); pszBuffer=NULL; GSWDebugLog(p_pLogServerData,"Stop GSWHTTPRequest_SendRequest"); return fOk; } //-------------------------------------------------------------------- static char * GSWHTTPRequest_PackageHeaders(GSWHTTPRequest *p_pHTTPRequest, char *p_pszBuffer, int p_iBufferSize) { int iHeaderLength=0; char *pszBuffer=NULL; char *pszTmp=NULL; GSWDict_PerformForAllElem(p_pHTTPRequest->pHeaders, GetHeaderLength, (void *)&iHeaderLength); pszBuffer = ((p_iBufferSize > (iHeaderLength+1)) ? p_pszBuffer : malloc(p_iBufferSize+2)); pszTmp = pszBuffer; GSWDict_PerformForAllElem(p_pHTTPRequest->pHeaders,FormatHeader,&pszTmp); *pszTmp++ = '\n'; *pszTmp++ = '\0'; return pszBuffer; }; //-------------------------------------------------------------------- static ERequestMethod GetHTTPRequestMethod(CONST char *pszMethod) { if (pszMethod) { if (strcmp(pszMethod,g_szMethod_Get)==0) return ERequestMethod_Get; else if (strcmp(pszMethod, g_szMethod_Post)==0) return ERequestMethod_Post; else if (!strcmp(pszMethod, g_szMethod_Head)==0) return ERequestMethod_Head; else if (!strcmp(pszMethod,g_szMethod_Put)==0) return ERequestMethod_Put; else return ERequestMethod_Unknown; } else return ERequestMethod_None; };