📄 wincgi.cpp
字号:
pBuf[i++] = '\n';
}
else
{
PIDBIterator_delete( pIter );
pBuf[i++] = '\0';
return 1;
};
};
pBuf[i++] = '\0';
PIDBIterator_delete( pIter );
return 0;
};
/* ---
Add client accept header to the buffer. Returns 0 on
success, 1 buffer exhausted and -1 on error.
--- */
int AddClientAcceptHeader( PIHTTP *pPIHTTP, PIDB *pQ, char *pBuf, int iBufSize )
{
int i = 0;
const char *pKey;
const char *pValue = (const char *)PIDB_lookup( pQ,
PIDBTYPE_RFC822, KEY_HTTP_ACCEPT, 0);
if (!pValue) return 0;
/* --- loop over all mime types in Accept header --- */
StringTokenizer tTokens( pValue, "," );
for( int j=0; j<tTokens.NumTokens(); j++)
{
pKey = tTokens.GetToken( j );
pValue = VALUE_YES;
assert( pKey && pValue );
if ( !pKey || !pValue )
{ /* sanity */ continue; };
/* ---
test for additional parameters
--- */
if ( char *pPos = strchr( pKey, ';' ))
{
memset (pPos, '\0', 1);
pValue = ++pPos;
if ( pPos = strchr( pValue, '=' ))
{
pValue = ++pPos;
}
}
int iVarSize = strlen( pKey );
int iValSize = strlen( pValue );
/* ---
Size available must be able to fit
- Variable name (iVarPos)
- Value (iValPos)
- 2..3 other characters, '=', ('\r'), '\n' for entry.
- one byte less for iBufSizedue to trailing '\0'
--- */
#if WIN32
# define ADDPSPACE 3
#else
# define ADDPSPACE 2
#endif
if ( (i+iVarSize+iValSize+ADDPSPACE) < iBufSize - 1 )
#undef ADDPSPACE
{
memcpy( &(pBuf[i]), pKey, iVarSize ); i+=iVarSize;
pBuf[i++] = '=';
memcpy( &(pBuf[i]), pValue, iValSize ); i+=iValSize;
#if WIN32
pBuf[i++] = '\r';
#endif
pBuf[i++] = '\n';
}
else
{
return 1;
};
};
pBuf[i++] = '\0';
return 0;
};
/* ---
Write client form data to an external temporary file. Returns 0 on
success, -1 on error. The key for the [Form External] section is in pResult.
--- */
int WriteExternal( PIHTTP *pPIHTTP, Pi3String *pDecoded, PIString &tResult )
{
PIDB *pH = pPIHTTP->pHostDB;
PIDB *pR = pPIHTTP->pResponseDB;
/* --- separate the value to be written into external file --- */
const char *pValue = strchr(Pi3String_getPtr(pDecoded), '=');
pValue++;
/* --- generate the unique path for the temporary file --- */
enum { BUFSIZE=68 };
char szBuf[BUFSIZE+1];
PIPlatform_getUniqueId(szBuf, BUFSIZE-4);
PIString sTmp(sExternalPath);
sTmp.Concatenate(szBuf);
sTmp.Concatenate(".tmp");
Pi3String *pPath = Pi3String_new( sTmp );
HTTPCore_relativeToAbsolutePath( pH, (const char *)sTmp, pPath );
/* --- Caclulate the result string 'key=pathname length' --- */
StringTokenizer tTokens( Pi3String_getPtr(pDecoded), "=" );
tResult = (const char *)tTokens.GetToken( 0 );
tResult.Concatenate('=');
tResult.Concatenate(Pi3String_getPtr(pPath));
tResult.Concatenate(' ');
sprintf( szBuf, "%lu", strlen(pValue) );
tResult.Concatenate( szBuf );
/* --- try to write this data block to the datafile --- */
PIPLATFORM_FD tFd = PIFile_open( Pi3String_getPtr(pPath), "w" );
if ( tFd!=PIPLATFORM_FD_INVALID )
{
/* --- mark datafile as a temporary file --- */
PIDB_add( pR, PIDBTYPE_STRING, KEY_INT_TEMPORARYFILE,
(void *)Pi3String_getPtr(pPath), 0 );
};
int iFailed = ( tFd == PIPLATFORM_FD_INVALID ||
PIFile_write( tFd, strlen(pValue), pValue )!=0 );
if ( tFd!=PIPLATFORM_FD_INVALID )
{ PIFile_close( tFd ); };
if ( iFailed )
{
HTTPCore_logError( pPIHTTP,
"WinCGI: Failed to write temporary file \
for external form data, path is '%s'.", Pi3String_getPtr(pPath) );
Pi3String_delete(pPath);
return -1;
};
Pi3String_delete(pPath);
return 0;
};
/* ---
Add client form data to the buffer. Returns 0 on
success and -1 on error.
--- */
int AddClientFormData( PIHTTP *pPIHTTP, PIDB *pQ, char *pBuf,
int iBufSize, PIString &tDecoded, PIString &tExternal )
{
Pi3String *pDecoded = Pi3String_new("");
PIString pEncoded(pBuf, iBufSize);
const char *pValue;
/* --- loop over all form fields --- */
StringTokenizer tTokens( pEncoded, "&" );
for( int j=0; j<tTokens.NumTokens(); j++)
{
pEncoded = tTokens.GetToken( j );
HTTPUtil_urlDecode( (Pi3String *)&pEncoded, pDecoded );
pValue = strchr(Pi3String_getPtr(pDecoded), '=');
if ( pValue )
{
if ( strlen(++pValue)>254
|| strcspn(pValue,"=\"\n") < strlen(pValue) )
{
if (WriteExternal(pPIHTTP, pDecoded, pEncoded))
{
Pi3String_delete( pDecoded );
return -1;
};
tExternal.Concatenate(pEncoded);
tExternal.Concatenate("\r\n");
continue;
}
};
tDecoded.Concatenate(Pi3String_getPtr(pDecoded));
tDecoded.Concatenate("\r\n");
}
Pi3String_delete( pDecoded );
return 0;
};
/* ---
Generate pipes and exeute CGI program.
return 0 on success, otherwise error code
--- */
int DoExecCGIChild(
char *pPath, /* exec command line */
const char *pDirectory, /* CGI program current directory */
PROCDESC *pProcess, /* child process id value argument */
int iDoStdin, /* do standard input standard handle */
FILEDESC *pStdout_Parent,
FILEDESC *pStdout_CGI,
FILEDESC *pStdin_Parent,
FILEDESC *pStdin_CGI,
FILEDESC *pStderr_Parent,
FILEDESC *pStderr_CGI,
PIHTTP &tPIHTTP
#if VERBOSE_DEBUG
, ostream &os
#endif
)
{
int iSanity = pPath && pProcess && pStdin_Parent && pStdout_Parent &&
pStdout_CGI && pStdin_CGI;
assert( iSanity );
if ( !iSanity )
{ return -1; };
/* --- CGI stdout handles --- */
FILEDESC tStdout_CGI = INVALID_DESC;
FILEDESC tStdout_Parent = INVALID_DESC;
FILEDESC tStdout_ParentDup = INVALID_DESC;
/* --- CGI stdin handles --- */
FILEDESC tStdin_CGI = INVALID_DESC;
FILEDESC tStdin_Parent = INVALID_DESC;
FILEDESC tStdin_ParentDup = INVALID_DESC;
/* --- CGI stderr handles --- */
FILEDESC tStderr_CGI = INVALID_DESC;
FILEDESC tStderr_Parent = INVALID_DESC;
FILEDESC tStderr_ParentDup = INVALID_DESC;
#if WIN32
BOOL bProcessCreated = FALSE;
DWORD dwFlags = 0;
char *AppName = 0;
STARTUPINFO tStartUp;
memset(&tStartUp, 0, sizeof(tStartUp));
tStartUp.cb=sizeof(tStartUp);
tStartUp.dwFlags = STARTF_USESHOWWINDOW;
if ( HTTPCore_debugEnabled() )
{ tStartUp.wShowWindow=SW_SHOW; }
else
{ tStartUp.wShowWindow=SW_HIDE; };
/*
** Execution flags
*/
if ( iFlags & FLG_16BIT )
{ dwFlags |= CREATE_SEPARATE_WOW_VDM; };
PROCESS_INFORMATION tProcessInfo;
/*
** complete command line for associations
*/
AppName = (char *)PIUtil_malloc(_MAX_PATH);
// Set AppName if the script name in pPath is associated
if ((int)FindExecutable(pPath, NULL, AppName) < 33)
{
PIUtil_free(AppName);
AppName = NULL;
};
/* --- spawn the CGI program --- */
bProcessCreated = CreateProcess(
AppName, /* address of module name */
(char *)pPath, /* address of command line */
NULL, /* address of process security attributes */
NULL, /* address of thread security attributes */
FALSE, /* new process inherits handles */
dwFlags, /* creation flags */
NULL, /* address of new environment block */
pDirectory, /* address of current directory name */
&tStartUp, /* address of STARTUPINFO */
&tProcessInfo /* address of PROCESS_INFORMATION */
);
PIUtil_free(AppName);
if ( !bProcessCreated )
{ goto nt_error_return; };
/* --- log debug information about the process --- */
HTTPCore_logDebug( DBG_MED, "Process created!, \n\thProcess %p\
\n\thThread %p\n\tdwProcessId %lu\t\n\tdwThreadId %lu",
tProcessInfo.dwThreadId,
tProcessInfo.dwProcessId,
tProcessInfo.hThread,
tProcessInfo.hProcess );
# if VERBOSE_DEBUG
os << "Process created!" << endl;
os << " hProcess " << hex << tProcessInfo.hProcess << endl;
os << " hThread " << hex << tProcessInfo.hThread << endl;
os << " dwProcessId " << hex << tProcessInfo.dwProcessId << endl;
os << " dwThreadId " << hex << tProcessInfo.dwThreadId << endl;
# endif
/* --- Handle to main thread in new process --- */
::CloseHandle( tProcessInfo.hThread );
*pProcess = tProcessInfo.hProcess;
*pStdout_Parent = tStdout_ParentDup;
*pStdout_CGI = tStdout_CGI;
if ( iDoStdin )
{
*pStdin_Parent = tStdin_ParentDup;
*pStdin_CGI = tStdin_CGI;
};
*pStderr_Parent = tStderr_ParentDup;
*pStderr_CGI = tStderr_CGI;
/* --- OK --- */
return 0;
nt_error_return:
/* --- restore handles --- */
int iTmp = GetLastError();
goto generic_error_return;
#elif POSIX
const char **ppCommandArgs=0;
register int iPid = 0;
/* ---
Create command line
--- */
{
/* --- scan once and NULL seperate path components --- */
int i;
int j = strlen( pPath );
int k=0;
for( i=0; i<j; i++ )
{
if ( (isspace(pPath[i])) )
{
pPath[i]='\0';
k++;
};
};
/* ---
k contains number of spaces in command line.
cmd1[sp]cmd2[sp]cmd3[sp]cmd4[0],
increment k to include command terminated by final null.
increment k again to allow NULL command at end of array.
--- */
k += 2;
/* --- allocate and assign argument array --- */
ppCommandArgs = (const char **)PIHTTP_allocMem( &tPIHTTP,
sizeof( const char * ) * k );
int x = 0;
const char *pLastArg = 0;
for( i=0; i<=j; i++ )
{
if ( pLastArg==0 )
{ pLastArg=&(pPath[i]); };
if ( pPath[i]=='\0' )
{
ppCommandArgs[x++] = pLastArg;
pLastArg = 0;
};
};
ppCommandArgs[x++] = 0;
assert( x==k );
};
/* ---
Try not to write any data to the processes data space to avoid
copy-on-write penalty for CGI child process.
iPid is declared register so its assignment on fork in the child
process will not write to the child process data space.
--- */
#if 0
/*
** NOTE
*/
#define P ( PIThread_getSystemHandle( PIThread_getCurrent() ) )
cerr << P << " 1.." << tStdin_Parent << endl;
cerr << P << " 2.." << tStdin_CGI << endl;
cerr << P << " 3.." << tStdout_Parent << endl;
cerr << P << " 4.." << tStdout_CGI << endl;
cerr << P << " 5.." << tStderr_Parent << endl;
cerr << P << " 6.." << tStderr_CGI << endl;
#endif
iPid = ::fork();
switch( iPid )
{
case -1:
break;
case 0:
/* --- change current directory --- */
if ( pDirectory )
{ ::chdir( pDirectory ); };
extern char **environ;
if ( ::execve( pPath, (char *const *)ppCommandArgs,
environ )==-1 )
{
perror( "CGI child, execve() failed" );
fprintf( stderr, "Path is '%s'\n", pPath );
fflush( stderr );
goto cgi_error;
};
cgi_error:
::_exit( 1 );
/* none of the following should happen */
::_exit( -1 );
assert( 0 );
break;
default:
/* --- this is the parent --- */
*pProcess = iPid;
*pStdout_CGI = tStdout_CGI;
*pStdout_Parent = tStdout_Parent;
*pStderr_CGI = tStderr_CGI;
*pStderr_Parent = tStderr_Parent;
if ( iDoStdin )
{
*pStdin_CGI = tStdin_CGI;
*pStdin_Parent = tStdin_Parent;
};
/* --- log debug information about the process --- */
HTTPCore_logDebug( DBG_MED, "Process created!, \n\tPid %d\
\n\tStdout_Parent %d\n\tStdout_CGI %d\n\tStderr_Parent %d\n\tStderr_CGI %d",
iPid, tStdout_Parent, tStdout_CGI, tStderr_Parent,
tStderr_CGI );
/* --- OK --- */
return 0;
};
/* --- error --- */
posix_error_return:
int iTmp = errno;
goto generic_error_return;
#endif
generic_error_return:
/* --- stdout handles --- */
CloseIfValidDesc( tStdout_CGI );
CloseIfValidDesc( tStdout_Parent );
CloseIfValidDesc( tStdout_ParentDup );
/* --- stdin handles --- */
CloseIfValidDesc( tStdin_CGI );
CloseIfValidDesc( tStdin_Parent );
CloseIfValidDesc( tStdin_ParentDup );
/* --- stdin handles --- */
CloseIfValidDesc( tStderr_CGI );
CloseIfValidDesc( tStderr_Parent );
CloseIfValidDesc( tStderr_ParentDup );
HTTPCore_logError( &tPIHTTP, "WinCGI: error executing CGI program \
system specific error code is '%d'.", iTmp );
/* --- return error --- */
return iTmp ? iTmp : -1;
};
/* ---
Wait for a child process to terminate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -