mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-22 19:21:23 +00:00
GSWApp. * GSWeb.framework/GSWStatisticsStore.m ([GSWStatisticsStore -init]): retain startDate. * GSWAdaptors/common/GSWUtil.c: use vsnprintf to prevent buffer overflow. * GSWAdaptors/common/GSWHTTPRequest.c (GSWHTTPRequest_SendRequest): terminate buffer. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@9220 72102866-910b-0410-8b05-ffd578937521
364 lines
12 KiB
C
364 lines
12 KiB
C
/* GSWHTTPRequest.c - GSWeb: Adaptors: HTTP Request
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
|
Date: Jully 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 "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 CONST char* GSWebHeaderForHTTPHeader(CONST char *header);
|
|
static char* GSWHTTPRequest_PackageHeaders(GSWHTTPRequest* p_pHTTPRequest,
|
|
char* pszBuffer,
|
|
int p_iBufferSize);
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
GSWHTTPRequest* GSWHTTPRequest_New(CONST char* p_pszMethod,char* p_pszURI,void* p_pLogServerData)
|
|
{
|
|
GSWHTTPRequest* pHTTPRequest=calloc(1,sizeof(GSWHTTPRequest));
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Start GSWHTTPRequest_New");
|
|
pHTTPRequest->eMethod = GetHTTPRequestMethod(p_pszMethod);
|
|
pHTTPRequest->pszRequest = p_pszURI; // It will be freed
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Stop GSWHTTPRequest_New");
|
|
return pHTTPRequest;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
void GSWHTTPRequest_Free(GSWHTTPRequest* p_pHTTPRequest,void* p_pLogServerData)
|
|
{
|
|
GSWLog(GSW_DEBUG,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;
|
|
};
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Stop GSWHTTPRequest_Free");
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
CONST char* GSWHTTPRequest_ValidateMethod(GSWHTTPRequest* p_pHTTPRequest,void* p_pLogServerData)
|
|
{
|
|
CONST char* pszMsg=NULL;
|
|
GSWLog(GSW_DEBUG,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;
|
|
};
|
|
};
|
|
GSWLog(GSW_DEBUG,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 = p_pszHTTPVersion ? strlen(p_pszHTTPVersion) : strlen(pszDefaultHTTPVersion);
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Start GSWHTTPRequest_HTTPToAppRequest");
|
|
if (p_pAppRequest->iInstance > 0) /* should be -1 !!! */
|
|
sprintf(szInstanceBuffer,"%d",p_pAppRequest->iInstance);
|
|
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);
|
|
|
|
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");
|
|
|
|
GSWLog(GSW_INFO,p_pLogServerData,"App Request: %s",p_pHTTPRequest->pszRequest);
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Stop GSWHTTPRequest_HTTPToAppRequest");
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
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;
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Start GSWHTTPRequest_SendRequest");
|
|
iRequestLength = strlen(p_pHTTPRequest->pszRequest);
|
|
iContentLength = p_pHTTPRequest->uContentLength;
|
|
#ifdef DEBUG
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"Request:%s",p_pHTTPRequest->pszRequest);
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"iContentLength:%d",iContentLength);
|
|
#endif
|
|
|
|
GSWDict_PerformForAllElem(p_pHTTPRequest->pHeaders,
|
|
GetHeaderLength,
|
|
&iHeaderLength);
|
|
iHeaderLength++; // Last /n
|
|
iLength=iRequestLength+iHeaderLength+iContentLength;
|
|
#ifdef DEBUG
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"iHeaderLength:%d",iHeaderLength);
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"iLength:%d",iLength);
|
|
#endif
|
|
|
|
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';
|
|
|
|
GSWLog(GSW_INFO,p_pLogServerData,
|
|
"Sending AppRequest Content: %s\n(%d Bytes)",
|
|
p_pHTTPRequest->pszRequest,
|
|
iContentLength);
|
|
// Just To be sure of the length
|
|
iLength = pszTmp - pszBuffer;
|
|
#ifdef DEBUG
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"pszBuffer:%s",pszBuffer);
|
|
GSWLog(GSW_DEBUG,p_pLogServerData,"iLength:%d",iLength);
|
|
#endif
|
|
fOk = GSWApp_SendBlock(p_socket,pszBuffer,iLength,p_pLogServerData);
|
|
free(pszBuffer);
|
|
pszBuffer=NULL;
|
|
GSWLog(GSW_DEBUG,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;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
static int compareHeader(CONST void* p_pKey0,CONST void* p_pKey1)
|
|
{
|
|
CONST char* pKey1=((GSWHeaderTranslationItem*)p_pKey1)->pszHTTP;
|
|
/*
|
|
if (p_pKey0)
|
|
GSWLog(GSW_ERROR,NULL,"p_pKey0=%p (CONST char*)p_pKey0=%s",p_pKey0,(CONST char*)p_pKey0);
|
|
if (p_pKey1)
|
|
{
|
|
if (((GSWHeaderTranslationItem*)p_pKey1)->pszHTTP)
|
|
GSWLog(GSW_ERROR,NULL,"p_pKey1=%p (CONST char*)p_pKey1=%s",p_pKey1,((GSWHeaderTranslationItem*)p_pKey1)->pszHTTP);
|
|
|
|
};
|
|
*/
|
|
if (pKey1)
|
|
return strcmp((CONST char*)p_pKey0,pKey1);
|
|
else if (!p_pKey0)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
static CONST char* GSWebHeaderForHTTPHeader(CONST char* p_pszHTTPHeader)
|
|
{
|
|
GSWHeaderTranslationItem* pItem=NULL;
|
|
if (GSWHeaderTranslationTableItemsNb==0)
|
|
GSWHeaderTranslationTable_Init();
|
|
pItem=bsearch(p_pszHTTPHeader,
|
|
GSWHeaderTranslationTable,
|
|
GSWHeaderTranslationTableItemsNb,
|
|
sizeof(GSWHeaderTranslationItem),
|
|
compareHeader);
|
|
return (pItem ? pItem->pszGSWeb : NULL);
|
|
};
|