📄 parseutil.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Copyright (c) 2000 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 the 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./////////////////////////////////////////////////////////////////////////////// $Revision: 1.1.1.1 $// $Date: 2004/10/19 11:54:08 $#include "../../inc/tools/config.h"#ifdef INTERNAL_WEB_SERVER#if EXCLUDE_WEB_SERVER == 0#include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <genlib/net/netexception.h>#include <genlib/net/http/tokenizer.h>#include <genlib/net/http/parseutil.h>#include <genlib/net/http/statuscodes.h>#include <genlib/util/utilall.h>#include <genlib/util/util.h>#include <genlib/util/gmtdate.h>#include <genlib/file/fileexceptions.h>#include <genlib/util/memreader.h>// HttpParseExceptionHttpParseException::HttpParseException( const char* s, int lineNumber ) : BasicException(""){ if ( lineNumber != -1 ) { char buf[100]; sprintf( buf, "line %d: ", lineNumber ); appendMessage( buf ); } appendMessage( s );}//////// callback used to read a HttpHeader value from a scannertypedef HttpHeaderValue* (*ReadHttpValueCallback) ( Tokenizer& scanner ); typedef void (*AddValueToListCallback) ( HttpHeaderValueList& list, HttpHeaderValue* value );// module vars ////////////////////// static -- to do: determine os/version on the flystatic const char* gServerDesc = "Linux/6.0 UPnP/1.0 Intel UPnP/0.9";static const char* gUserAgentDesc = "Intel UPnP/0.9";/////////////////////////////////// // ******** CREATE callback functions ****static HttpHeaderValue* CreateIdentifierValue(){ return new IdentifierValue;}static HttpHeaderValue* CreateIdentifierQValue(){ return new IdentifierQValue;}static HttpHeaderValue* CreateMediaRange(){ return new MediaRange;}static HttpHeaderValue* CreateLanguageTag(){ return new LanguageTag;}static HttpHeaderValue* CreateCacheDirective(){ return new CacheDirective;}// *********** endstruct SortedTableEntry{ char* name; int id;};#define NUM_HEADERS 52// table _must_ be sorted by header namestatic SortedTableEntry HeaderNameTable[NUM_HEADERS] ={ { "ACCEPT", HDR_ACCEPT }, { "ACCEPT-CHARSET", HDR_ACCEPT_CHARSET }, { "ACCEPT-ENCODING", HDR_ACCEPT_ENCODING }, { "ACCEPT-LANGUAGE", HDR_ACCEPT_LANGUAGE }, { "ACCEPT-RANGES", HDR_ACCEPT_RANGES }, { "AGE", HDR_AGE }, { "ALLOW", HDR_ALLOW }, { "AUTHORIZATION", HDR_AUTHORIZATION }, { "CACHE-CONTROL", HDR_CACHE_CONTROL }, { "CALLBACK", HDR_UPNP_CALLBACK }, { "CONNECTION", HDR_CONNECTION }, { "CONTENT-ENCODING", HDR_CONTENT_ENCODING }, { "CONTENT-LANGUAGE", HDR_CONTENT_LANGUAGE }, { "CONTENT-LENGTH", HDR_CONTENT_LENGTH }, { "CONTENT-LOCATION", HDR_CONTENT_LOCATION }, { "CONTENT-MD5", HDR_CONTENT_MD5 }, { "CONTENT-TYPE", HDR_CONTENT_TYPE }, { "DATE", HDR_DATE }, { "ETAG", HDR_ETAG }, { "EXPECT", HDR_EXPECT }, { "EXPIRES", HDR_EXPIRES }, { "FROM", HDR_FROM }, { "HOST", HDR_HOST }, { "IF-MATCH", HDR_IF_MATCH }, { "IF-MODIFIED-SINCE", HDR_IF_MODIFIED_SINCE }, { "IF-NONE-MATCH", HDR_IF_NONE_MATCH }, { "IF-RANGE", HDR_IF_RANGE }, { "IF-UNMODIFIED-SINCE",HDR_IF_UNMODIFIED_SINCE }, { "LAST-MODIFIED", HDR_LAST_MODIFIED }, { "LOCATION", HDR_LOCATION }, { "MAN", HDR_UPNP_MAN }, { "MAX-FORWARDS", HDR_MAX_FORWARDS }, { "NT", HDR_UPNP_NT }, { "NTS", HDR_UPNP_NTS }, { "PRAGMA", HDR_PRAGMA }, { "PROXY-AUTHENTICATE", HDR_PROXY_AUTHENTICATE }, { "PROXY-AUTHORIZATION",HDR_PROXY_AUTHORIZATION }, { "RANGE", HDR_RANGE }, { "REFERER", HDR_REFERER }, { "SERVER", HDR_SERVER }, { "SID", HDR_UPNP_SID }, { "SOAPACTION", HDR_UPNP_SOAPACTION }, { "ST", HDR_UPNP_ST }, { "TE", HDR_TE }, { "TRAILER", HDR_TRAILER }, { "TRANSFER-ENCODING", HDR_TRANSFER_ENCODING }, { "USER-AGENT", HDR_USER_AGENT }, { "USN", HDR_UPNP_USN }, { "VARY", HDR_VARY }, { "VIA", HDR_VIA }, { "WARNING", HDR_WARNING }, { "WWW-AUTHENTICATE", HDR_WWW_AUTHENTICATE },};// returns header ID; or -1 on errorint NameToID( const char* name, SortedTableEntry* table, int size, bool caseSensitive = true ){ int top, mid, bot; int cmp; top = 0; bot = size - 1; while ( top <= bot ) { mid = (top + bot) / 2; if ( caseSensitive ) { cmp = strcmp( name, table[mid].name ); } else { cmp = strcasecmp( name, table[mid].name ); } if ( cmp > 0 ) { top = mid + 1; // look below mid } else if ( cmp < 0 ) { bot = mid - 1; // look above mid } else // cmp == 0 { return table[mid].id; // match } } return -1; // header name not found}// returns textual representation of id in table;// NULL if id is invalid or missing from tableconst char* IDToName( int id, SortedTableEntry* table, int size ){ if ( id < 0 ) return NULL; for ( int i = 0; i < size; i++ ) { if ( id == table[i].id ) { return table[i].name; } } return NULL;}// skips all blank lines (lines with crlf + optional whitespace);// removes leading whitespace from first non-blank linestatic void SkipBlankLines( IN Tokenizer& scanner ){ Token *token; while ( true ) { token = scanner.getToken(); if ( !(token->tokType == Token::CRLF || token->tokType == Token::WHITESPACE) ) { // not whitespace or crlf; restore and done scanner.pushBack(); return; } }}// reads and discards LWS// returns true if matched; false if not matched LWSbool SkipLWS( IN Tokenizer& scanner ){ Token* token; bool crlfMatch = true; // skip optional CRLF token = scanner.getToken(); if ( token->tokType != Token::CRLF ) { // not CRLF scanner.pushBack(); crlfMatch = false; } // match whitespace token = scanner.getToken(); if ( token->tokType != Token::WHITESPACE ) { // no match scanner.pushBack(); // put back crlf as well, if read if ( crlfMatch ) scanner.pushBack(); return false; // input does not match LWS } return true; // match}// skips *LWSvoid SkipOptionalLWS( IN Tokenizer& scanner ){ // skip LWS until no match while ( SkipLWS(scanner) ) { }}static void SkipOptionalWhitespace( IN Tokenizer& scanner ){ Token* token; token = scanner.getToken(); if ( token->tokType != Token::WHITESPACE ) { scanner.pushBack(); }}// reads and discards a header from input streamstatic void SkipHeader( IN Tokenizer& scanner ){ Token* token; // skip all lines that are continuation of the header while ( true ) { // skip until eol do { token = scanner.getToken(); // handle incomplete or bad input if ( token->tokType == Token::END_OF_STREAM ) { scanner.pushBack(); return; } } while ( token->tokType != Token::CRLF ); // header continues or ends? token = scanner.getToken(); if ( token->tokType != Token::WHITESPACE ) { // possibly, new header starts here scanner.pushBack(); break; } }}/*// returns a string that matches the pattern//// pattern should not have Token::END_OF_STREAM,// last pattern should be null, (0) and// patternSize excludes this nullstatic int MatchPattern( IN Tokenizer& scanner, IN char* pattern, IN int patternSize, OUT xstring& match ){ assert( pattern != NULL ); assert( patternSize > 0 ); match = ""; scanner.getToken(); for ( i = 0; i < patternSize; i++ ) { token = scanner.getToken(); if ( token.tokType != pattern[i] ) { return -1; } match += token->s; } return 0;}*/// reads header name from input// call when scanning start of line// header ::= headername : value//// throws ParseFailException if header identifier not foundstatic void ParseHeaderName( IN Tokenizer& scanner, OUT xstring& hdrName ){ Token *token; token = scanner.getToken(); if ( token->tokType != Token::IDENTIFIER ) { scanner.pushBack(); // put token back in stream // not an identifier throw HttpParseException( "ParseHeaderName()", scanner.getLineNum() ); } hdrName = token->s;}// skips the ':' after header name and the all whitespace// surrounding it// precond: cursor pointing after headerNamestatic void SkipColonLWS( IN Tokenizer& scanner ){ Token *token; SkipOptionalLWS( scanner ); token = scanner.getToken(); if ( token->s != ':' ) { scanner.pushBack(); throw HttpParseException( "SkipColonLWS(): expecting colon", scanner.getLineNum() ); } SkipOptionalLWS( scanner ); }// header ::= name : value// returns value of a header// called when currToken is pointing to a non-whitespace token// after colon// NOTE: value can be blank; "" (len = 0)static void ParseHeaderValue( IN Tokenizer& scanner, OUT xstring& value ){ Token* token; value = ""; //SkipOptionalLWS( scanner ); // no leading whitespace // precond: next token is not whitespace while ( true ) { // add all str till eol or end of stream while ( true ) { token = scanner.getToken(); if ( token->tokType == Token::END_OF_STREAM ) { scanner.pushBack(); throw HttpParseException( "ParseHeaderValue(): unexpected end" ); } if ( token->tokType == Token::CRLF ) { break; // end of value? } value += token->s; } token = scanner.getToken(); // header continued on new line? if ( token->tokType != Token::WHITESPACE ) { // no; header done scanner.pushBack(); scanner.pushBack(); // return CRLF too break; } else { // header value continued value += ' '; } } // precond: // value is either empty "", or has one at least one // non-whitespace char; also, no whitespace on left if ( value.length() > 0 ) { const char *start_ptr, *eptr; int sublen; start_ptr = value.c_str(); eptr = start_ptr + value.length() - 1; // start at last char while ( *eptr == ' ' || *eptr == '\t' ) { eptr--; } sublen = eptr - start_ptr + 1; if ( value.length() != sublen ) { // trim right whitespace value.deleteSubstring( eptr - start_ptr + 1, value.length() - sublen ); } } else { value = ""; }}#ifdef no_such_deff// ************************************************// no special parsing performed for value// throws:// ParseNoMatchException: if error reading header name// ParseNoMatchException(PARSERR_COLON_NOT_FOUND) :// if colon following parse is not found// & scanner points non-colon tokenstatic void ParseSimpleHeader( IN Tokenizer& scanner, OUT xstring& name, OUT xstring& value ){ // get header name ParseHeaderValue( scanner, name ); // skip colon SkipOptionalLWS( scanner ); Token *token = scanner.getToken(); if ( token->s != ":" ) { scanner.pushBack(); HttpParseException e( "ParseSimpleHeader()", scanner.getLineNum() ); e.setErrorCode( PARSERR_COLON_NOT_FOUND ); throw e; } SkipOptionalLWS( scanner ); // get header value ParseHeaderValue( scanner, name );}// Reads a request line// throws ParseNoMatchException : code PARSERR_BAD_REQUEST_LINE// if request line is unacceptablestatic void ParseRequestLine( IN Tokenizer& scanner, OUT xstring& method, OUT xstring& uri, OUT xstring& httpVers ){ Token* token; ParseNoMatchException e( "ParseSimpleHeader()" ); e.setErrorCode( PARSERR_BAD_REQUEST_LINE ); // get method token = scanner.getToken(); if ( token->tokType != Token::IDENTIFIER ) { scanner.pushBack(); throw e; } method = token->s; // skip spaces token = scanner.getToken(); if ( token->tokType != Token::WHITESPACE ) { scanner.pushBack(); throw e; } // get uri int count = 0; uri = ""; while ( true )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -