📄 webserver.c
字号:
// 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 ************************************************************************/inthttp_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 ************************************************************************/voidweb_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 + -