📄 webserver.c
字号:
if( ( pVirtualDirCallback->
get_info( filename->buf, &finfo ) != UPNP_E_SUCCESS )
|| finfo.is_directory ) {
err_code = HTTP_NOT_FOUND;
goto error_handler;
}
}
// not readable
if( !finfo.is_readable ) {
err_code = HTTP_FORBIDDEN;
goto error_handler;
}
// finally, get content type
// if ( get_content_type(filename->buf, &content_type) != 0 )
//{
// goto error_handler;
// }
}
} else if( !using_alias ) {
if( gDocumentRootDir.length == 0 ) {
goto error_handler;
}
//
// get file name
//
// filename str
if( membuffer_assign_str( filename, gDocumentRootDir.buf ) != 0 ||
membuffer_append_str( filename, request_doc ) != 0 ) {
goto error_handler; // out of mem
}
// remove trailing slashes
while( filename->length > 0 &&
filename->buf[filename->length - 1] == '/' ) {
membuffer_delete( filename, filename->length - 1, 1 );
}
if( req->method != HTTPMETHOD_POST ) {
// get info on file
if( get_file_info( filename->buf, &finfo ) != 0 ) {
err_code = HTTP_NOT_FOUND;
goto error_handler;
}
// try index.html if req is a dir
if( finfo.is_directory ) {
if( filename->buf[filename->length - 1] == '/' ) {
temp_str = "index.html";
} else {
temp_str = "/index.html";
}
if( membuffer_append_str( filename, temp_str ) != 0 ) {
goto error_handler;
}
// get info
if( get_file_info( filename->buf, &finfo ) != 0 ||
finfo.is_directory ) {
err_code = HTTP_NOT_FOUND;
goto error_handler;
}
}
// not readable
if( !finfo.is_readable ) {
err_code = HTTP_FORBIDDEN;
goto error_handler;
}
}
// finally, get content type
// if ( get_content_type(filename->buf, &content_type) != 0 )
// {
// goto error_handler;
// }
}
RespInstr->ReadSendSize = finfo.file_length;
//Check other header field.
if( ( err_code =
CheckOtherHTTPHeaders( req, RespInstr,
finfo.file_length ) ) != HTTP_OK ) {
goto error_handler;
}
if( req->method == HTTPMETHOD_POST ) {
*rtype = RESP_POST;
err_code = UPNP_E_SUCCESS;
goto error_handler;
}
if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) {
//Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
//Transfer-Encoding: chunked
// K means add chunky header ang G means range header.
if( http_MakeMessage( headers, resp_major, resp_minor, "RTGKDstcSCc", HTTP_PARTIAL_CONTENT, // status code
// RespInstr->ReadSendSize,// content length
finfo.content_type,
// content_type.buf, // content type
RespInstr, // Range
"LAST-MODIFIED: ",
&finfo.last_modified ) != 0 ) {
goto error_handler;
}
} else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) {
//Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
//Transfer-Encoding: chunked
// K means add chunky header ang G means range header.
if( http_MakeMessage( headers, resp_major, resp_minor, "RNTGDstcSCc", HTTP_PARTIAL_CONTENT, // status code
RespInstr->ReadSendSize, // content length
finfo.content_type,
//content_type.buf, // content type
RespInstr, //Range Info
"LAST-MODIFIED: ",
&finfo.last_modified ) != 0 ) {
goto error_handler;
}
} else if( !RespInstr->IsRangeActive && RespInstr->IsChunkActive ) {
//Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
//Transfer-Encoding: chunked
// K means add chunky header ang G means range header.
if( http_MakeMessage( headers, resp_major, resp_minor, "RKTDstcSCc", HTTP_OK, // status code
//RespInstr->ReadSendSize,// content length
finfo.content_type,
// content_type.buf, // content type
"LAST-MODIFIED: ",
&finfo.last_modified ) != 0 ) {
goto error_handler;
}
} else {
if( RespInstr->ReadSendSize >= 0 ) {
//Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
//Transfer-Encoding: chunked
// K means add chunky header ang G means range header.
if( http_MakeMessage( headers, resp_major, resp_minor, "RNTDstcSCc", HTTP_OK, // status code
RespInstr->ReadSendSize, // content length
finfo.content_type,
//content_type.buf, // content type
"LAST-MODIFIED: ",
&finfo.last_modified ) != 0 ) {
goto error_handler;
}
} else {
//Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
//Transfer-Encoding: chunked
// K means add chunky header ang G means range header.
if( http_MakeMessage( headers, resp_major, resp_minor, "RTDstcSCc", HTTP_OK, // status code
//RespInstr->ReadSendSize,// content length
finfo.content_type,
//content_type.buf, // content type
"LAST-MODIFIED: ",
&finfo.last_modified ) != 0 ) {
goto error_handler;
}
}
}
if( req->method == HTTPMETHOD_HEAD ) {
*rtype = RESP_HEADERS;
} else if( using_alias ) {
// GET xml
*rtype = RESP_XMLDOC;
} else if( using_virtual_dir ) {
*rtype = RESP_WEBDOC;
} else {
// GET filename
*rtype = RESP_FILEDOC;
}
//simple get http 0.9 as specified in http 1.0
//don't send headers
if( req->method == HTTPMETHOD_SIMPLEGET ) {
membuffer_destroy( headers );
}
err_code = UPNP_E_SUCCESS;
error_handler:
free( request_doc );
ixmlFreeDOMString( finfo.content_type );
// membuffer_destroy( &content_type );
if( err_code != UPNP_E_SUCCESS && alias_grabbed ) {
alias_release( alias );
}
return err_code;
}
/************************************************************************
* Function: http_RecvPostMessage
*
* Parameters:
* http_parser_t* parser ; HTTP Parser object
* IN SOCKINFO *info ; Socket Information object
* char * filename ; File where received data is copied to
* struct SendInstruction * Instr ; Send Instruction object which gives
* information whether the file is a virtual file or not.
*
* Description: Receives the HTTP post message
*
* Returns:
* HTTP_INTERNAL_SERVER_ERROR
* HTTP_UNAUTHORIZED
* HTTP_REQUEST_RANGE_NOT_SATISFIABLE
* HTTP_OK
************************************************************************/
int
http_RecvPostMessage( http_parser_t * parser,
IN SOCKINFO * info,
char *filename,
struct SendInstruction *Instr )
{
unsigned int Data_Buf_Size = 1024;
char Buf[1024];
int Timeout = 0;
long Num_Write = 0;
FILE *Fp;
parse_status_t status = PARSE_OK;
xboolean ok_on_close = FALSE;
unsigned int entity_offset = 0;
int num_read = 0;
int ret_code = 0;
if( Instr && Instr->IsVirtualFile ) {
Fp = virtualDirCallback.open( filename, UPNP_WRITE );
if( Fp == NULL ) {
return HTTP_INTERNAL_SERVER_ERROR;
}
} else {
Fp = fopen( filename, "wb" );
if( Fp == NULL ) {
return HTTP_UNAUTHORIZED;
}
}
parser->position = POS_ENTITY;
do {
//first parse what has already been gotten
if( parser->position != POS_COMPLETE ) {
status = parser_parse_entity( parser );
}
if( status == PARSE_INCOMPLETE_ENTITY ) {
// read until close
ok_on_close = TRUE;
} else if( ( status != PARSE_SUCCESS )
&& ( status != PARSE_CONTINUE_1 )
&& ( status != PARSE_INCOMPLETE ) ) {
//error
return HTTP_BAD_REQUEST;
}
//read more if necessary entity
while( ( ( entity_offset + Data_Buf_Size ) >
parser->msg.entity.length )
&& ( parser->position != POS_COMPLETE ) ) {
num_read = sock_read( info, Buf, sizeof( Buf ), &Timeout );
if( num_read > 0 ) {
// append data to buffer
ret_code = membuffer_append( &parser->msg.msg,
Buf, num_read );
if( ret_code != 0 ) {
// set failure status
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
}
status = parser_parse_entity( parser );
if( status == PARSE_INCOMPLETE_ENTITY ) {
// read until close
ok_on_close = TRUE;
} else if( ( status != PARSE_SUCCESS )
&& ( status != PARSE_CONTINUE_1 )
&& ( status != PARSE_INCOMPLETE ) ) {
return HTTP_BAD_REQUEST;
}
} else if( num_read == 0 ) {
if( ok_on_close ) {
DBGONLY( UpnpPrintf
( UPNP_INFO, HTTP, __FILE__, __LINE__,
"<<< (RECVD) <<<\n%s\n-----------------\n",
parser->msg.msg.buf );
//print_http_headers( &parser->msg );
)
parser->position = POS_COMPLETE;
} else {
// partial msg
parser->http_error_code = HTTP_BAD_REQUEST; // or response
return HTTP_BAD_REQUEST;
}
} else {
return num_read;
}
}
if( ( entity_offset + Data_Buf_Size ) > parser->msg.entity.length ) {
Data_Buf_Size = parser->msg.entity.length - entity_offset;
}
memcpy( Buf, &parser->msg.msg.buf[parser->entity_start_position
+ entity_offset],
Data_Buf_Size );
entity_offset += Data_Buf_Size;
if( Instr->IsVirtualFile ) {
Num_Write = virtualDirCallback.write( Fp, Buf, Data_Buf_Size );
if( Num_Write < 0 ) {
virtualDirCallback.close( Fp );
return HTTP_INTERNAL_SERVER_ERROR;
}
} else {
Num_Write = fwrite( Buf, 1, Data_Buf_Size, Fp );
if( Num_Write < 0 ) {
fclose( Fp );
return HTTP_INTERNAL_SERVER_ERROR;
}
}
} while( ( parser->position != POS_COMPLETE )
|| ( entity_offset != parser->msg.entity.length ) );
if( Instr->IsVirtualFile ) {
virtualDirCallback.close( Fp );
} else {
fclose( Fp );
}
/*
while(TotalByteReceived < Instr->RecvWriteSize &&
(NumReceived = sock_read(info,Buf, Data_Buf_Size,&Timeout) ) > 0 )
{
TotalByteReceived = TotalByteReceived + NumReceived;
Num_Write = virtualDirCallback.write(Fp, Buf, NumReceived);
if (ferror(Fp))
{
virtualDirCallback.close(Fp);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
if(TotalByteReceived < Instr->RecvWriteSize)
{
return HTTP_INTERNAL_SERVER_ERROR;
}
virtualDirCallback.close(Fp);
}
*/
return HTTP_OK;
}
/************************************************************************
* Function: web_server_callback
*
* Parameters:
* IN http_parser_t *parser ; HTTP Parser Object
* INOUT http_message_t* req ; HTTP Message request
* IN SOCKINFO *info ; Socket information object
*
* Description: main entry point into web server;
* handles HTTP GET and HEAD requests
*
* Returns:
* void
************************************************************************/
void
web_server_callback( IN http_parser_t * parser,
INOUT http_message_t * req,
IN SOCKINFO * info )
{
int ret;
int timeout = 0;
enum resp_type rtype;
membuffer headers;
membuffer filename;
struct xml_alias_t xmldoc;
struct SendInstruction RespInstr;
//Initialize instruction header.
RespInstr.IsVirtualFile = 0;
RespInstr.IsChunkActive = 0;
RespInstr.IsRangeActive = 0;
RespInstr.IsTrailers = 0;
// init
membuffer_init( &headers );
membuffer_init( &filename );
//Process request should create the different kind of header depending on the
//the type of request.
ret =
process_request( req, &rtype, &headers, &filename, &xmldoc,
&RespInstr );
if( ret != UPNP_E_SUCCESS ) {
// send error code
http_SendStatusResponse( info, ret, req->major_version,
req->minor_version );
} else {
//
// send response
switch ( rtype ) {
case RESP_FILEDOC: // send file, I = further instruction to send data.
http_SendMessage( info, &timeout, "Ibf", &RespInstr,
headers.buf, headers.length,
filename.buf );
break;
case RESP_XMLDOC: // send xmldoc , I = further instruction to send data.
http_SendMessage( info, &timeout, "Ibb", &RespInstr,
headers.buf, headers.length,
xmldoc.doc.buf, xmldoc.doc.length );
alias_release( &xmldoc );
break;
case RESP_WEBDOC: //, I = further instruction to send data.
/*
http_SendVirtualDirDoc( info, &timeout, "Ibf",&RespInstr,
headers.buf, headers.length,
filename.buf );
*/
http_SendMessage( info, &timeout, "Ibf", &RespInstr,
headers.buf, headers.length,
filename.buf );
break;
case RESP_HEADERS: // headers only
http_SendMessage( info, &timeout, "b",
headers.buf, headers.length );
break;
case RESP_POST: // headers only
ret =
http_RecvPostMessage( parser, info, filename.buf,
&RespInstr );
//Send response.
http_MakeMessage( &headers, 1, 1, "RTDSCc", ret,
"text/html" );
http_SendMessage( info, &timeout, "b", headers.buf,
headers.length );
break;
default:
assert( 0 );
}
}
DBGONLY( UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
"webserver: request processed...\n" );
)
membuffer_destroy( &headers );
membuffer_destroy( &filename );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -