httpreadwrite.c
来自「原来由英特尔制定的UPnP SDK的」· C语言 代码 · 共 2,067 行 · 第 1/5 页
C
2,067 行
/////////////////////////////////////////////////////////////////////////////// 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 "config.h"#include <assert.h>#include <stdarg.h>#ifndef UPNP_USE_BCBPP #ifndef UPNP_USE_MSVCPP #include <inttypes.h> #include <stdint.h> #endif#endif#ifndef WIN32 #include <arpa/inet.h> #include <fcntl.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>#else #include <winsock2.h> #include <malloc.h>#endif#include "unixutil.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"/* * Please, do not change these to const int while MSVC cannot understand * const int in array dimensions. *//*const int CHUNK_HEADER_SIZE = 10;const int CHUNK_TAIL_SIZE = 10;*/#define CHUNK_HEADER_SIZE 10#define CHUNK_TAIL_SIZE 10/************************************************************************ * 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 ) {#ifdef WIN32 UpnpPrintf(UPNP_CRITICAL, HTTP, __FILE__, __LINE__, "connect error: %d\n", WSAGetLastError());#endif 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 ) { 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_OUTOF_BOUNDS; } 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 ) { 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, ... ){ char c; char *buf = NULL; size_t buf_length; char *filename = NULL; FILE *Fp; int num_read; int num_written; off_t amount_to_be_read = 0; va_list argp; char *file_buf = NULL; char *ChunkBuf = NULL; struct SendInstruction *Instr = NULL; char Chunk_Header[CHUNK_HEADER_SIZE]; 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 = 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 + CHUNK_HEADER_SIZE; } else if( c == 'f' ) { // file name filename = 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; } 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( fseeko( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) { free( ChunkBuf ); return UPNP_E_FILE_READ_ERROR; } } while( amount_to_be_read ) { if( Instr ) { int n = (amount_to_be_read >= Data_Buf_Size) ? Data_Buf_Size : amount_to_be_read; if( Instr->IsVirtualFile ) { num_read = virtualDirCallback.read( Fp, file_buf, n ); } else { num_read = fread( file_buf, 1, n, 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 ) { char *str = "0\r\n\r\n"; num_written = sock_write(info, str, strlen(str), TimeOut); } else { RetVal = UPNP_E_FILE_READ_ERROR; } goto Cleanup_File; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?