📄 wincgi.cpp
字号:
PIIOBuffer_delete( pCGIBuffer );
PIObject_delete( pChildIO, 0, 0 );
PIFile_close( tFd );
return bIgnoreStatus;
}
}
PIIOBuffer_delete( pCGIBuffer );
PIObject_delete( pChildIO, 0, 0 );
};
};
PIFile_close( tFd );
/* ---
If a datafile name pattern was specified write the data block
to that file
--- */
if ( pDataFile && pDataBlock )
{
int iDataSize = 4096; /* --- initial guess --- */
int iLen = -1;
char *pData = 0;
for(;;)
{
pData = (char *)PIHTTP_allocMem( &tPIHTTP, iDataSize );
iLen = Pi3Expression_write( pDataBlock, &tPIHTTP, &tContext,
pData, iDataSize );
if ( iLen==-1 )
{ break; };
/* --- try again if buffer was not big enough --- */
if ( iLen>iDataSize ) {
iDataSize = iLen;
continue;
};
break;
};
/* ---
Error getting data block ?
--- */
if ( iLen==-1 )
{
assert( 0 );
HTTPCore_logError( &tPIHTTP,
"WinCGI: Internal error getting data for datafile '%s'.",
((const char *)tContext.sDataFile) );
tPIHTTP.iStatus = ST_INTERNALERROR;
return bIgnoreStatus;
};
/* --- try to write this data block to the datafile --- */
PIPLATFORM_FD tFd = PIFile_open( tContext.sDataFile, "w" );
if ( tFd!=PIPLATFORM_FD_INVALID )
{
/* --- mark datafile as a temporary file --- */
PIDB_add( pR, PIDBTYPE_STRING, KEY_INT_TEMPORARYFILE,
(void *)(const char *)tContext.sDataFile, 0 );
};
int iFailed = ( tFd == PIPLATFORM_FD_INVALID ||
PIFile_write( tFd, iLen, pData )!=0 );
if ( tFd!=PIPLATFORM_FD_INVALID )
{ PIFile_close( tFd ); };
if ( iFailed )
{
HTTPCore_logError( &tPIHTTP,
"WinCGI: Failed to write datafile, path is '%s'.",
((const char *)tContext.sDataFile) );
tPIHTTP.iStatus = ST_INTERNALERROR;
return bIgnoreStatus;
};
};
/* ---
Generate command line pattern
--- */
enum { CMD_BUF_SIZE=255 };/* --- this will fit most command lines --- */
char szCmdBuf[CMD_BUF_SIZE+1];
char *pCommandLine = szCmdBuf;
int iLen = Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext,
pCommandLine, CMD_BUF_SIZE );
szCmdBuf[CMD_BUF_SIZE] = '\0';
if ( iLen>CMD_BUF_SIZE )
{
/* --- automatic buffer not big enough, allocate a new one --- */
pCommandLine = (char *)PIHTTP_allocMem( &tPIHTTP, iLen+1 );
Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext,
pCommandLine, iLen );
Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext,
pCommandLine, iLen );
};
pCommandLine[iLen] = '\0';
#if VERBOSE_DEBUG
cerr << "Executing commandline: '" << pCommandLine << "'" << endl;
#endif
int iRCode = DoExecCGIChild(
pCommandLine,
pDirectory,
&tProcess,
iDoStdin,
&tStdout_Parent,
&tStdout_CGI,
&tStdin_Parent,
&tStdin_CGI,
&tStderr_Parent,
&tStderr_CGI,
tPIHTTP
#if VERBOSE_DEBUG
, cerr
#endif
);
/* ---
Error in CGI program
--- */
if ( iRCode )
{
HTTPCore_logError( &tPIHTTP,
"WinCGI: DoExecCGIChild() failed. Error code is %d. \
Start of command line is '%s'.", iRCode, szCmdBuf );
tPIHTTP.iStatus = ST_INTERNALERROR;
CLOSE_ALL_HANDLES;
return bIgnoreStatus;
};
/*
** pError serves as error flag
*/
int iRet = 0;
const char *pError = 0;
const char *pArgs[3];
PIObject *pChildIO = 0;
PIIOBuffer *pCGIBuffer = 0;
CloseIfValidDesc( tStdin_CGI );
CloseIfValidDesc( tStdin_Parent );
/* ---
Wait for process to die.
---- */
if ( !WaitForChild( szCmdBuf, tPIHTTP, tProcess ) )
{ iRet = -1; /* error message already given */ };
CloseProcessDesc( tProcess );
tProcess = INVALID_DESC;
/* ---
Close CGI side of pipe
--- */
CloseFileDesc( tStdout_CGI );
/* ---
Read and discard stderr, write this CGI error to server error file
--- */
enum { BUF_SIZE=2047 };
char szBuf[BUF_SIZE+1];
/* ---
CGI output is from a file, open the file
--- */
assert( tStdout_Parent == INVALID_DESC );
tStdout_Parent = (FILEDESC)PIFile_open( tContext.sOutputFile, "r" );
/* ---
Make a clone of the prototype pipe IO object for communication
with this CGI process
--- */
pArgs[0] = (const char *)tStdout_Parent;
pArgs[1] = (const char *)tStdin_Parent;
pArgs[2] = (const char *)0; /* handle is a pipe? - no */
pChildIO = PIObject_copy( pPipeIO, 3, pArgs );
if ( !pChildIO )
{
pError = "WinCGI: Failed to open communication channel to CGI \
program.";
}
else
{
/* ---
Make CGI buffer object
--- */
pCGIBuffer = PIIOBuffer_new( pChildIO );
assert( pCGIBuffer );
};
/* ---
Read CGI request headers
--- */
if ( !pError && !iRet )
{
if ( HTTPCore_readHeaders( pCGIBuffer, pR, RH_RESPONSE ) )
{ pError = "Error reading response headers from CGI program"; };
};
if ( pError )
{
if ( *pError )
{
HTTPCore_logError( &tPIHTTP, "WinCGI: %s.\nStart of command line \
is '%s'.", pError, szCmdBuf );
}
else
{
HTTPCore_logError( &tPIHTTP, "WinCGI: Start of command line \
is '%s'.", szCmdBuf );
};
iRet = -1;
};
#if VERBOSE_DEBUG
cerr << dec << iRet << endl;
#endif
/* ---
Check the type of the response
- Partial (usual case)
- Full
- or redirect
--- */
const char *pCLF = 0;
const char *pLocation = 0;
if ( !iRet && ( pCLF = (const char *)
PIDB_lookup( pR, PIDBTYPE_STRING, KEY_HTTP_CLF, 0 ) ) )
{
/* ++++ __________________________ +++ *
Full Response (Non-Parsed Headers)
* ++++ __________________________ +++ */
/* --- grap the status code sent by the CGI --- */
int i=0;
for(; pCLF[i] && !(isspace(pCLF[i])); i++); /* advance to space */
for(; pCLF[i] && (isspace(pCLF[i])); i++); /* advance past space */
tPIHTTP.iStatus = atoi( &(pCLF[i]) );
/* ---
disable keep open, hope the CGI sent the appropriate
'Connection' headers for this HTTP version
--- */
PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE,
KEY_INT_KEEPOPEN, (void *)0, 0 );
/* --- send status header from CGI --- */
PIIOBuffer_writeLn( &tB, pCLF, -1, PIIOBUF_NONE );
/* --- loop over RFC822 headers to send them --- */
PIDBIterator *pIter = PIDB_getIterator( pR, PIDBTYPE_RFC822, 0, 0 );
for( ;
PIDBIterator_atValidElement( pIter );
PIDBIterator_next( pIter ) )
{
const char *pHeader;
const char *pContent = (const char *)
PIDBIterator_current( pIter, &pHeader );
PIIOBuffer_write( &tB, pHeader, -1, PIIOBUF_NONE );
PIIOBuffer_write( &tB, ": ", 2, PIIOBUF_NONE );
PIIOBuffer_writeLn( &tB, pContent, -1, PIIOBUF_NONE );
};
PIDBIterator_delete( pIter );
/* --- empty CRLF --- */
PIIOBuffer_writeLn( &tB, "", 0, PIIOBUF_NONE );
/* ---
for a full reponse no REDIRECT action should be
taken based on the status code, as the CGI program is handling
the status itself
--- */
bIgnoreStatus = true;
/* --- continue to allow the content-body to be sent --- */
}
else if ( !iRet && (pLocation=(const char *)
PIDB_lookup( pR, PIDBTYPE_RFC822, KEY_HTTP_LOCATION, 0 ) ) )
{
/* ++++ __________________________ +++ *
Location Response
* ++++ __________________________ +++ */
/* --- determine if this is a URL path or a URI --- */
if ( *pLocation=='/' )
{
/* ---
URL path, expand to full URI and replace in Location
--- */
PIOStrStream ostr;
if ( PIDB_lookup( pC, PIDBTYPE_STRING, KEY_HTTPS_KEYSIZE, 0 ) )
{
/*
** Running under SSL
*/
ostr << "https://";
}
else
{
/*
** Not running under SSL
*/
ostr << "http://";
};
const char *pHostName = HTTPUtil_getHostName( &tPIHTTP );
if ( pHostName )
{ ostr << pHostName; };
const char *pPort = HTTPUtil_getHostPort( &tPIHTTP );
if ( pPort )
{ ostr << ':' << pPort; };
ostr << pLocation;
ostr << ends;
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_LOCATION,
(void *)ostr.str(), 0 );
};
/* --- change status to permanent redirect --- */
tPIHTTP.iStatus = ST_PERMANENTREDIRECT;
/* ---
Has the CGI program sent any content ?
--- */
if ( !PIIOBuffer_pollBeforeRead( pCGIBuffer ) )
{
/* ---
No content
--- */
if ( pCGIBuffer )
{ PIIOBuffer_delete( pCGIBuffer ); };
PIObject_delete( pChildIO, 0, 0 );
CLOSE_ALL_HANDLES;
return bIgnoreStatus;
};
/* ---
for a location reponse with no content no REDIRECT action should be
taken based on the status code, as the CGI program is handling
the content itself
--- */
bIgnoreStatus = true;
/* ---
start to send the response and allow the
output from the CGI to be sent to the client as entity
body for the request.
--- */
PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE,
KEY_INT_KEEPOPEN, (void *)0, 0 );
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{ iRet = -1; };
}
else if ( !iRet )
{
/* ++++ __________________________ +++ *
Partial Response (aka Parsed Headers)
* ++++ __________________________ +++ */
/* ---
Make sure that at least 'Content-Type' exists.
--- */
if ( !PIDB_lookup( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTTYPE, 0 ))
{
HTTPCore_logError( &tPIHTTP, "WinCGI: CGI program \
did not provide 'Content-Type' header. Start of command line is '%s'.", szCmdBuf );
iRet = -1;
/* ---
if 'Status' header exists,
then set the status appropriately
--- */
const char *pStatus = (const char *)PIDB_lookup( pR,
PIDBTYPE_RFC822, KEY_HTTP_STATUS, 0 );
if ( pStatus )
{
tPIHTTP.iStatus = atoi( pStatus );
};
}
else
{
/* --- start the response --- */
tPIHTTP.iStatus = ST_OK;
PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE,
KEY_INT_KEEPOPEN, (void *)0, 0 );
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{ iRet = -1; };
};
};
if ( !iRet )
{ iRet = WriteBufferToBuffer( *pCGIBuffer, tB ); };
if ( pCGIBuffer )
{ PIIOBuffer_delete( pCGIBuffer ); };
#if VERBOSE_DEBUG
cerr << dec << iRet << endl;
#endif
CloseIfValidDesc( tStdout_Parent );
/* ---
Swallow up stderr stream from CGI child
--- */
CloseFileDesc( tStderr_CGI );
for(;;)
{
int iRead;
int iRet = PIPlatform_pollPipeFD(
(PIPLATFORM_FD)tStderr_Parent, PIPLATFORM_POLL_READ, 0 );
if ( iRet != PIPLATFORM_POLL_READ )
{
if (iRet == PIAPI_ERROR)
{
iRet = PIPlatform_getLastError();
if ((iRet != PIAPI_NOTSUPPORTED) && (iRet != PIAPI_EINVAL))
{ break; };
}
else
{ break; };
};
// if ( iRet!=PIPLATFORM_POLL_READ )
// { break; };
#if WIN32
if ( !::ReadFile( tStderr_Parent, szBuf, BUF_SIZE,
(unsigned long *)&iRead, NULL ) || !iRead )
{ break; };
#elif POSIX
iRead = ::read( tStderr_Parent, szBuf, BUF_SIZE );
if ( iRead==-1 && errno==EINTR )
{ continue; };
if ( iRead==-1 || !iRead )
{ break; };
#endif
szBuf[iRead] = '\0';
/*
** Write stderr output into the error logfile
*/
HTTPCore_logError( &tPIHTTP, "WinCGI: Stderr output from \
CGI program follows \n\
______________________________________________________________________________\
__\n%s\n\
______________________________________________________________________________\
__\nCGI program command line is '%s'.", szBuf, szCmdBuf );
/* --- mark an error --- */
iRet = -1;
};
CloseIfValidDesc( tStderr_Parent );
PIObject_delete( pChildIO, 0, 0 );
if ( iRet )
{
tPIHTTP.iStatus =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -