📄 dirindex.cpp
字号:
};
/* --- Set the Media type --- */
if ( iFlags & FLG_MIMETYPE )
{
tContext.tMedia.pField = sMIME;
tContext.tMedia.iLength = sMIME.Len();
};
/* --- Get the icon path for this MIME type --- */
if ( iFlags & FLG_ICON )
{
const PIString &sIcon = GetMIMEIcon( sMIME );
tContext.tIcon.pField = sIcon;
tContext.tIcon.iLength = sIcon.Len();
};
/* --- get the files description --- */
if ( pDescriptionDB )
{
DescriptionMap *pDesc = (DescriptionMap *)PIDB_lookup(
pDescriptionDB, PIDBTYPE_OPAQUE, pName, 0 );
if ( pDesc )
{
tContext.tDescription.pField = pDesc->sDescription;
tContext.tDescription.iLength = pDesc->sDescription.Len();
}
else
{
tContext.tDescription.pField = 0;
tContext.tDescription.iLength = 0;
};
};
/* --- generate the output and send it to the remote client --- */
assert( pFilePattern );
if ( !WriteExpression( pFilePattern, tPIHTTP, tContext ) )
{ return 0; };
/* --- null out some fields --- */
tContext.tName.iLength = 0;
tContext.tAltName.iLength = 0;
tContext.tLastModifiedDate.iLength = 0;
tContext.tIsDirectory.iLength = 0;
tContext.tRelativePath.iLength = 0;
tContext.tIcon.iLength = 0;
tContext.tMedia.iLength = 0;
tContext.tSize.iLength = 0;
return 1;
};
/*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ *
Generate the directory trailer
*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ */
int Bottom( PIHTTP &tPIHTTP, PIFInfo *pDir, WriteContext &tContext ) const
{
if ( !WriteExpression( pListBottomPattern, tPIHTTP, tContext ) )
{ return 0; }
/* --- send any footer file --- */
if ( !SendFile( tPIHTTP, sFooterFile, pDir ) )
{
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: Error \
sending footer file '%s'.", (const char *)sFooterFile );
return 0;
};
if ( !WriteExpression( pFooterPattern, tPIHTTP, tContext ) )
{ return 0; }
return 1;
};
/*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ *
Generate the directory and write in to output stream
*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ */
bool GenerateDirectoryListing(
PIHTTP &tPIHTTP,
WriteContext &tContext,
PIFInfo *pDir,
const char *pRelativePath ) const
{
assert( pDir );
assert( PIFInfo_isDirectory( pDir ) );
tContext.tDirectory.pField = pRelativePath;
tContext.tDirectory.iLength = strlen( pRelativePath );
/* ---
Attempt to load a description file
--- */
PIDB *pDescriptionDB = 0;
if ( sDescriptionFile!=PIString::Empty() )
{
pDescriptionDB = PIDB_new( 0, "File Descriptions" );
if ( !LoadDescriptionFile( pDescriptionDB, pDir ) )
{
PIDB_delete( pDescriptionDB );
pDescriptionDB = 0;
};
};
PIFInfo *pFile = PIFInfo_getFirstFileInDirectory( pDir );
int iError = 0; /* error flag */
PIFInfo *Files[MAX_FILESORT_ARRAY];
int fCount = 0;
unsigned long ulSize = 0;
while( pFile && !iError && ( fCount < MAX_FILESORT_ARRAY ))
{
/* ---
Check file is allowed, this is an OR function, if any allow
pattern matches then include this file
--- */
int iAllow = 0;
if ( PIFInfo_isReadable( pFile ) )
{
/* ---
Get filename
--- */
PIString sFileName( PIFInfo_getName( pFile ) );
for( ConstDblListIterator i( lInclude ); !i.BadIndex(); i++ )
{
PIString &sPattern = *( (PIString *)i.Current() );
if ( HTTPUtil_regexMatch(
sPattern, sPattern.Len(),
sFileName, sFileName.Len() )
)
{
iAllow = 1;
break;
};
};
if ( iAllow )
{
/* ---
Check if the file has been excluded, this is an OR function,
exclude if any exlusion matches
--- */
for( ConstDblListIterator e( lExclude ); !e.BadIndex(); e++ )
{
PIString &sPattern = *( (PIString *)e.Current() );
if ( HTTPUtil_regexMatch(
sPattern, sPattern.Len(),
sFileName, sFileName.Len() )
)
{
iAllow = 0;
break;
};
};
};
};
if ( iAllow )
{
if (!PIFInfo_isDirectory( pFile ))
ulSize += PIFInfo_getSize( pFile );
Files[fCount++] = PIFInfo_new( PIFInfo_getPath( pFile ));
};
if ( iError || !PIFInfo_getNextFileInDirectory( pFile ) )
{ PIFInfo_delete( pFile ); pFile = 0; };
}; //while
if ( !iError )
{
Files[fCount] = 0;
qSort(Files, 0, fCount - 1, pDescriptionDB, iSortByColumn, bSortDescending, iOptions & FLG_SORTCASE);
}
enum { BUF_SIZE=63 };
char szBuf[BUF_SIZE+1];
sprintf(szBuf, "%lu", fCount);
PIString sDirCount = szBuf;
/* --- set directory count --- */
tContext.tDirCount.pField = sDirCount;
tContext.tDirCount.iLength = sDirCount.Len();
PIString sDirSize;
if ( iOptions & FLG_SIZE )
{
enum { BUF_SIZE=63 };
char szBuf[BUF_SIZE+1];
*szBuf = '\0';
sprintf( szBuf, "%lu", ulSize );
sDirSize = szBuf;
}
if ( iOptions & FLG_FORMATSIZE )
{
sDirSize = "0";
WriteThousands( sDirSize, ulSize, "," /* thousands delimiter */ );
}
else if ( iOptions & FLG_ABBREVSIZE )
{
enum { BUF_SIZE=63 };
char szBuf[BUF_SIZE+1];
*szBuf = '\0';
char s='K';
if ( ulSize>=0x100000 ) /* 1 Meg. */
{
s = 'M';
ulSize = 0xFFFFF & (ulSize >> 20);
sprintf( szBuf, "%d ", (int)ulSize );
sDirSize = szBuf;
}
else
{
ulSize = 0x3FF & (ulSize >> 10);
sprintf( szBuf, "%d ", (int)ulSize );
sDirSize = szBuf;
}
sDirSize.Concatenate( s );
};
/* --- set directory size --- */
tContext.tDirSize.pField = sDirSize;
tContext.tDirSize.iLength = sDirSize.Len();
/* --- write the header --- */
Top( tPIHTTP, pDir, tContext );
/* --- write the body --- */
for (int j = 0; j < fCount; j++ ) {
// call 'File' only if no error but delete array members in any case
iError = iError || !File( tPIHTTP, tContext, Files[j],
pRelativePath, pDescriptionDB );
PIFInfo_delete( Files[j] );
};
/* --- write the footer --- */
Bottom( tPIHTTP, pDir, tContext );
/* ---
Delete descriptions
--- */
PIDBIterator *pIter = PIDB_getIterator( pDescriptionDB,
PIDBTYPE_OPAQUE, 0, 0 );
if ( pIter )
{
for( ; pIter && PIDBIterator_atValidElement( pIter );
PIDBIterator_next( pIter ) )
{
DescriptionMap *pDesc = (DescriptionMap *)
PIDBIterator_current( pIter, 0 );
assert( pDesc );
PI_DELETE( pDesc );
};
};
if ( pDescriptionDB )
{ PIDB_delete( pDescriptionDB ); };
PIDBIterator_delete( pIter );
return true;
};
public:
/*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ *
Handle the request
*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ */
int Handle( int iPhase, PIHTTP &tPIHTTP, PIIOBuffer & /* tB */ )
{
if ( iPhase!=PH_HANDLE ) { return PIAPI_ERROR; };
PIDB *pC = tPIHTTP.pConnectionDB;
PIDB *pQ = tPIHTTP.pRequestDB;
PIDB *pR = tPIHTTP.pResponseDB;
/* ---
The following is the kernel of the sort property
together with the qSort function.
--- */
// set the default sort order by options value
bSortDescending = ( iOptions & FLG_SORTDESC );
// parse the query string and change the table header row
char *pQueryString = (char *)
PIDB_lookup( pQ, PIDBTYPE_STRING, KEY_HTTP_QUERYSTRING, 0 );
char *pos = NULL;
int bListTopModified = 0;
// set the default sort column by options value
// and find default field in table header row
if ( iOptions & FLG_SORTTYPE )
{
iSortByColumn = SORT_TYPE;
pos = strstr( sListTop, KEY_SORT_TYPE );
}
else if ( iOptions & FLG_SORTNAME )
{
iSortByColumn = SORT_NAME;
pos = strstr( sListTop, KEY_SORT_NAME );
}
else if ( iOptions & FLG_SORTSIZE )
{
iSortByColumn = SORT_SIZE;
pos = strstr( sListTop, KEY_SORT_SIZE );
}
else if ( iOptions & FLG_SORTDATE )
{
iSortByColumn = SORT_DATE;
pos = strstr( sListTop, KEY_SORT_DATE );
}
else if ( iOptions & FLG_SORTDSCR )
{
iSortByColumn = SORT_DESC;
pos = strstr( sListTop, KEY_SORT_DESC );
};
// the last sort order
// int iOldColumn = iSortByColumn;
// expected Tokens in QueryString
const char *pColumn = 0;
const char *pSort = 0;
if ( !pQueryString || !strcmp( pQueryString, "" )) {
if (pos) {
// set the sort order for the default column to the inverse default
if ( bSortDescending )
{ strncpy( pos + SORT_KEY_LEN + 1, "A", 1 ); }
else
{ strncpy( pos + SORT_KEY_LEN + 1, "D", 1 ); };
bListTopModified = 1;
};
} else {
StringTokenizer tTokens( pQueryString, "=" );
if (tTokens.NumTokens() < 2) {
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: Invalid QueryString '%s'.", pQueryString );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
} else {
pColumn = (const char *)tTokens.GetToken( 0 );
pSort = (const char *)tTokens.GetToken( 1 );
};
// switch sort order
if ( pSort ) { bSortDescending = !strcmp( pSort, "D" ); };
// find the current sort column (query string must be part of header row)
pos = pColumn ? strstr( sListTop, pColumn ) : 0;
if ( pos ) {
// set the sort column by query string field
if ( !strcmp( pColumn, KEY_SORT_TYPE )) { iSortByColumn = SORT_TYPE; };
if ( !strcmp( pColumn, KEY_SORT_NAME )) { iSortByColumn = SORT_NAME; };
if ( !strcmp( pColumn, KEY_SORT_SIZE )) { iSortByColumn = SORT_SIZE; };
if ( !strcmp( pColumn, KEY_SORT_DATE )) { iSortByColumn = SORT_DATE; };
if ( !strcmp( pColumn, KEY_SORT_DESC )) { iSortByColumn = SORT_DESC; };
// the header has to be patched
if ( bSortDescending ) {
strncpy( pos + strlen( pColumn ) + 1, "A", 1 );
} else {
strncpy( pos + strlen( pColumn ) + 1, "D", 1 );
};
bListTopModified = 1;
};
};
// write the changed table header into Pi3-Expression
if ( bListTopModified ) {
// delete old expression
if ( pListTopPattern ) { Pi3Expression_delete( pListTopPattern ); };
Pi3String *pError = Pi3String_new( 0 );
// create new expression from changed table header
pListTopPattern = Pi3Expression_new( sListTop, aFunctions, pError );
Pi3String_delete( pError );
// Error!
if ( !pListTopPattern ) {
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: Error when trying to change header row." );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );;
};
};
/* --- request must be GET or HEAD --- */
int iMethod = (int)PIDB_lookup( pQ, PIDBTYPE_OPAQUE, KEY_HTTP_METHOD,
0 );
if ( iMethod!=MD_GET && iMethod!=MD_HEAD )
{ return PIAPI_CONTINUE; };
/* ---
Get URL Path
--- */
const char *pURI = (const char *)
PIDB_lookup( pQ, PIDBTYPE_STRING, pFKURI, PIDBFLAG_FASTKEY );
if ( !pURI )
{
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: pURI is NULL." );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );;
};
/* --- get directory --- */
const char *pPath = (const char *)PIDB_lookup( pR, PIDBTYPE_STRING,
pFKPath, PIDBFLAG_FASTKEY );
PIFInfo *pDir = HTTPCore_getCachedFile( pPath );
if ( !pDir )
{
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: \
HTTPCore_getCachedFile() failed.");
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
if ( !PIFInfo_exists( pDir ) )
{
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: Resource \
with path '%s' does not exist.", PIFInfo_getPath( pDir ) );
HTTPCore_releaseCachedFile( pDir );
return HTTPUtil_doHTTPError( &tPIHTTP, 404 );
};
if ( !PIFInfo_isDirectory( pDir ) )
{
HTTPCore_logError( &tPIHTTP, "DirectoryIndex: Resource \
with path '%s' is not a directory.", PIFInfo_getPath( pDir ) );
HTTPCore_releaseCachedFile( pDir );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* --- set the status --- */
tPIHTTP.iStatus = ST_OK;
/* --- replace content-type --- */
PIDB_replace( pR, PIDBTYPE_RFC822, pFKContentType,
(void *)"text/html", PIDBFLAG_FASTKEY );
/* --- send last modified --- */
Pi3String *pTmp = Pi3String_new( 0 );
time_t tT = PIFInfo_getLastModified( pDir );
PIPlatform_beforeUnsafeBlock();
struct tm *pTms = gmtime( &tT );
HTTPUtil_rFC822Time( pTms, pTmp );
PIPlatform_afterUnsafeBlock();
PIDB_add( pR, PIDBTYPE_RFC822, KEY_HTTP_LASTMODIFIED,
(void *)Pi3String_getPtr( pTmp ),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -