mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-23 11:41:20 +00:00
o Time statistics addition git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@20489 72102866-910b-0410-8b05-ffd578937521
399 lines
12 KiB
C
399 lines
12 KiB
C
/* GSWHTTPRequest.c - GSWeb: Adaptors: HTTP Request
|
|
Copyright (C) 1999, 2000, 2001, 2003-2004 Free Software Foundation, Inc.
|
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
|
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 <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#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;
|
|
};
|
|
|