📄 httpreadwrite.c
字号:
/////////////////////////////////////////////////////////////////////////////// Copyright (c) 2000-2003 Intel Corporation // All rights reserved. //// Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: //// * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * 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. // * Neither name of Intel Corporation nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission.// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS 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 INTEL OR // 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.//////////////////////////////////////////////////////////////////////////////************************************************************************* Purpose: This file defines the functionality making use of the http * It defines functions to receive messages, process messages, send * messages************************************************************************/#include <assert.h>#include <stdarg.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <unistd.h>#include <sys/utsname.h>#include "unixutil.h"#include "config.h"#include "upnp.h"#include "upnpapi.h"#include "membuffer.h"#include "uri.h"#include "statcodes.h"#include "httpreadwrite.h"#include "sock.h"#include "webserver.h"#define DOSOCKET_READ 1#define DOSOCKET_WRITE 0/************************************************************************* Function: http_FixUrl * * Parameters: * IN uri_type* url ; URL to be validated and fixed* OUT uri_type* fixed_url ; URL after being fixed.* * Description: Validates URL * * Returns: * UPNP_E_INVALID_URL * UPNP_E_SUCCESS ************************************************************************/inthttp_FixUrl( IN uri_type * url, OUT uri_type * fixed_url ){ char *temp_path = "/"; *fixed_url = *url; if( token_string_casecmp( &fixed_url->scheme, "http" ) != 0 ) { return UPNP_E_INVALID_URL; } if( fixed_url->hostport.text.size == 0 ) { return UPNP_E_INVALID_URL; } // set pathquery to "/" if it is empty if( fixed_url->pathquery.size == 0 ) { fixed_url->pathquery.buff = temp_path; fixed_url->pathquery.size = 1; } return UPNP_E_SUCCESS;}/************************************************************************* Function: http_FixStrUrl * * Parameters: * IN char* urlstr ; Character string as a URL * IN int urlstrlen ; Length of the character string * OUT uri_type* fixed_url ; Fixed and corrected URL* * Description: Parses URL and then validates URL * * Returns: * UPNP_E_INVALID_URL * UPNP_E_SUCCESS ************************************************************************/inthttp_FixStrUrl( IN char *urlstr, IN int urlstrlen, OUT uri_type * fixed_url ){ uri_type url; if( parse_uri( urlstr, urlstrlen, &url ) != HTTP_SUCCESS ) { return UPNP_E_INVALID_URL; } return http_FixUrl( &url, fixed_url );}/************************************************************************* Function: http_Connect * * Parameters: * IN uri_type* destination_url ; URL containing destination information * OUT uri_type *url ; Fixed and corrected URL* * Description: Gets destination address from URL and then connects to the * remote end* * Returns: * socket descriptor on sucess * UPNP_E_OUTOF_SOCKET * UPNP_E_SOCKET_CONNECT on error ************************************************************************/inthttp_Connect( IN uri_type * destination_url, OUT uri_type * url ){ int connfd; http_FixUrl( destination_url, url ); connfd = socket( AF_INET, SOCK_STREAM, 0 ); if( connfd == -1 ) { return UPNP_E_OUTOF_SOCKET; } if( connect( connfd, ( struct sockaddr * )&url->hostport.IPv4address, sizeof( struct sockaddr_in ) ) == -1 ) { shutdown( connfd, SD_BOTH ); UpnpCloseSocket( connfd ); return UPNP_E_SOCKET_CONNECT; } return connfd;}/************************************************************************* Function: http_RecvMessage * * Parameters: * IN SOCKINFO *info ; Socket information object* OUT http_parser_t* parser, HTTP parser object* IN http_method_t request_method ; HTTP request method * IN OUT int* timeout_secs ; time out * OUT int* http_error_code ; HTTP error code returned* * Description: Get the data on the socket and take actions based on the * read data to modify the parser objects buffer. If an error is reported * while parsing the data, the error code is passed in the http_errr_code * parameter* * Returns: * UPNP_E_BAD_HTTPMSG * UPNP_E_SUCCESS ************************************************************************/inthttp_RecvMessage( IN SOCKINFO * info, OUT http_parser_t * parser, IN http_method_t request_method, IN OUT int *timeout_secs, OUT int *http_error_code ){ parse_status_t status; int num_read; xboolean ok_on_close = FALSE; char buf[2 * 1024]; if( request_method == HTTPMETHOD_UNKNOWN ) { parser_request_init( parser ); } else { parser_response_init( parser, request_method ); } while( TRUE ) { num_read = sock_read( info, buf, sizeof( buf ), timeout_secs ); if( num_read > 0 ) { // got data status = parser_append( parser, buf, num_read ); if( status == PARSE_SUCCESS ) { DBGONLY( UpnpPrintf ( UPNP_INFO, HTTP, __FILE__, __LINE__, "<<< (RECVD) <<<\n%s\n-----------------\n", parser->msg.msg.buf ); //print_http_headers( &parser->msg ); ) if( parser->content_length > ( unsigned int )g_maxContentLength ) { *http_error_code = HTTP_REQ_ENTITY_TOO_LARGE; return UPNP_E_BAD_HTTPMSG; } return 0; } else if( status == PARSE_FAILURE ) { *http_error_code = parser->http_error_code; return UPNP_E_BAD_HTTPMSG; } else if( status == PARSE_INCOMPLETE_ENTITY ) { // read until close ok_on_close = TRUE; } else if( status == PARSE_CONTINUE_1 ) //Web post request. murari { return PARSE_SUCCESS; } } 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 ); ) return 0; } else { // partial msg *http_error_code = HTTP_BAD_REQUEST; // or response return UPNP_E_BAD_HTTPMSG; } } else { *http_error_code = parser->http_error_code; return num_read; } }}/************************************************************************* Function: http_SendMessage * * Parameters: * IN SOCKINFO *info ; Socket information object* IN OUT int * TimeOut ; time out value * IN const char* fmt, ... Pattern format to take actions upon * * Description: Sends a message to the destination based on the * IN const char* fmt parameter * fmt types: * 'f': arg = const char * file name * 'm': arg1 = const char * mem_buffer; arg2= size_t buf_length * E.g.: * char *buf = "POST /xyz.cgi http/1.1\r\n\r\n"; * char *filename = "foo.dat"; * int status = http_SendMessage( tcpsock, "mf", * buf, strlen(buf), // args for memory buffer * filename ); // arg for file * * Returns: * UPNP_E_OUTOF_MEMORY * UPNP_E_FILE_READ_ERROR * UPNP_E_SUCCESS ************************************************************************/inthttp_SendMessage( IN SOCKINFO * info, IN OUT int *TimeOut, IN const char *fmt, ... ){#define CHUNK_HEADER_SIZE 10#define CHUNK_TAIL_SIZE 10 char c; char *buf = NULL; size_t buf_length; char *filename = NULL; FILE *Fp; int num_read, num_written, amount_to_be_read = 0; va_list argp; char *file_buf = NULL, *ChunkBuf = NULL; struct SendInstruction *Instr = NULL; char Chunk_Header[10]; int RetVal = 0; // 10 byte allocated for chunk header. int Data_Buf_Size = WEB_SERVER_BUF_SIZE; va_start( argp, fmt ); while( ( c = *fmt++ ) != 0 ) { if( c == 'I' ) { Instr = ( struct SendInstruction * ) va_arg( argp, struct SendInstruction * ); assert( Instr ); if( Instr->ReadSendSize >= 0 ) amount_to_be_read = Instr->ReadSendSize; else amount_to_be_read = Data_Buf_Size; if( amount_to_be_read < WEB_SERVER_BUF_SIZE ) Data_Buf_Size = amount_to_be_read; ChunkBuf = ( char * )malloc( Data_Buf_Size + CHUNK_HEADER_SIZE + CHUNK_TAIL_SIZE ); if( !ChunkBuf ) return UPNP_E_OUTOF_MEMORY; file_buf = ChunkBuf + 10; } if( c == 'f' ) { // file name filename = ( char * )va_arg( argp, char * ); if( Instr && Instr->IsVirtualFile ) Fp = virtualDirCallback.open( filename, UPNP_READ ); else Fp = fopen( filename, "rb" ); if( Fp == NULL ) { free( ChunkBuf ); return UPNP_E_FILE_READ_ERROR; } assert( Fp ); if( Instr && Instr->IsRangeActive && Instr->IsVirtualFile ) { if( virtualDirCallback.seek( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) { free( ChunkBuf ); return UPNP_E_FILE_READ_ERROR; } } else if( Instr && Instr->IsRangeActive ) { if( fseek( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) { free( ChunkBuf ); return UPNP_E_FILE_READ_ERROR; } } while( amount_to_be_read ) { if( Instr ) { if( amount_to_be_read >= Data_Buf_Size ) { if( Instr->IsVirtualFile ) num_read = virtualDirCallback.read( Fp, file_buf, Data_Buf_Size ); else num_read = fread( file_buf, 1, Data_Buf_Size, Fp ); } else { if( Instr->IsVirtualFile ) num_read = virtualDirCallback.read( Fp, file_buf, amount_to_be_read ); else num_read = fread( file_buf, 1, amount_to_be_read, Fp ); } amount_to_be_read = amount_to_be_read - num_read; if( Instr->ReadSendSize < 0 ) { //read until close amount_to_be_read = Data_Buf_Size; } } else { num_read = fread( file_buf, 1, Data_Buf_Size, Fp ); } if( num_read == 0 ) // EOF so no more to send. { if( Instr && Instr->IsChunkActive ) { num_written = sock_write( info, "0\r\n\r\n", strlen( "0\r\n\r\n" ), TimeOut ); } else { RetVal = UPNP_E_FILE_READ_ERROR; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -