📄 sendfile.cpp
字号:
/*____________________________________________________________________________*\
*
Copyright (c) 1997-2003 John Roy, Holger Zimmermann. All rights reserved.
These sources, libraries and applications are
FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
as long as the following conditions are adhered to.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*____________________________________________________________________________*|
*
* $Source: /cvsroot/pi3web/Pi3Web_200/Source/HTTP/SendFile.cpp,v $
* $Date: 2004/07/04 19:23:55 $
*
Description:
\*____________________________________________________________________________*/
//$SourceTop:$
#include <iostream.h>
#include <stdio.h>
#include <ctype.h>
#include <fstream.h>
#include "HandBase.h"
#include "HTTPCore.h"
#include "HTTPUtil.h"
#include "PIStrStr.h"
#include "StrToken.h"
#include "PIString.h"
#include "DeQuote.h"
#include "PiAPI.h"
/*____________________________________________________________________________*\
*
Description:
\*____________________________________________________________________________*/
#define KEY_CONF_HEADERPATTERN "HeaderPattern"
#define KEY_CONF_FOOTERPATTERN "FooterPattern"
#define KEY_CONF_METHODS "Methods"
#define KEY_CONF_FILEKEY "FileKey"
#define KEY_CONF_NOTEKEY "NoteKey"
#define KEY_CONF_UPLOADPATH "UploadPath"
#define KEY_CONF_UPLOADLIMIT "UploadLimit"
#define KEY_CONF_DESCFILE "DescriptionFile"
#define KEY_CONF_NOTE "Annotation"
#define KEY_CONF_RANGES "Ranges"
#define KEY_CONF_CHUNKLIMIT "ChunkLimit"
#define NOTE_EXT ".txt"
/*____________________________________________________________________________*\
*
Description:
\*____________________________________________________________________________*/
#if 0
/*
** HTML documentation for this handler
*/
/*___+++HTMLDOC_BEGIN+++___*/
Name:
SendFile
Description:
Send a file including headers to a remote client. If this is a 'HEAD'
request only the HTTP headers will be sent. This handler also handles
'PUT', 'DELETE' and 'POST' (HTTP form upload) requests.
<H5>Overview</H5>
<TABLE BORDER=1>
<TH>Option
<TH>Default
<TH>Values
<TH>Short Description
<TH>Example(s)
<TR>
<TD>HeaderPattern
<TD>-
<TD>A Pi3Expression
<TD>Output first
<TD>HeaderPattern="<HTML><TITLE>The Title</TITLE>"
<TR>
<TD>FooterPattern
<TD>-
<TD>A Pi3Expression
<TD>Output last
<TD>FooterPattern="</HTML>"
<TR>
<TD>Methods
<TD>GET | HEAD
<TD>GET | HEAD | PUT | DELETE | POST | OPTIONS | TRACE
<TD>Supported HTTP methods
<TD>Methods GET | HEAD | PUT | DELETE
<TR>
<TD>FileKey
<TD>-
<TD>A string
<TD>Key for the filename part of multipart HTTP message
<TD>FileKey "upfile"
<TR>
<TD>NoteKey
<TD>-
<TD>A string
<TD>Key for the annotation part of a multipart HTTP message
<TD>NoteKey "notes"
<TR>
<TD>UploadPath
<TD>-
<TD>A valid path in URL format.
<TD>Override the default path of a form upload
<TD>UploadPath "/uploads/"
<TR>
<TD>UploadLimit
<TD>0
<TD>A number >= 0.
<TD>Limitation of the upload filesize
<TD>UploadLimit 2.097.152
<TR>
<TD>DescriptionFile
<TD>-
<TD>A filename without a path
<TD>File with annotations about the uploaded file
<TD>DescriptionFile ".desc"
<TR>
<TD>Annotation
<TD>-
<TD>A Pi3Expression
<TD>Expression is written to 'filename_ext.txt' during upload
<TD>Annotation "From:\t$A$MHost:\t$h$MTime:\t$t$MUrl:\t\"$r\"$M"
<TR>
<TD>ChunkLimit
<TD>0
<TD>A number >= 0.
<TD>Minimum filesize for chunked transfer-encoding
<TD>ChunkLimit 32768
<TR>
<TD>Ranges
<TD>'none'
<TD>A string, either 'none' or 'bytes'.
<TD>Whether or not ranges are allowed.
<TD>Ranges bytes
</TABLE>
<STRONG>-</STRONG> in the <IT>default</IT> indicates no default<BR>
<STRONG>+</STRONG> in the <IT>default</IT> indicates the field is mandatory<BR>
<H4>Description of Options</H4>
<H5>HeaderPattern</H5>
Specifies a pattern of data that will be pre-appended to the file.
<H5>FooterPattern</H5>
Specifies a pattern of data that will be appended to the file.
<H5>Methods</H5>
A chain of option fields describing the HTTP methods supported by this handler.
Supported methods are GET | HEAD | PUT | DELETE | POST | OPTIONS.
The default is GET | HEAD if this option is omitted.
<P>The action caused by the HTTP methods are
<TABLE BORDER=1>
<TR>
<TH>Method
<TH>Action
<TR>
<TD>GET
<TD>To send the requested file to the browser.
<TR>
<TD>HEAD
<TD>To send only the HTTP header for the requested file to the browser.
<TR>
<TD>PUT
<TD>HTTP/1.1 request, to upload the requested file from a web browser to the server.
If the file already exists it must be a writeable and a regular file.
<TR>
<TD>DELETE
<TD>HTTP/1.1 request, to delete the requested file. File must exist and be a regular
file or directory. Deletion works not recursive in directories and directory must be
empty.
<TR>
<TD>POST
<TD>To upload a file using HTTP form upload with multipart message. An upload form
looks like
<P><XMP>
<HTML>
<BODY>
<FORM method="POST" enctype="multipart/form-data" action="/errors/success.htm">
<P>File <INPUT type=file name=upfile>
<P>Notes <INPUT type=text name=notes>
<P> <INPUT type=submit value=Upload>
</FORM>
</BODY>
</HTML>
</XMP>
You can use PathInfo to redirect file to an upload directory action="/errors/success.htm".
The file in the action URL should always expire. Your browser will force this with a meta
tag in the HTML-Header
<P><XMP>
<META http-equiv="expires" content="0">
</XMP>
<TR>
<TD>OPTIONS
<TD>HTTP/1.1 request, to retrieve the supported methods for the respective URL or
the server itself.
<TR>
<TD>TRACE
<TD>HTTP/1.1 request, which works like an echo handler. this could be used to test
the client
</TABLE>
<H5>FileKey</H5>
The key for the filename part during HTTP form upload of a multipart HTTP message.
This value is usually the same as the parameter 'name' of the filename input field
within the upload form.
<H5>NoteKey</H5>
The key for the annotation part during HTTP form upload of a multipart HTTP message.
This value is usually the same as the parameter 'name' of the annotations input field
within an upload form.
<H5>UploadPath</H5>
A valid path in URL format. This value overrides the default path of a form upload.
The default path is the PathInfo of the HTTP request URL.
<H5>UploadLimit</H5>
This option is used to limitate the maximum number of bytes for a single file upload.
<H5>DescriptionFile</H5>
Allows to write annotations about uploaded file into a descriptive file. This file has
usually the same name as the file used by the HTML-directory index for descriptions.
<H5>Annotation</H5>
The parsed Pi3Expression is written to a file 'filename_ext.txt' during upload.
The annotations are listed in the directory index of the upload directory visible for
other users.
<H5>ChunkLimit</H5>
This option determines the minimum filesize to be used for chunked transfer-encoding.
If a file exceeds the limit, the content is encoded using chunks, if not, the content
is transfered as usual. A value of 0 switches the feature off.
<H5>Ranges</H5>
This option determines, whether or not range requests will be answered. A GET/HEAD
request containing the 'Range' or 'If-Range' header is then handled as a partial GET/HEAD.
Currently only simple byte ranges are supported.
Phase:
HANDLE
Returns:
PIAPI_COMPLETED if the file was sent. INT_REDIRECT is returned in a POST
request if the file was uploaded.
If this handler was invoked for a phase other than HANDLE then PIAPI_ERROR
is returned.
Note:
Example:
<PRE>
<Object>
Name SendFile
Class SendFileClass
</Object>
<Object>
...
Handle SendFile
...
</Object>
</PRE>
/*___+++HTMLDOC_END+++___*/
#endif
int fnMultipartCb( int iKind, char *szName, char *szData, long lData, PIHTTP *pPIHTTP, void *pUser );
#define FLG_GET 0x00000002
#define FLG_POST 0x00000004
#define FLG_HEAD 0x00000008
#define FLG_PUT 0x00000010
#define FLG_DELETE 0x00000020
#define FLG_OPTIONS 0x00000040
#define FLG_TRACE 0x00000080
#define FLG_CONNECT 0x00000100
/*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ *
Map these flags to names
*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ */
struct {
const char *pName;
int iFlag;
} aMethodMap[] =
{
{ MD_NAME_GET, FLG_GET },
{ MD_NAME_POST, FLG_POST },
{ MD_NAME_HEAD, FLG_HEAD },
{ MD_NAME_PUT, FLG_PUT },
{ MD_NAME_DELETE, FLG_DELETE },
{ MD_NAME_OPTIONS, FLG_OPTIONS },
{ MD_NAME_TRACE, FLG_TRACE },
{ MD_NAME_CONNECT, FLG_CONNECT },
/* --- leave this last always --- */
{ 0, 0 }
};
/*____________________________________________________________________________*\
*
Class:
Description:
\*____________________________________________________________________________*/
class DescriptionMap
{
public:
PIString sFileName;
PIString sDescription;
DescriptionMap( const char *pLine )
{
assert( pLine );
int iLen = strlen( pLine );
int i=0;
for( i=0; i<iLen && pLine[i]!='|'; i++ );
PIString sTmp( pLine, i );
sFileName = sTmp;
if ( i<iLen ) { i++; };
pLine= &( pLine[i] );
sDescription = pLine;
};
DescriptionMap( PIString sFile, char *szBuf, int lBuf )
{
sFileName = sFile;
PIString sTmp( szBuf, lBuf );
sDescription = sTmp;
};
};
/*____________________________________________________________________________*\
*
Class:
Description:
\*____________________________________________________________________________*/
class SendFile : public HandlerBaseHTTP
{
friend int fnMultipartCb( int iKind, char *szName, char *szData, long lData, PIHTTP *pPIHTTP, void *pUser );
private:
/* ---
Configuration data
--- */
Pi3Expression *pHeaderPattern; /* pattern for top */
Pi3Expression *pFooterPattern; /* pattern for footer */
int iMethods; /* flags for supported HTTP-Methods */
PIString sFileKey;
PIString sNoteKey;
Pi3Expression *pAnnotation;
PIString sDescFile;
PIString sPathInfo;
PIString sUploadPath;
PIString sUploadFile;
int iUploadLimit;
int iChunkLimit;
int iAllowRanges;
PIPLATFORM_FD tFD;
// Fast DB lookup keys
const char *pFKMethod;
const char *pFKRange;
const char *pFKIfRange;
const char *pFKPath;
const char *pFKProtocol;
protected:
/*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ *
Load an expression or condition
*___ +++++++++++++++++++++++++++++++++++++++++++++++++ ___ */
int LoadExpression( const char *pName, Pi3Expression **ppExpression,
FnPi3Write *pFunctions, const char *pValue, PIOStrStream &os )
{
assert( ppExpression );
Pi3Expression *pExpression = *ppExpression;
if ( pExpression )
{
os << "'" << pName << "' may only be specified once." << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String *pError = Pi3String_new( 0 );
pExpression = Pi3Expression_new( pValue, pFunctions, pError );
if ( !pExpression )
{
os << "Error parsing expression: " <<
Pi3String_getPtr( pError ) << ends;
CONFIG_ERR( Object(), os.str() );
Pi3Expression_delete( pExpression );
Pi3String_delete( pError );
return 0;
};
Pi3String_delete( pError );
*ppExpression = pExpression;
return 1;
};
int Parameter( const char *pVariable, const char *pValue,
const char *pWhere )
{
assert( pVariable && pValue );
PIOStrStream os;
os << pWhere << "SendFile: ";
if ( !PIUtil_stricmp( KEY_CONF_HEADERPATTERN, pVariable ))
{
if ( !LoadExpression( KEY_CONF_HEADERPATTERN, &pHeaderPattern,
0, pValue, os ) )
{ return 0; };
assert( pHeaderPattern );
}
else if ( !PIUtil_stricmp( KEY_CONF_FOOTERPATTERN, pVariable ))
{
if ( !LoadExpression( KEY_CONF_FOOTERPATTERN, &pFooterPattern, 0, pValue, os ))
{ return 0; };
assert( pFooterPattern );
}
else if ( !PIUtil_stricmp( KEY_CONF_FILEKEY, pVariable ))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -