📄 sendfile.cpp
字号:
int i = 0;
/*
** loop over all RFC822 headers in request block to calculate Content Length
*/
PIDBIterator *pIter = PIDB_getIterator( pQ, PIDBTYPE_RFC822, 0, 0 );
if ( !pIter )
{
return PIAPI_ERROR;
};
for(; PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
{
const char *pKey;
const char *pValue = (const char *)PIDBIterator_current( pIter, &pKey );
assert( pKey && pValue );
ulLen += strlen(pKey) + strlen(pValue) + 4;
};
PIDBIterator_delete( pIter );
/* --- content-length --- */
char szBuf[2];
sprintf( szBuf, "%lu", ulLen );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, szBuf, 0 );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTTYPE, (void *)TYPE_MSG_HTTP, 0 );
/* --- start response --- */
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{
return PIAPI_ERROR;
};
if ( PIIOBuffer_write( tPIHTTP.pBuffer, pReq, strlen(pReq), PIIOBUF_NONE) == 0 )
{
return PIAPI_ERROR;
};
if ( PIIOBuffer_write( tPIHTTP.pBuffer, "\r\n", 2, PIIOBUF_NONE) == 0 )
{
return PIAPI_ERROR;
};
pIter = PIDB_getIterator( pQ, PIDBTYPE_RFC822, 0, 0 );
for(; PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
{
const char *pKey;
const char *pValue = (const char *)PIDBIterator_current( pIter, &pKey );
assert( pKey && pValue );
if ( PIIOBuffer_write( tPIHTTP.pBuffer, pKey, strlen(pKey), PIIOBUF_NONE) == 0 )
{
PIDBIterator_delete( pIter );
return PIAPI_ERROR;
};
if ( PIIOBuffer_write( tPIHTTP.pBuffer, ": ", 2, PIIOBUF_NONE) == 0 )
{
PIDBIterator_delete( pIter );
return PIAPI_ERROR;
};
if ( PIIOBuffer_write( tPIHTTP.pBuffer, pValue, strlen(pValue), PIIOBUF_NONE) == 0 )
{
PIDBIterator_delete( pIter );
return PIAPI_ERROR;
};
if ( PIIOBuffer_write( tPIHTTP.pBuffer, "\r\n", 2, PIIOBUF_NONE) == 0 )
{
PIDBIterator_delete( pIter );
return PIAPI_ERROR;
};
};
PIDBIterator_delete( pIter );
return PIAPI_COMPLETED;
};
public:
SendFile( PIObject *pObject, int iArgc, const char *ppArgv[] )
: HandlerBaseHTTP( pObject ),
pHeaderPattern( 0 ),
pFooterPattern( 0 ),
iMethods( FLG_GET | FLG_HEAD ),
sFileKey( "upfile" ),
sNoteKey( "notes" ),
pAnnotation( 0 ),
sDescFile( 0 ),
sPathInfo( 0 ),
sUploadPath( 0 ),
sUploadFile( 0 ),
iUploadLimit( 0 ),
iChunkLimit( 0 ),
iAllowRanges( 0 ),
tFD( PIPLATFORM_FD_INVALID ),
pFKMethod( PIDB_getFastKey( KEY_HTTP_METHOD, PIDBTYPE_OPAQUE )),
pFKRange( PIDB_getFastKey( KEY_HTTP_RANGE, PIDBTYPE_RFC822 )),
pFKIfRange( PIDB_getFastKey( KEY_HTTP_IFRANGE, PIDBTYPE_RFC822 )),
pFKPath( PIDB_getFastKey( KEY_INT_PATH, PIDBTYPE_STRING )),
pFKProtocol( PIDB_getFastKey( KEY_HTTP_PROTOCOL, PIDBTYPE_OPAQUE ))
{
ReadParameters( iArgc, ppArgv );
};
~SendFile()
{
Pi3Expression_delete( pHeaderPattern );
Pi3Expression_delete( pFooterPattern );
};
int Handle( int iPhase, PIHTTP &tPIHTTP, PIIOBuffer &tB )
{
if ( iPhase!=PH_HANDLE ) { return PIAPI_ERROR; };
/* ---
Lookup method
--- */
int iMethod = (int)PIDB_lookup( tPIHTTP.pRequestDB, PIDBTYPE_OPAQUE,
pFKMethod, PIDBFLAG_FASTKEY );
/* ---
Check for supported methods
--- */
if ( iMethods )
{
int iMethFlag = 1;
iMethFlag <<= iMethod;
/* ---
The method is not handled by this object
--- */
if ( !(iMethFlag & iMethods) )
{
/* ---
The object has been created with default methods
--- */
if ( (iMethods==(FLG_GET | FLG_HEAD)) &&
(!( iMethFlag==FLG_GET || iMethFlag==FLG_HEAD )))
{ return PIAPI_CONTINUE; };
/* ---
The object has been created with method mask
--- */
return HTTPUtil_doHTTPError( &tPIHTTP, ST_NOTIMPLEMENTED );
};
}
// check, that range headers are provided only in GET and HEAD requests
// AND ignore range header in sub-requests (internal redirects)
const char *szRangeHeader = 0;
if (!PIHTTP_isChild( &tPIHTTP))
{
szRangeHeader = (const char *)PIDB_lookup( tPIHTTP.pRequestDB, PIDBTYPE_RFC822,
pFKRange, PIDBFLAG_FASTKEY );
};
if ( szRangeHeader && !(iMethod==MD_GET || iMethod==MD_HEAD))
{
HTTPCore_logError( &tPIHTTP, "SendFile: Range headers can only be processed in GET and HEAD requests.");
return HTTPUtil_doHTTPError( &tPIHTTP, ST_NOTIMPLEMENTED );
};
switch( iMethod )
{
case MD_GET:
case MD_HEAD:
return Get_Head( tPIHTTP, iMethod, szRangeHeader );
case MD_PUT:
return Put( tPIHTTP, tB );
case MD_POST:
return Post( tPIHTTP, tB );
case MD_DELETE:
return Delete( tPIHTTP );
case MD_OPTIONS:
return Options( tPIHTTP, tB );
case MD_TRACE:
return Trace( tPIHTTP, tB );
default:
assert( 0 );
/* ---
Something is real going wrong
--- */
return PIAPI_ERROR;
};
return PIAPI_ERROR;
};
};
#define pfkUpfileHandle "UPFILE_HANDLE"
int fnMultipartCb( int iKind, char *szName, char *szData, long lData, PIHTTP *pPIHTTP, void *pUser )
{
// The file part of the message
if ( !PIUtil_stricmp( szName, ((SendFile *)pUser)->sFileKey ))
{
PIString sPath;
if ( iKind & MP_PART_FIRST )
{
// Extract filename
char *pFileName = strstr( szData, "filename=" );
if ( !pFileName ) return PIAPI_ERROR;
pFileName += strlen("filename=") + 1;
char *pStrEnd = strchr( pFileName, '"' );
if ( pStrEnd )
{
*pStrEnd = 0;
}
else
{
return PIAPI_ERROR;
};
// memset( strchr( pFileName, '"' ), 0, 1);
PIFInfo *pFInfo = HTTPCore_getCachedFile( pFileName );
if ( !pFInfo ) return PIAPI_ERROR;
strcpy( pFileName, PIFInfo_getName( pFInfo ));
((SendFile *)pUser)->sUploadFile = pFileName;
HTTPCore_releaseCachedFile( pFInfo );
/* ---
Get file path
--- */
sPath = ((SendFile *)pUser)->sUploadPath;
sPath.Concatenate( ((SendFile *)pUser)->sUploadFile );
/* ---
Get the file object
--- */
pFInfo = HTTPCore_getCachedFile( sPath );
if ( !pFInfo ) return PIAPI_ERROR;
/* ---
If this file exist it must be a regular file
--- */
if ( PIFInfo_exists( pFInfo ) && !PIFInfo_isRegular( pFInfo ))
{
HTTPCore_logError( pPIHTTP, "SendFile: File with \
path '%s' is not a regular file.", (const char *)sPath );
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( pPIHTTP, ST_INTERNALERROR );
};
/* ---
If this file exist it must be a writeable file
--- */
if ( PIFInfo_exists( pFInfo ) && !PIFInfo_isWritable( pFInfo ))
{
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( pPIHTTP, ST_FORBIDDEN );
};
HTTPCore_releaseCachedFile( pFInfo );
// jump over Content-Disposition
char *szStart = (char *)memchr( szData, 10, lData );
if ( !szStart ) return PIAPI_ERROR;
// jump over Content-Type
szStart = (char *)memchr( szStart + 1, 10, lData );
if ( !szStart ) return PIAPI_ERROR;
// jump over CR/LF
szStart = (char *)memchr( szStart + 1, 10, lData ) + 1;
if ( !szStart ) return PIAPI_ERROR;
// Open file from origin name
((SendFile *)pUser)->tFD = PIFile_open( sPath, "w" );
if ( ((SendFile *)pUser)->tFD == PIPLATFORM_FD_INVALID ) return PIAPI_ERROR;
if ( PIFile_write( ((SendFile *)pUser)->tFD, lData - (szStart - szData), szStart ))
{
PIFile_close( ((SendFile *)pUser)->tFD );
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
return PIAPI_ERROR;
};
};
if ( iKind & MP_PART_NEXT )
{
// write the data to the file
if ( PIFile_write( ((SendFile *)pUser)->tFD, lData, szData ))
{
PIFile_close( ((SendFile *)pUser)->tFD );
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
return PIAPI_ERROR;
};
};
if ( iKind & MP_PART_LAST )
{
if ( iKind == MP_PART_LAST )
{
// write the data to the file
if ( PIFile_write( ((SendFile *)pUser)->tFD, lData, szData ))
{
PIFile_close( ((SendFile *)pUser)->tFD );
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
return PIAPI_ERROR;
};
};
// close the file
if ( PIFile_close( ((SendFile *)pUser)->tFD )) return PIAPI_ERROR;
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
/* ---
Write the annotation
--- */
if ( !((SendFile *)pUser)->pAnnotation ) return PIAPI_COMPLETED;
enum { BUF_SIZE=1024 };
char szBuf[BUF_SIZE];
strcpy( szBuf, ((SendFile *)pUser)->sUploadPath );
strcat( szBuf, ((SendFile *)pUser)->sUploadFile );
char *pStrEnd = strchr( szBuf, '.' );
if ( pStrEnd )
{
*pStrEnd = '_';
}
else
{
return PIAPI_ERROR;
};
// if ( strchr( szBuf, '.' )) memset( strchr( szBuf, '.' ), '_', 1 );
sPath = szBuf;
sPath.Concatenate( NOTE_EXT );
char *pBuf = szBuf;
int iLen = Pi3Expression_write( ((SendFile *)pUser)->pAnnotation, pPIHTTP, 0, pBuf, BUF_SIZE );
if ( iLen > BUF_SIZE )
{
pBuf = PI_NEW( char[iLen] );
Pi3Expression_write( ((SendFile *)pUser)->pAnnotation, pPIHTTP, 0, pBuf, iLen );
};
// Open file from origin name
((SendFile *)pUser)->tFD = PIFile_open( sPath, "w" );
if ( ((SendFile *)pUser)->tFD == PIPLATFORM_FD_INVALID ) return PIAPI_ERROR;
/* --- write the message --- */
int iRet = PIFile_writeAtomic( ((SendFile *)pUser)->tFD, iLen, pBuf );
if ( pBuf != szBuf )
{
PI_DELETE( [] pBuf );
};
if ( iRet )
{
/* --- an error occurred --- */
HTTPCore_logError( pPIHTTP, "SendFile: \
PIFile_writeAtomic() failed for file '%s', error code '%d'.", (const char *)sPath,
PIPlatform_getLastError() );
PIFile_close( ((SendFile *)pUser)->tFD );
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
return HTTPUtil_doHTTPError( pPIHTTP, ST_INTERNALERROR );
};
// close the file
if ( PIFile_close( ((SendFile *)pUser)->tFD )) return PIAPI_ERROR;
((SendFile *)pUser)->tFD = PIPLATFORM_FD_INVALID;
};
return PIAPI_COMPLETED;
};
// The note part of the message
if ( !PIUtil_stricmp( szName, ((SendFile *)pUser)->sNoteKey ))
{
if ( !((SendFile *)pUser)->sDescFile ) return PIAPI_COMPLETED;
// The file name must exist!
if ( !((SendFile *)pUser)->sUploadFile ) return PIAPI_ERROR;
/* ---
Get path information of upload file
--- */
PIFInfo *pFInfo = HTTPCore_getCachedFile( ((SendFile *)pUser)->sUploadPath );
if ( !pFInfo ) return PIAPI_ERROR;
PIString sPath = ((SendFile *)pUser)->sUploadPath;
sPath.Concatenate( ((SendFile *)pUser)->sDescFile );
HTTPCore_releaseCachedFile( pFInfo );
// jump over Content-Disposition
char *szStart = (char *)memchr( szData, 10, lData );
if ( !szStart ) return PIAPI_ERROR;
// jump over CR/LF
szStart = (char *)memchr( szStart + 1, 10, lData ) + 1;
if ( !szStart ) return PIAPI_ERROR;
PIDB *pDescriptionDB = PIDB_new( 0, "File Descriptions" );
if ( !((SendFile *)pUser)->LoadDescriptionFile( pDescriptionDB, sPath ))
{
PIDB_delete( pDescriptionDB );
return PIAPI_ERROR;
};
DescriptionMap *pDesc = (DescriptionMap *)PIDB_lookup( pDescriptionDB,
PIDBTYPE_OPAQUE, ((SendFile *)pUser)->sUploadFile, 0 );
if ( !pDesc )
{
pDesc = PI_NEW( DescriptionMap( ((SendFile *)pUser)->sUploadFile,
szStart, lData - (szStart - szData)));
PIDB_add( pDescriptionDB, PIDBTYPE_OPAQUE, pDesc->sFileName,
(void *)pDesc, 0 );
}
else
{
PIString sTmp( szStart, lData - (szStart - szData));
pDesc->sDescription = sTmp;
};
if ( !((SendFile *)pUser)->SaveDescriptionFile( pDescriptionDB, sPath ))
{
PIDB_delete( pDescriptionDB );
return PIAPI_ERROR;
};
PIDB_delete( pDescriptionDB );
return PIAPI_COMPLETED;
};
return PIAPI_ERROR;
};
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int SendFile_constructor( PIObject *pObj,
int iArgc, const char *ppArgv[] )
{
return HandlerBaseHTTP_constructor( pObj, PI_NEW( SendFile( pObj,
iArgc, ppArgv ) ) );
}
#if 0
/*___+++CNF_BEGIN+++___*/
<Class>
Name SendFileClass
Type LogicExtension
Library HTTP
OnClassLoad HandlerBaseHTTP_onClassLoad
Constructor SendFile_constructor
CopyConstructor HandlerBaseHTTP_copyConstructor
Destructor HandlerBaseHTTP_destructor
Execute HandlerBaseHTTP_execute
</Class>
<Object>
Name SendFile
Class SendFileClass
</Object>
/*___+++CNF_END+++___*/
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -