📄 sendfile.cpp
字号:
char *pFooter = 0;
int iFooterLen = 0;
if ( pFooterPattern )
{
pFooter = ( iMethod==MD_GET ) ? szFooter : 0;
iFooterLen = Pi3Expression_write( pFooterPattern, &tPIHTTP, 0, pFooter, PATTERN_BUF_SIZE );
if ( iFooterLen>PATTERN_BUF_SIZE && pFooter )
{
pFooter = PI_NEW( char[iFooterLen] );
Pi3Expression_write( pFooterPattern, &tPIHTTP, 0, pFooter, iFooterLen );
};
};
/* --- transfer-encoding --- */
int iFlags = iChunkLimit && iFileSize > iChunkLimit && (!PIHTTP_isChild( &tPIHTTP)
&& (int)PIDB_lookup( pQ, PIDBTYPE_OPAQUE, pFKProtocol, PIDBFLAG_FASTKEY ) == 3 )
? PIIOBUF_CHUNKED : PIIOBUF_NONE;
if ( iFlags & PIIOBUF_CHUNKED )
{
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_TRANSFERENCODING, (void *)KEY_HTTP_CHUNKED, 0 );
}
/* --- content-length --- */
// else
{
enum { BUF_SIZE=63 };
char szBuf[BUF_SIZE+1];
unsigned long ulLen = iRange ? iRange : iFileSize;
ulLen += iHeaderLen;
ulLen += iFooterLen;
sprintf( szBuf, "%lu", ulLen );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, szBuf, 0 );
};
/* --- last modified --- */
Pi3String *pTmp = Pi3String_new( 0 );
time_t tT = PIFInfo_getLastModified( pFInfo );
PIPlatform_beforeUnsafeBlock();
struct tm *pTms = gmtime( &tT );
HTTPUtil_rFC822Time( pTms, pTmp );
PIPlatform_afterUnsafeBlock();
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_LASTMODIFIED, (void *)Pi3String_getPtr( pTmp ), 0 );
Pi3String_delete( pTmp );
/* --- If current status is 0 then change to 200 OK --- */
if ( !tPIHTTP.iStatus ) tPIHTTP.iStatus = iRange ? ST_PARTIALCONTENT: ST_OK;
/* --- start response --- */
int iRet =
HTTPCore_sendGeneralHeaders( &tPIHTTP ) == PIAPI_COMPLETED
&& HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) == PIAPI_COMPLETED;
if ( iRet && (iFlags & PIIOBUF_CHUNKED) ) iRet = PIIOBuffer_flush( tPIHTTP.pBuffer );
if ( iRet && (iMethod == MD_GET) )
{
if ( pHeader && iHeaderLen )
{
iRet = ( PIIOBuffer_write( tPIHTTP.pBuffer, pHeader, iHeaderLen, iFlags)>0 );
};
if ( iRet )
{
if ( iAllowRanges && iRange )
{
iRet = !HTTPUtil_sendFileRange( tPIHTTP.pBuffer, pFInfo, iFlags, uiFrom, uiTo );
}
else
{
iRet = !HTTPUtil_sendFile( tPIHTTP.pBuffer, pFInfo, iFlags, 0 );
}
};
if ( iRet && pFooter && iFooterLen )
{
iRet = ( PIIOBuffer_write( tPIHTTP.pBuffer, pFooter, iFooterLen, iFlags)>0 );
};
};
if ( pHeader && pHeader!=szHeader ) { PI_DELETE( [] pHeader ); };
if ( pFooter && pFooter!=szFooter ) { PI_DELETE( [] pFooter ); };
HTTPCore_releaseCachedFile( pFInfo );
/* ---
If iRet is zero, an error occurred sending the file.
** NOTE: Maybe do something with it.
--- */
return iRet ? PIAPI_COMPLETED : PIAPI_ERROR;
};
/* ---
Implementation of HTTP/1.1 method DELETE (unlink file)
--- */
int Delete( PIHTTP &tPIHTTP )
{
PIDB *pQ = tPIHTTP.pRequestDB;
PIDB *pR = tPIHTTP.pResponseDB;
/* ---
Get file object
--- */
const char *pPath = (const char *)PIDB_lookup( pR, PIDBTYPE_STRING,
pFKPath, PIDBFLAG_FASTKEY );
PIFInfo *pFInfo = HTTPCore_getCachedFile( pPath );
if ( !pFInfo ) return PIAPI_ERROR;
/* ---
This file must exist and be a regular file
--- */
if ( !PIFInfo_exists( pFInfo ) || !PIFInfo_isRegular( pFInfo ))
{
HTTPCore_logError( &tPIHTTP, "SendFile: File with \
path '%s' does not exist or is not a regular file.", pPath );
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
This file must be a writeable file
--- */
if ( !PIFInfo_isWritable( pFInfo ))
{
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_FORBIDDEN );
};
if ( PIFile_unlink( PIFInfo_getPath( pFInfo )))
{
HTTPCore_logError( &tPIHTTP, "SendFile: Could not unlink file with path '%s'.", pPath );
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* --- If current status is 0 then change to 200 OK --- */
if ( !tPIHTTP.iStatus ) tPIHTTP.iStatus = ST_OK;
/* --- content-length --- */
char szBuf[2];
unsigned long ulLen = 0;
sprintf( szBuf, "%lu", ulLen );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, szBuf, 0 );
/* --- start response --- */
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{
HTTPCore_releaseCachedFile( pFInfo );
return PIAPI_ERROR;
};
HTTPCore_releaseCachedFile( pFInfo );
/* ---
If iRet is zero, an error occurred sending the file.
** NOTE: Maybe do something with it.
--- */
return PIAPI_COMPLETED;
};
/* ---
Implementation of HTTP/1.1 method PUT (File upload)
--- */
int Put( PIHTTP &tPIHTTP, PIIOBuffer &tB )
{
PIDB *pQ = tPIHTTP.pRequestDB;
PIDB *pR = tPIHTTP.pResponseDB;
/* ---
Check Content-Length for Limit
--- */
char *szContentLength = (char *)PIDB_lookup( pQ, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, 0 );
// No Content-Length or a limit is defined and Content-Length is over limit
if ( !szContentLength ) return PIAPI_ERROR;
if ( iUploadLimit && ( iUploadLimit < atol( szContentLength )))
{
int iRead = 0;
int iBufRead = 0;
#if 0
/* --- loop until no more bytes left --- */
do
{
/* --- no more data or client timeout ? --- */
if ( PIIOBuffer_pollBeforeRead( &tB ) < 1 ) break;
/* --- read the data --- */
PIIOBuffer_read( &tB, &iBufRead );
iRead += iBufRead;
}
while ( iRead < atol( szContentLength ));
#endif
HTTPCore_logError( &tPIHTTP, "SendFile: File is too large for upload.");
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
Get file object
--- */
const char *pPath = (const char *)PIDB_lookup( pR, PIDBTYPE_STRING,
KEY_INT_PATH, 0 );
PIFInfo *pFInfo = HTTPCore_getCachedFile( pPath );
if ( !pFInfo ) return PIAPI_ERROR;
/* ---
If this file exist it must be a regular file
--- */
if ( PIFInfo_exists( pFInfo ) && !PIFInfo_isRegular( pFInfo ))
{
HTTPCore_logError( &tPIHTTP, "SendFile: File with \
path '%s' is not a regular file.", pPath );
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, 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( &tPIHTTP, ST_FORBIDDEN );
};
if ( HTTPUtil_recvFile( &tPIHTTP, &tB, pFInfo ))
{
HTTPCore_logError( &tPIHTTP, "SendFile: Could not write file with path '%s'. \
The error code was %d", PIFInfo_getPath( pFInfo ), PIPlatform_getLastError());
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* --- Change status to 201 CREATED or 204 NOCONTENT if already exists --- */
tPIHTTP.iStatus = PIFInfo_exists( pFInfo ) ? ST_NOCONTENT : ST_CREATED;
HTTPCore_releaseCachedFile( pFInfo );
/* --- content-length --- */
char szBuf[2];
unsigned long ulLen = 0;
sprintf( szBuf, "%lu", ulLen );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, szBuf, 0 );
/* Determine and send Location header */
pPath = (const char *)PIDB_lookup( pR, PIDBTYPE_STRING, KEY_INT_PATHINFO, 0 );
if (!pPath)
{
pPath = (const char *)PIDB_lookup( pR, PIDBTYPE_STRING,
KEY_INT_SCRIPTNAME, 0 );
};
if (pPath)
{
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_LOCATION, (void *)pPath, 0 );
};
/* --- start response --- */
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{
return PIAPI_ERROR;
};
return PIAPI_COMPLETED;
};
/* ---
Implementation of HTTP method POST (form upload as multipart message)
--- */
int Post( PIHTTP &tPIHTTP, PIIOBuffer &tB )
{
PIDB *pR = tPIHTTP.pResponseDB;
PIDB *pQ = tPIHTTP.pRequestDB;
/* ---
Check Content-Type for multipart MIME message
--- */
const char *szContentType = (const char *)PIDB_lookup( pQ, PIDBTYPE_RFC822, KEY_HTTP_CONTENTTYPE, 0 );
if ( strcmp( szContentType, "multipart/form-data;" ) < 0 )
{
/* --- The message is not for this handler! --- */
return PIAPI_CONTINUE;
}
/* ---
Check Content-Length for Limit
--- */
const char *szContentLength = (const char *)PIDB_lookup( pQ, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, 0 );
// No Content-Length or a limit is defined and Content-Length is over limit
if ( !szContentLength ) return PIAPI_ERROR;
if ( iUploadLimit && ( iUploadLimit < atol( szContentLength )))
{
int iRead = 0;
int iBufRead = 0;
#if 0
/* --- loop until no more bytes left --- */
do
{
/* --- no more data or client timeout ? --- */
if ( PIIOBuffer_pollBeforeRead( &tB ) < 1 ) break;
/* --- read the data --- */
PIIOBuffer_read( &tB, &iBufRead );
iRead += iBufRead;
}
while ( iRead < atol( szContentLength ));
#endif
HTTPCore_logError( &tPIHTTP, "SendFile: File is too large for upload.");
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
(Re)set the upload path
--- */
if ( sPathInfo.Len() > 0 )
{
sUploadPath = sPathInfo;
}
else
{
sUploadPath = (const char *)PIDB_lookup( tPIHTTP.pResponseDB, PIDBTYPE_STRING,
KEY_INT_PATHINFO, 0 );
};
if ( sUploadPath.Len() == 0 ) sUploadPath = "/";
GetPathTranslated( tPIHTTP, sUploadPath );
if ( HTTPUtil_recvMultipartMsg( &tPIHTTP, &tB, &fnMultipartCb, this ))
{
HTTPCore_logError( &tPIHTTP, "SendFile: Error during file upload. \
The system error code was %d.", PIPlatform_getLastError());
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* --- If current status is 0 then change to 200 OK --- */
if ( !tPIHTTP.iStatus ) tPIHTTP.iStatus = ST_OK;
/* --- content-length --- */
char szBuf[2];
unsigned long ulLen = 0;
sprintf( szBuf, "%lu", ulLen );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, szBuf, 0 );
// response - internal redirect to the upload URL again
int iRet = ResetPath( tPIHTTP );
return (iRet != PIAPI_COMPLETED) ? iRet : HTTPUtil_doHTTPError(
&tPIHTTP, ST_OK );
};
/* ---
Implementation of HTTP/1.1 method OPTIONS
--- */
int Options( PIHTTP &tPIHTTP, PIIOBuffer &tB )
{
PIDB *pR = tPIHTTP.pResponseDB;
PIDB *pQ = tPIHTTP.pRequestDB;
const char *pURI = (const char *)PIDB_lookup( pQ, PIDBTYPE_STRING, KEY_HTTP_URI, 0 );
enum { BUF_SIZE=256 };
char szBuf[BUF_SIZE+1];
char *pPos = szBuf;
if (!PIUtil_stricmp(pURI, "*")) {
for (int i = MD_UNKNOWN+1; i < MD_LAST; i++) {
if (iMethods & 1<<i) {
if (pPos > szBuf) {
strcpy(pPos, ", ");
pPos += 2;
};
strcpy(pPos, aMethodMap[i-1].pName);
pPos += strlen(aMethodMap[i-1].pName);
};
};
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_PUBLIC, szBuf, 0 );
} else {
/* --- make sub request context --- */
PIHTTP *pChildHTTP = PIHTTP_newChild( &tPIHTTP );
pURI = (const char *)PIDB_lookup( pQ, PIDBTYPE_STRING,
KEY_HTTP_URI, 0 );
/* --- set path --- */
PIDB_replace( pChildHTTP->pRequestDB, PIDBTYPE_STRING,
KEY_HTTP_URI, (void *)pURI, 0 );
for (int i = MD_UNKNOWN+1; i < MD_LAST; i++) {
// We don't test method OPTIONS in sub request ...
if ( MD_OPTIONS != i )
{
pChildHTTP->iStatus = 0;
/* --- set method --- */
PIDB_replace( pChildHTTP->pRequestDB, PIDBTYPE_STRING,
KEY_HTTP_METHOD, (void *)aMethodMap[i-1].pName, 0 );
pURI = (const char *)PIDB_lookup( pQ, PIDBTYPE_STRING,
KEY_HTTP_URI, 0 );
PIDB_replace( pChildHTTP->pResponseDB, PIDBTYPE_STRING,
KEY_INT_PATH, (void *)pURI, 0 );
/* --- dispatch the sub request across the mapping phase --- */
int iRet = HTTPCore_dispatch( pChildHTTP, PH_MAPPING, PH_CHECKTYPE );
/* --- copy the method to the response if child status OK --- */
if ( (iRet == PIAPI_COMPLETED) && ( pChildHTTP->iStatus != ST_NOTIMPLEMENTED )
&& ( pChildHTTP->iStatus != ST_METHODNOTALLOWED ))
{
if (pPos > szBuf) {
strcpy(pPos, ", ");
pPos += 2;
};
strcpy(pPos, aMethodMap[i-1].pName);
pPos += strlen(aMethodMap[i-1].pName);
};
}
else
// ... 'cause we know, OPTIONS is allowed for the main request
{
if (pPos > szBuf)
{
strcpy(pPos, ", ");
pPos += 2;
}
strcpy(pPos, MD_NAME_OPTIONS);
pPos += strlen(MD_NAME_OPTIONS);
};
};
PIHTTP_delete( pChildHTTP );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_ALLOW, szBuf, 0 );
};
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, (void *)"0", 0 );
PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTTYPE, 0, 0 );
/* --- start response --- */
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{
return PIAPI_ERROR;
};
return PIAPI_COMPLETED;
};
/* ---
Implementation of HTTP/1.1 method TRACE
--- */
int Trace( PIHTTP &tPIHTTP, PIIOBuffer &tB )
{
PIDB *pR = tPIHTTP.pResponseDB;
PIDB *pQ = tPIHTTP.pRequestDB;
const char *pReq = (const char *)PIDB_lookup( pQ, PIDBTYPE_STRING,
KEY_HTTP_CLF, 0 );
unsigned long ulLen = strlen(pReq) + 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -