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

📄 sendfile.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		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 + -