php-src/sapi/litespeed/lsapilib.c
2006-01-13 03:21:51 +00:00

1128 lines
30 KiB
C

/*
Copyright (c) 2005, Lite Speed Technologies Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the Lite Speed Technologies Inc nor the
names of its contributors may be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/***************************************************************************
lsapilib.c - description
-------------------
begin : Mon Feb 21 2005
copyright : (C) 2005 by George Wang
email : gwang@litespeedtech.com
***************************************************************************/
#include <lsapilib.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
//#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#define LSAPI_ST_REQ_HEADER 1
#define LSAPI_ST_REQ_BODY 2
#define LSAPI_ST_RESP_HEADER 4
#define LSAPI_ST_RESP_BODY 8
#define LSAPI_RESP_BUF_SIZE 8192
#define LSAPI_INIT_RESP_HEADER_LEN 4096
static int g_inited = 0;
static int g_running = 1;
LSAPI_Request g_req;
void Flush_RespBuf_r( LSAPI_Request * pReq );
static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
{
"HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET",
"HTTP_ACCEPT_ENCODING",
"HTTP_ACCEPT_LANG", "HTTP_AUTHORIZATION",
"HTTP_CONNECTION", "CONTENT_TYPE",
"CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2",
"HTTP_HOST", "HTTP_PRAGMA",
"HTTP_REFERER", "HTTP_USER_AGENT",
"HTTP_CACHE_CTRL",
"HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH",
"HTTP_IF_NONE_MATCH",
"HTTP_IF_RANGE",
"HTTP_IF_UNMODIFIED_SINCE",
"HTTP_KEEPALIVE",
"HTTP_RANGE",
"HTTP_X_FORWARDED_FOR",
"HTTP_VIA",
"HTTP_TRANSFER_ENCODING"
};
static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] =
{ 11, 19, 20, 16, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 15,
22, 13, 18, 13, 24, 14, 10, 20, 8, 22 };
static void lsapi_sigpipe( int sig )
{
}
static void lsapi_siguser1( int sig )
{
g_running = 0;
}
#ifndef sighandler_t
typedef void (*sighandler_t)(int);
#endif
static void lsapi_signal(int signo, sighandler_t handler)
{
struct sigaction sa;
sigaction(signo, NULL, &sa);
if (sa.sa_handler == SIG_DFL)
{
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = handler;
sigaction(signo, &sa, NULL);
}
}
static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader,
char type, int len )
{
pHeader->m_versionB0 = LSAPI_VERSION_B0; //LSAPI protocol version
pHeader->m_versionB1 = LSAPI_VERSION_B1;
pHeader->m_type = type;
pHeader->m_flag = LSAPI_ENDIAN;
pHeader->m_packetLen.m_iLen = len;
}
static int lsapi_close( int fd )
{
int ret;
while( 1 )
{
ret = close( fd );
if (( ret == -1 )&&( errno == EINTR )&&(g_running))
continue;
return ret;
}
}
static inline int lsapi_read( int fd, void * pBuf, int len )
{
int ret;
while( 1 )
{
ret = read( fd, (char *)pBuf, len );
if (( ret == -1 )&&( errno == EINTR )&&(g_running))
continue;
return ret;
}
}
//static int lsapi_write( int fd, const void * pBuf, int len )
//{
// int ret;
// const char * pCur;
// const char * pEnd;
// if ( len == 0 )
// return 0;
// pCur = (const char *)pBuf;
// pEnd = pCur + len;
// while( g_running && (pCur < pEnd) )
// {
// ret = write( fd, pCur, pEnd - pCur );
// if ( ret >= 0)
// pCur += ret;
// else if (( ret == -1 )&&( errno != EINTR ))
// return ret;
// }
// return pCur - (const char *)pBuf;
//}
static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
{
int ret;
int left = totalLen;
int n = count;
while(( left > 0 )&&g_running )
{
ret = writev( fd, *pVec, n );
if ( ret > 0 )
{
left -= ret;
if (( left <= 0)||( !g_running ))
return totalLen - left;
while( ret > 0 )
{
if ( (*pVec)->iov_len <= ret )
{
ret -= (*pVec)->iov_len;
++(*pVec);
}
else
{
(*pVec)->iov_base = (char *)(*pVec)->iov_base + ret;
(*pVec)->iov_len -= ret;
break;
}
}
}
else if (( ret == -1 )&&( errno != EINTR ))
return ret;
}
return totalLen - left;
}
//static int getTotalLen( struct iovec * pVec, int count )
//{
// struct iovec * pEnd = pVec + count;
// int total = 0;
// while( pVec < pEnd )
// {
// total += pVec->iov_len;
// ++pVec;
// }
// return total;
//}
static inline int allocateBuf( LSAPI_Request * pReq, int size )
{
char * pBuf = (char *)realloc( pReq->m_pReqBuf, size );
if ( pBuf )
{
pReq->m_pReqBuf = pBuf;
pReq->m_reqBufSize = size;
pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf;
return 0;
}
return -1;
}
static int allocateIovec( LSAPI_Request * pReq, int n )
{
struct iovec * p = (struct iovec *)realloc(
pReq->m_pIovec, sizeof(struct iovec) * n );
if ( !p )
return -1;
pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec );
pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec );
pReq->m_pIovec = p;
pReq->m_pIovecEnd = p + n;
return 0;
}
static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size )
{
char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size );
if ( !p )
return -1;
pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf );
pReq->m_pRespHeaderBuf = p;
pReq->m_pRespHeaderBufEnd = p + size;
return 0;
}
static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType )
{
if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )||
( LSAPI_VERSION_B1 != pHeader->m_versionB1 )||
( pktType != pHeader->m_type ))
return -1;
if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT ))
{
register char b;
b = pHeader->m_packetLen.m_bytes[0];
pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3];
pHeader->m_packetLen.m_bytes[3] = b;
b = pHeader->m_packetLen.m_bytes[1];
pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2];
pHeader->m_packetLen.m_bytes[2] = b;
}
return pHeader->m_packetLen.m_iLen;
}
static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList,
int *curSize, int newSize )
{
struct LSAPI_key_value_pair * pBuf;
if ( *curSize >= newSize )
return 0;
if ( newSize > 8192 )
return -1;
pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize *
sizeof(struct LSAPI_key_value_pair) );
if ( pBuf )
{
*pEnvList = pBuf;
*curSize = newSize;
return 0;
}
else
return -1;
}
static inline int isPipe( int fd )
{
char achPeer[128];
int len = 128;
if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
( errno == ENOTCONN ))
return 0;
else
return 1;
}
static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
char **pBegin, char * pEnd )
{
struct LSAPI_key_value_pair * pEnvEnd;
int keyLen = 0, valLen = 0;
if ( count > 8192 )
return -1;
pEnvEnd = pEnvList + count;
while( pEnvList != pEnvEnd )
{
if ( pEnd - *pBegin < 4 )
return -1;
keyLen = *((unsigned char *)((*pBegin)++));
keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++));
valLen = *((unsigned char *)((*pBegin)++));
valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++));
if ( *pBegin + keyLen + valLen > pEnd )
return -1;
if (( !keyLen )||( !valLen ))
return -1;
pEnvList->pKey = *pBegin;
*pBegin += keyLen;
pEnvList->pValue = *pBegin;
*pBegin += valLen;
pEnvList->keyLen = keyLen - 1;
pEnvList->valLen = valLen - 1;
++pEnvList;
}
if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 )
return -1;
*pBegin += 4;
return 0;
}
static inline void swapIntEndian( int * pInteger )
{
char * p = (char *)pInteger;
register char b;
b = p[0];
p[0] = p[3];
p[3] = b;
b = p[1];
p[1] = p[2];
p[2] = b;
}
static inline void fixEndian( LSAPI_Request * pReq )
{
struct lsapi_req_header *p= pReq->m_pHeader;
swapIntEndian( &p->m_httpHeaderLen );
swapIntEndian( &p->m_reqBodyLen );
swapIntEndian( &p->m_scriptFileOff );
swapIntEndian( &p->m_scriptNameOff );
swapIntEndian( &p->m_queryStringOff );
swapIntEndian( &p->m_requestMethodOff );
swapIntEndian( &p->m_cntUnknownHeaders );
swapIntEndian( &p->m_cntEnv );
swapIntEndian( &p->m_cntSpecialEnv );
}
static void fixHeaderIndexEndian( LSAPI_Request * pReq )
{
int i;
for( i = 0; i < H_TRANSFER_ENCODING; ++i )
{
if ( pReq->m_pHeaderIndex->m_headerOff[i] )
{
register char b;
char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]);
b = p[0];
p[0] = p[1];
p[1] = b;
swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] );
}
}
if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
{
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
while( pCur < pEnd )
{
swapIntEndian( &pCur->nameOff );
swapIntEndian( &pCur->nameLen );
swapIntEndian( &pCur->valueOff );
swapIntEndian( &pCur->valueLen );
++pCur;
}
}
}
static int parseRequest( LSAPI_Request * pReq, int totalLen )
{
int shouldFixEndian;
char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header );
char * pEnd = pReq->m_pReqBuf + totalLen;
shouldFixEndian = ( LSAPI_ENDIAN != (
pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) );
if ( shouldFixEndian )
{
fixEndian( pReq );
}
if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&&
allocateEnvList( &pReq->m_pSpecialEnvList,
&pReq->m_specialEnvListSize,
pReq->m_pHeader->m_cntSpecialEnv ) == -1 )
return -1;
if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&&
allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize,
pReq->m_pHeader->m_cntEnv ) == -1 )
return -1;
if ( parseEnv( pReq->m_pSpecialEnvList,
pReq->m_pHeader->m_cntSpecialEnv,
&pBegin, pEnd ) == -1 )
return -1;
if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
&pBegin, pEnd ) == -1 )
return -1;
pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff;
pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff;
pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff;
pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff;
pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7));
pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin;
pBegin += sizeof( struct lsapi_http_header_index );
pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin;
pBegin += sizeof( struct lsapi_header_offset) *
pReq->m_pHeader->m_cntUnknownHeaders;
pReq->m_pHttpHeader = pBegin;
pBegin += pReq->m_pHeader->m_httpHeaderLen;
if ( pBegin != pEnd )
return -1;
if ( shouldFixEndian )
{
fixHeaderIndexEndian( pReq );
}
return 0;
}
static struct lsapi_packet_header ack = {'L', 'S',
LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
static inline int notify_req_received( LSAPI_Request * pReq )
{
if ( write( pReq->m_fd, &ack, LSAPI_PACKET_HEADER_LEN )
< LSAPI_PACKET_HEADER_LEN )
return -1;
return 0;
}
static int readReq( LSAPI_Request * pReq )
{
int len;
int packetLen;
if ( !pReq )
return -1;
if ( pReq->m_reqBufSize < 8192 )
{
if ( allocateBuf( pReq, 8192 ) == -1 )
return -1;
}
while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN )
{
len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize );
if ( len <= 0 )
return -1;
pReq->m_bufRead += len;
}
pReq->m_reqState = LSAPI_ST_REQ_HEADER;
packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST );
if ( packetLen < 0 )
return -1;
if ( packetLen > LSAPI_MAX_HEADER_LEN )
return -1;
if ( packetLen > pReq->m_reqBufSize )
{
if ( allocateBuf( pReq, packetLen ) == -1 )
return -1;
}
while( packetLen > pReq->m_bufRead )
{
len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead );
if ( len <= 0 )
return -1;
pReq->m_bufRead += len;
}
if ( parseRequest( pReq, packetLen ) < 0 )
return -1;
pReq->m_bufProcessed = packetLen;
pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER;
return notify_req_received( pReq );
}
int LSAPI_Init(void)
{
if ( !g_inited )
{
lsapi_signal(SIGPIPE, lsapi_sigpipe);
lsapi_signal(SIGUSR1, lsapi_siguser1);
if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 )
return -1;
g_inited = 1;
}
return 0;
}
void LSAPI_stop(void)
{
g_running = 0;
}
int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
{
if ( !pReq )
return -1;
memset( pReq, 0, sizeof( LSAPI_Request ) );
if ( allocateIovec( pReq, 16 ) == -1 )
return -1;
pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE );
if ( !pReq->m_pRespBuf )
return -1;
pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5];
if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 )
return -1;
if ( isPipe( fd ) )
{
pReq->m_fdListen = -1;
pReq->m_fd = fd;
}
else
{
pReq->m_fdListen = fd;
pReq->m_fd = -1;
}
return 0;
}
int LSAPI_Is_Listen( void )
{
return LSAPI_Is_Listen_r( &g_req );
}
int LSAPI_Is_Listen_r( LSAPI_Request * pReq)
{
return pReq->m_fdListen != -1;
}
int LSAPI_Accept_r( LSAPI_Request * pReq )
{
char achPeer[128];
int len;
int nodelay = 1;
if ( !pReq )
return -1;
if ( LSAPI_Finish_r( pReq ) == -1 )
return -1;
while( g_running )
{
if ( pReq->m_fd == -1 )
{
if ( pReq->m_fdListen != -1)
{
len = sizeof( achPeer );
pReq->m_fd = accept( pReq->m_fdListen,
(struct sockaddr *)&achPeer, &len );
if (( pReq->m_fd == -1 )&&( errno == EINTR ))
continue;
if (( pReq->m_fd != -1 )&&
(((struct sockaddr *)&achPeer)->sa_family == AF_INET ))
{
setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY,
(char *)&nodelay, sizeof(nodelay));
}
}
else
return -1;
}
if ( !readReq( pReq ) )
break;
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
LSAPI_Reset_r( pReq );
}
return 0;
}
static struct lsapi_packet_header finish = {'L', 'S',
LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
int LSAPI_Finish_r( LSAPI_Request * pReq )
{
//finish req body
if ( !pReq )
return -1;
if (pReq->m_reqState)
{
if ( pReq->m_fd != -1 )
{
if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
{
LSAPI_FinalizeRespHeaders_r( pReq );
}
if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
{
Flush_RespBuf_r( pReq );
}
pReq->m_pIovecCur->iov_base = (void *)&finish;
pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN;
++pReq->m_pIovecCur;
LSAPI_Flush_r( pReq );
}
LSAPI_Reset_r( pReq );
}
return 0;
}
void LSAPI_Reset_r( LSAPI_Request * pReq )
{
pReq->m_pRespBufPos = pReq->m_pRespBuf;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf;
memset( &pReq->m_pHeaderIndex, 0,
(char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex );
}
int LSAPI_Release_r( LSAPI_Request * pReq )
{
if ( pReq->m_pReqBuf )
free( pReq->m_pReqBuf );
if ( pReq->m_pSpecialEnvList )
free( pReq->m_pSpecialEnvList );
if ( pReq->m_pEnvList )
free( pReq->m_pEnvList );
if ( pReq->m_pRespHeaderBuf )
free( pReq->m_pRespHeaderBuf );
return 0;
}
char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
{
int off;
if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) )
return NULL;
off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ];
if ( !off )
return NULL;
if ( *(pReq->m_pHttpHeader + off +
pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) )
*( pReq->m_pHttpHeader + off +
pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
return pReq->m_pHttpHeader + off;
}
int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
{
int len;
int total;
//char *pOldBuf = pBuf;
if (!pReq || ( !pBuf )||(bufLen < 0 ))
return -1;
total = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
if ( total <= 0 )
return 0;
if ( total < bufLen )
bufLen = total;
total = 0;
len = pReq->m_bufRead - pReq->m_bufProcessed;
if ( len > 0 )
{
if ( len > bufLen )
len = bufLen;
memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len );
pReq->m_bufProcessed += len;
total += len;
pBuf += len;
bufLen -= len;
}
while( bufLen > 0 )
{
len = lsapi_read( pReq->m_fd, pBuf, bufLen );
if ( len > 0 )
{
total += len;
pBuf += len;
bufLen -= len;
}
else if ( len < 0 )
return -1;
}
pReq->m_reqBodyRead += total;
return total;
}
//int LSAPI_Write( const char * pBuf, int len )
//{
// return LSAPI_Write_r( &g_req, pBuf, len );
//}
int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
{
struct lsapi_packet_header * pHeader;
const char * pEnd;
const char * p;
int bufLen;
int toWrite;
int packetLen;
if ( !pReq || !pBuf )
return -1;
if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos )
{
memmove( pReq->m_pRespBufPos, pBuf, len );
pReq->m_pRespBufPos += len;
return len;
}
if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
{
LSAPI_FinalizeRespHeaders_r( pReq );
}
pReq->m_reqState |= LSAPI_ST_RESP_BODY;
pHeader = pReq->m_respPktHeader;
p = pBuf;
pEnd = pBuf + len;
bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
while( ( toWrite = pEnd - p ) > 0 )
{
packetLen = toWrite + bufLen;
if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
{
packetLen = LSAPI_MAX_DATA_PACKET_LEN;
toWrite = packetLen - bufLen;
}
lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
packetLen + LSAPI_PACKET_HEADER_LEN );
pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN;
pReq->m_pIovecCur->iov_base = (void *)pHeader;
pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
++pReq->m_pIovecCur;
++pHeader;
if ( bufLen > 0 )
{
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
pReq->m_pIovecCur->iov_len = bufLen;
pReq->m_pRespBufPos = pReq->m_pRespBuf;
++pReq->m_pIovecCur;
bufLen = 0;
}
pReq->m_pIovecCur->iov_base = (void *)p;
pReq->m_pIovecCur->iov_len = toWrite;
++pReq->m_pIovecCur;
p += toWrite;
if ( pHeader >= pReq->m_respPktHeaderEnd - 1)
{
if ( LSAPI_Flush_r( pReq ) == -1 )
return -1;
pHeader = pReq->m_respPktHeader;
}
}
if ( pHeader != pReq->m_respPktHeader )
if ( LSAPI_Flush_r( pReq ) == -1 )
return -1;
return p - pBuf;
}
void Flush_RespBuf_r( LSAPI_Request * pReq )
{
struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
pReq->m_reqState |= LSAPI_ST_RESP_BODY;
lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
bufLen + LSAPI_PACKET_HEADER_LEN );
pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN;
pReq->m_pIovecCur->iov_base = (void *)pHeader;
pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
++pReq->m_pIovecCur;
++pHeader;
if ( bufLen > 0 )
{
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
pReq->m_pIovecCur->iov_len = bufLen;
pReq->m_pRespBufPos = pReq->m_pRespBuf;
++pReq->m_pIovecCur;
bufLen = 0;
}
}
int LSAPI_Flush_r( LSAPI_Request * pReq )
{
int ret = 0;
int n;
if ( !pReq )
return -1;
if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
{
LSAPI_FinalizeRespHeaders_r( pReq );
}
if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
{
Flush_RespBuf_r( pReq );
}
n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
if ( n > 0 )
{
ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite,
n, pReq->m_totalLen );
if ( ret < pReq->m_totalLen )
{
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
ret = -1;
}
pReq->m_totalLen = 0;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
}
return ret;
}
int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
{
struct lsapi_packet_header header;
const char * pEnd;
const char * p;
int packetLen;
int totalLen;
int ret;
struct iovec iov[2];
struct iovec *pIov;
if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
{
LSAPI_Flush_r( pReq );
}
p = pBuf;
pEnd = pBuf + len;
while( ( packetLen = pEnd - p ) > 0 )
{
if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
{
packetLen = LSAPI_MAX_DATA_PACKET_LEN;
}
lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM,
packetLen + LSAPI_PACKET_HEADER_LEN );
totalLen = packetLen + LSAPI_PACKET_HEADER_LEN;
iov[0].iov_base = (void *)&header;
iov[0].iov_len = LSAPI_PACKET_HEADER_LEN;
iov[1].iov_base = (void *)p;
iov[1].iov_len = packetLen;
p += packetLen;
pIov = iov;
ret = lsapi_writev( pReq->m_fd, &pIov,
2, totalLen );
if ( ret < totalLen )
{
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
ret = -1;
}
}
return p - pBuf;
}
char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
{
struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList;
struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
if ( !pReq || !name )
return NULL;
while( pBegin < pEnd )
{
if ( strcmp( name, pBegin->pKey ) == 0 )
return pBegin->pValue;
++pBegin;
}
return NULL;
}
int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
int i;
int len = 0;
char * pValue;
int ret;
int count = 0;
if ( !pReq || !fn )
return -1;
for( i = 0; i < H_TRANSFER_ENCODING; ++i )
{
if ( pReq->m_pHeaderIndex->m_headerOff[i] )
{
len = pReq->m_pHeaderIndex->m_headerLen[i];
pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
*(pValue + len ) = 0;
ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
pValue, len, arg );
++count;
if ( ret <= 0 )
return ret;
}
}
if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
{
char achHeaderName[256];
char *p;
char *pKey;
char *pKeyEnd ;
int keyLen;
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
while( pCur < pEnd )
{
pKey = pReq->m_pHttpHeader + pCur->nameOff;
keyLen = pCur->nameLen;
pKeyEnd = pKey + keyLen;
memcpy( achHeaderName, "HTTP_", 5 );
p = &achHeaderName[5];
if ( keyLen > 250 )
keyLen = 250;
while( pKey < pKeyEnd )
{
char ch = *pKey++;
if ( ch == '-' )
*p++ = '_';
else
*p++ = toupper( ch );
}
*p = 0;
keyLen += 5;
pValue = pReq->m_pHttpHeader + pCur->valueOff;
*(pValue + pCur->valueLen ) = 0;
ret = (*fn)( achHeaderName, pCur->valueLen,
pValue, len, arg );
if ( ret <= 0 )
return ret;
++pCur;
}
}
return count + pReq->m_pHeader->m_cntUnknownHeaders;
}
static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
int n, LSAPI_CB_EnvHandler fn, void * arg )
{
struct LSAPI_key_value_pair * pEnd = pEnv + n;
int ret;
if ( !pEnv || !fn )
return -1;
while( pEnv < pEnd )
{
ret = (*fn)( pEnv->pKey, pEnv->keyLen,
pEnv->pValue, pEnv->valLen, arg );
if ( ret <= 0 )
return ret;
++pEnv;
}
return n;
}
int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
if ( !pReq || !fn )
return -1;
if ( pReq->m_pHeader->m_cntEnv > 0 )
{
return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
fn, arg );
}
return 0;
}
int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
if ( !pReq || !fn )
return -1;
if ( pReq->m_pHeader->m_cntSpecialEnv > 0 )
{
return EnvForeach( pReq->m_pSpecialEnvList,
pReq->m_pHeader->m_cntSpecialEnv,
fn, arg );
}
return 0;
}
int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
{
if ( !pReq || !pReq->m_pIovec )
return -1;
if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) )
return 0;
pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER;
if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf )
{
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf;
pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
pReq->m_totalLen += pReq->m_pIovecCur->iov_len;
++pReq->m_pIovecCur;
}
pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header)
+ pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short );
pReq->m_totalLen += pReq->m_pIovec->iov_len;
lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader,
LSAPI_RESP_HEADER, pReq->m_totalLen );
pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader;
pReq->m_pIovecToWrite = pReq->m_pIovec;
return 0;
}
int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len )
{
if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX )
return -1;
if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
return -1;
if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
return -1;
if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
{
int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
newlen -= newlen % 4096;
if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
return -1;
}
memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
pReq->m_pRespHeaderBufPos += len;
*pReq->m_pRespHeaderBufPos++ = 0;
++len; //add one byte padding for \0
pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
++pReq->m_respHeader.m_respInfo.m_cntHeaders;
return 0;
}