webserver.c
来自「基于LINUX/UNIX的UPN库,是智能家具的用的底层库.」· C语言 代码 · 共 1,765 行 · 第 1/4 页
C
1,765 行
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 if (http_MakeMessage( headers, resp_major, resp_minor, "R" "T" "GKD" "s" "tcS" "XcCc", HTTP_PARTIAL_CONTENT, // status code finfo.content_type, // content type RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT) != 0 ) { goto error_handler; } } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) { // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, "R" "N" "T" "GD" "s" "tcS" "XcCc", HTTP_PARTIAL_CONTENT, // status code RespInstr->ReadSendSize, // content length finfo.content_type, // content type RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT) != 0 ) { goto error_handler; } } else if( !RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, "RK" "TD" "s" "tcS" "XcCc", HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT) != 0 ) { goto error_handler; } } else { // !RespInstr->IsRangeActive && !RespInstr->IsChunkActive if (RespInstr->ReadSendSize >= 0) { // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, "R" "N" "TD" "s" "tcS" "XcCc", HTTP_OK, // status code RespInstr->ReadSendSize, // content length finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT) != 0 ) { goto error_handler; } } else { // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, "R" "TD" "s" "tcS" "XcCc", HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT) != 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 ); 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 fclose( Fp ); 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 ) { 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 = 0; 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, "RTDSXcCc", ret, "text/html", X_USER_AGENT ); http_SendMessage( info, &timeout, "b", headers.buf, headers.length ); break; default: assert( 0 ); } } UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, "webserver: request processed...\n" ); membuffer_destroy( &headers ); membuffer_destroy( &filename );}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?