⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sendfile.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			sFileKey = (const char *)DeQuote( pValue );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_NOTEKEY, pVariable ))
			{
			sNoteKey = (const char *)DeQuote( pValue );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_NOTE, pVariable ))
			{
			if ( !LoadExpression( KEY_CONF_NOTE, &pAnnotation, 0, pValue, os ))
				{ return 0; };
			assert( pAnnotation );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_DESCFILE, pVariable ))
			{
			sDescFile = (const char *)DeQuote( pValue );
			PIFInfo *pFInfo = HTTPCore_getCachedFile( sDescFile );
			if ( !pFInfo || strcspn( PIFInfo_getPath( pFInfo ), "/\\" ) < strlen( sDescFile ))
				{
				HTTPCore_releaseCachedFile( pFInfo );
				os << "Error during read parameter '" << pVariable << "' or \
the filename '" << sDescFile << "' contains a path." << ends;
				CONFIG_ERR( Object(), os.str() );
				return 0;
				};
			HTTPCore_releaseCachedFile( pFInfo );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_UPLOADPATH, pVariable ))
			{
			sPathInfo = (const char *)DeQuote( pValue );			
			}
		else if ( !PIUtil_stricmp( KEY_CONF_UPLOADLIMIT, pVariable ))
			{
			iUploadLimit = atol( (const char *)pValue );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_CHUNKLIMIT, pVariable ))
			{
			iChunkLimit = atol( (const char *)pValue );
			}
		else if ( !PIUtil_stricmp( KEY_CONF_METHODS, pVariable ))
			{
			/* ---
			Split the options up by the bar ('|') character and then
			strip trailing and leading whitespace from option before
			attempting to match it.
			--- */
			StringTokenizer tTokens( pValue, "|" );
			iMethods = 0;
			for(int i = 0; i < tTokens.NumTokens(); i++)
				{
				const char *pToken = tTokens.GetToken( i );

				/* --- skip leading whitespace --- */
				for( ; *pToken && (isspace(*pToken)); pToken++ );

				/* ---
				include only to first whitespace trailing whitespace
				--- */
				int j=0;
				for( ; pToken[j] && !(isspace(pToken[j])); j++ );
				/* ---
				j now contains the length of the first word in pToken
				--- */

				/* ---
				cycle through the list of available flags
				comparing them with this one
				--- */
				int i=0;
				for( ; aMethodMap[i].pName; i++ )
					{
					if ( !PIUtil_strncmpi( aMethodMap[i].pName, pToken, j ) )
						{ break; };
					};
				if ( !aMethodMap[i].pName )
					{
					/* --- flag not found --- */
					PIString sTmp( pToken, j );
					os << "Unknown HTTP method flag '" << sTmp << "'." << ends;
					CONFIG_ERR( Object(), os.str() );
					return 0;
					};
				iMethods |= aMethodMap[i].iFlag;
				};	/* --- loop over tokens seperated by '|' --- */
			}
		else if ( !PIUtil_stricmp( KEY_CONF_RANGES, pVariable ))
			{
			iAllowRanges = PIUtil_stricmp((const char *)DeQuote( pValue ), KEY_HTTP_BYTES) == 0;

			if ( iAllowRanges && (pHeaderPattern || pFooterPattern) )
				{
				os << "Ranges cannot be configured together with header/footer pattern." << ends;
				CONFIG_ERR( Object(), os.str() );
				return 0;
				}
			}
		else
			{
			os << "Unknown directive '" << pVariable <<
				"'" << ends;
			CONFIG_ERR( Object(), os.str() );
			return 0;
			};

		return 1;
		};


	/* ---
	Create a translated path
	--- */
	int GetPathTranslated( PIHTTP &tPIHTTP, PIString &sPath )
		{
		/* --- make sub request context --- */
		PIHTTP *pChildHTTP = PIHTTP_newChild( &tPIHTTP );

		/* --- set path --- */
		PIDB_replace( pChildHTTP->pResponseDB, PIDBTYPE_STRING,
			KEY_INT_PATH, (void *)(const char *)sPath, 0 );

		/* --- dispatch the sub request across the mapping phase --- */
		int iRet = PIAPI_ERROR;
		iRet = HTTPCore_dispatch( pChildHTTP, PH_MAPPING, PH_MAPPING );
			
		/* --- copy the childs path to this path translated --- */
		if ( iRet == PIAPI_COMPLETED && (( pChildHTTP->iStatus == 0 )
			|| ( pChildHTTP->iStatus == ST_OK )))
			{
			sPath = (const char *)PIDB_lookup( pChildHTTP->pResponseDB, PIDBTYPE_STRING,
				KEY_INT_PATH, 0 );
			}
		else
			{
			PIHTTP_delete( pChildHTTP );
			return PIAPI_ERROR;
			};

		PIHTTP_delete( pChildHTTP );
		return PIAPI_COMPLETED;
		};


	/* ---
	Reset the mapped path before doing internal direct
	--- */
	int ResetPath( PIHTTP &tPIHTTP )
	{
		int iRet = PIAPI_COMPLETED;

		const char *pURI = (const char *)PIDB_lookup( tPIHTTP.pRequestDB, 
					PIDBTYPE_STRING, KEY_HTTP_URI, 0 );
		if ( pURI ) 
			{
			char *pTmp = new char[strlen(pURI)+1];
			strcpy( pTmp, pURI ); 

			/* ---
			Then contract it to avoid side effects of '.' and '..' in
			the URL
			--- */
			if ( HTTPUtil_contractPath( pTmp )>0 )
				{
				/* --- force a 403 (forbidden) error --- */
				tPIHTTP.iStatus = ST_FORBIDDEN;
				iRet = INT_REDIRECT;
				}
			else
				{
				PIDB_replace( tPIHTTP.pResponseDB, PIDBTYPE_STRING,
					KEY_INT_PATH, pTmp, 0 );
				};

			delete [] pTmp;
			}
		else
			{
			HTTPCore_logError( &tPIHTTP, "Could not set request path\n" );
			iRet = HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
			};

		return iRet;
	}

	/* ---
	Load a description file, if one exists and contains descriptions return 1
	else 0
	--- */
	int LoadDescriptionFile( PIDB *pDescriptionDB, PIString sPath ) const
		{
		assert( pDescriptionDB );
		assert( sPath );

		/* --- get the file --- */
		PIFInfo *pFInfo = HTTPCore_getCachedFile( sPath );
		if ( !pFInfo ) return 0;

		if ( PIFInfo_exists( pFInfo ) && PIFInfo_isRegular( pFInfo ))
			{	
			enum { BUF_SIZE=1023 };
			char szBuf[BUF_SIZE+1];
			*szBuf = '\0';
			ifstream ifs( PIFInfo_getPath( pFInfo ) );
			while( ifs && !ifs.eof() ) 	
				{
				ifs.getline( szBuf, BUF_SIZE );
				if ( strlen( szBuf ))
					{
					DescriptionMap *pDesc = PI_NEW( DescriptionMap( szBuf ));
					PIDB_add( pDescriptionDB, PIDBTYPE_OPAQUE, pDesc->sFileName,
						(void *)pDesc, 0 );
					};
				};
			};
		HTTPCore_releaseCachedFile( pFInfo );
		return 1;
		};


	/* ---
	Save a description file, success return 1 else 0
	--- */
	int SaveDescriptionFile( PIDB *pDescriptionDB, PIString sPath ) const
		{
		assert( pDescriptionDB );
		assert( sPath );

		/* --- get the file --- */
		PIFInfo *pFInfo = HTTPCore_getCachedFile( sPath );
		if ( !pFInfo ) return 0;
		if ( PIFInfo_exists( pFInfo ) && !PIFInfo_isRegular( pFInfo )) return 0;
	
		ofstream ofs( PIFInfo_getPath( pFInfo ) );

		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 );
				ofs << pDesc->sFileName << "|" << pDesc->sDescription << "\n";

				PI_DELETE( pDesc );
				};
			};
		PIDBIterator_delete( pIter );
		HTTPCore_releaseCachedFile( pFInfo );
		return 1;
		};

	/* ---
	returns 1 if the file has been modified, i.e. needs to be completely reloaded
	--- */
	int checkIfRange( const char *szIfRangeHeader, PIFInfo *pFInfo )
		{
		// no If-Range header, continue
		if (!szIfRangeHeader) return 0;

		/* --- read file Last-Modified --- */
		time_t tTmp = PIFInfo_getLastModified( pFInfo );

		PIPlatform_beforeUnsafeBlock();
		struct tm *pLM = gmtime( &tTmp );
		if ( !pLM )
			{
			PIPlatform_afterUnsafeBlock();
			return 1;
			};
		struct tm tLM;
		memcpy( &tLM, pLM, sizeof( struct tm ) );
		PIPlatform_afterUnsafeBlock();

		/* --- read If-Modified-Since time --- */
		struct tm tIMS;
		if ( HTTPUtil_readTime( szIfRangeHeader, &tIMS ) )
			{ return 1; };

		/* ---
		Compare modification dates
		--- */
		return (
			tLM.tm_sec != tIMS.tm_sec ||
			tLM.tm_min != tIMS.tm_min ||
			tLM.tm_hour != tIMS.tm_hour ||
			tLM.tm_mday != tIMS.tm_mday ||
			tLM.tm_mon != tIMS.tm_mon ||
			tLM.tm_year != tIMS.tm_year
			);
		}

	/* ---
	Implementation of HTTP methods GET and HEAD (send headers and file)
	--- */
	int Get_Head( PIHTTP &tPIHTTP, int iMethod, const char *szRangeHeader )
		{
		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 );
		};

		/* --- ranges (RFC2616, 14.35) --- */
		unsigned int uiFrom = 0;
		unsigned int uiTo = 0;
		int iFileSize = PIFInfo_getSize( pFInfo );
		int iRange = 0;

		if ( iAllowRanges )
			{
			// Tell the client, that this handler supports ranges
			PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_ACCEPTRANGES, (void *)KEY_HTTP_BYTES, 0 );

			const char *szIfRangeHeader = (const char *)PIDB_lookup( pQ, PIDBTYPE_RFC822,
				pFKIfRange, PIDBFLAG_FASTKEY);

			// extract range values and perform some sanity checks
			if (szRangeHeader)
				{
				// This handler supports only byte ranges 
				if ( int i = PIUtil_strncmpi(szRangeHeader, KEY_HTTP_BYTES, sizeof(KEY_HTTP_BYTES)-1)
				  || strchr(szRangeHeader, ',') )
					{
					HTTPCore_logError( &tPIHTTP, "SendFile: Only simple byte ranges are supported.");
					PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTRANGE, (void *)"*", 0 );
					HTTPCore_releaseCachedFile( pFInfo );
					return HTTPUtil_doHTTPError( &tPIHTTP, ST_RANGENOTSATISFIABLE );
					}

				// search for '='
				const char *szFrom = strchr(szRangeHeader, '=');
				if (szFrom)	szFrom++;

				// szFrom now points to the 1st char beyond the '=',
				// i.e. can contain only '-' or digits
				if (!szFrom || strcspn(szFrom, "-1234567890"))
					{
					HTTPCore_logError( &tPIHTTP, "SendFile: Invalid range specifier.");
					PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTRANGE, (void *)"*", 0 );
					HTTPCore_releaseCachedFile( pFInfo );
					return HTTPUtil_doHTTPError( &tPIHTTP, ST_RANGENOTSATISFIABLE );
					}

				// search for '-' 
				const char *szTo = strchr(szRangeHeader, '-');

				// szTo can contain only '-' or digits
				if (!szTo || strcspn(szTo, "-1234567890"))
					{
					HTTPCore_logError( &tPIHTTP, "SendFile: Invalid range specifier.");
					PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTRANGE, (void *)"*", 0 );
					HTTPCore_releaseCachedFile( pFInfo );
					return HTTPUtil_doHTTPError( &tPIHTTP, ST_RANGENOTSATISFIABLE );
					}
				
				// this means a range spec. of (final) 'bytes=-nnnn'
				if (szFrom == szTo)
					{
					uiFrom = iFileSize-1 - atol(szTo++);
					uiTo = iFileSize-1;
					}

				// this means a range spec. of (final) 'bytes=nnnn-'
				else if (strlen(szTo) == 1)
					{
					uiFrom = atol(szFrom);
					uiTo = iFileSize-1;
					}

				// this means a range spec. of 'bytes=nnnn-mmmm'
				else
					{
					uiFrom = atol(szFrom);
					uiTo = atol(szTo++);
					}

				iRange = 1 + uiTo - uiFrom;

				// Sanity check of the range values
				if (iRange < 1 || iRange > iFileSize || uiTo > iFileSize-1 )
					{
					HTTPCore_logError( &tPIHTTP, "SendFile: Invalid range specifier.");
					PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTRANGE, (void *)"*", 0 );
					HTTPCore_releaseCachedFile( pFInfo );
					return HTTPUtil_doHTTPError( &tPIHTTP, ST_RANGENOTSATISFIABLE );
					}

				// evaluate IfRangeHeader, we do this after the sanity check
				// to be sure the Range header is valid nevertheless
				if ( checkIfRange( szIfRangeHeader, pFInfo ) )
					{
					// file is modified, i.e. the whole file mus be re-sent
					uiFrom = 0;
					uiTo = iFileSize;
					iRange = 1 + uiTo - uiFrom;
					}

				enum { BUF_SIZE=63 };
				char szBuf[BUF_SIZE+1];
				sprintf(szBuf, "bytes %d-%d/%d",uiFrom, uiTo, iFileSize);
				PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTRANGE, szBuf, 0 );
				}
			else
				{
				// If-Range requires a Range header
				if (szIfRangeHeader)
					{
					HTTPCore_logError( &tPIHTTP, "SendFile: If-Range header without Range received.");
					HTTPCore_releaseCachedFile( pFInfo );
					return HTTPUtil_doHTTPError( &tPIHTTP, ST_BADREQUEST );
					}
				}
			}
		else
			{
			// Tell the client, that this handler doesn't support ranges
			PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_ACCEPTRANGES, (void *)KEY_HTTP_NONE, 0 );

			// Can't handle range request, the support for ranges has been switched off
			// Exception: the whole resource has been requested (bytes=0-)
			if (szRangeHeader && PIUtil_stricmp(szRangeHeader, "bytes=0-"))
				{
				HTTPCore_logError( &tPIHTTP, "SendFile: This handler is not configured to support ranges.");
				HTTPCore_releaseCachedFile( pFInfo );
				return HTTPUtil_doHTTPError( &tPIHTTP, ST_NOTIMPLEMENTED );
				}
			}

		/* --- 	
		Get the header
		--- */
		enum { PATTERN_BUF_SIZE=1024 };
		char szHeader[PATTERN_BUF_SIZE];
		char *pHeader = 0;
		int iHeaderLen = 0;
		if ( pHeaderPattern )
			{
			pHeader = ( iMethod==MD_GET ) ? szHeader : 0;
			iHeaderLen = Pi3Expression_write( pHeaderPattern, &tPIHTTP, 0, pHeader, PATTERN_BUF_SIZE );

			if ( iHeaderLen>PATTERN_BUF_SIZE && pHeader )
				{
				pHeader = PI_NEW( char[iHeaderLen] );
				Pi3Expression_write( pHeaderPattern, &tPIHTTP, 0, pHeader, iHeaderLen );
				};
			};

		/* --- 	
		Get the footer
		--- */
		char szFooter[PATTERN_BUF_SIZE];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -