📄 sphttpmsg.cpp
字号:
/* * Copyright 2007 Stephen Liu * For license terms, see the file COPYING along with this library. */#include <stdio.h>#include <string.h>#include <stdlib.h>#include "sphttpmsg.hpp"#include "sputils.hpp"static char * sp_strsep(char **s, const char *del){ char *d, *tok; if (!s || !*s) return NULL; tok = *s; d = strstr(tok, del); if (d) { *s = d + strlen(del); *d = '\0'; } else { *s = NULL; } return tok;}SP_HttpMsgParser :: SP_HttpMsgParser(){ mMessage = NULL; mStatus = eStartLine; mIgnoreContent = 0;}SP_HttpMsgParser :: ~SP_HttpMsgParser(){ if( NULL != mMessage ) delete mMessage;}void SP_HttpMsgParser :: setIgnoreContent( int ignoreContent ){ mIgnoreContent = ignoreContent;}int SP_HttpMsgParser :: isIgnoreContent() const{ return 0 != mIgnoreContent;}int SP_HttpMsgParser :: parseStartLine( SP_HttpMessage ** message, const void * buffer, int len ){ int lineLen = 0; char * pos = (char*)memchr( buffer, '\n', len ); if( NULL != pos ) { lineLen = pos - (char*)buffer + 1; char * line = (char*)malloc( lineLen + 1 ); memcpy( line, buffer, lineLen ); line[ lineLen ] = '\0'; pos = line; char * first, * second; first = sp_strsep( &pos, " " ); second = sp_strsep( &pos, " " ); if( 0 == strncasecmp( line, "HTTP", 4 ) ) { SP_HttpResponse * response = new SP_HttpResponse(); if( NULL != first ) response->setVersion( first ); if( NULL != second ) response->setStatusCode( atoi( second ) ); if( NULL != pos ) response->setReasonPhrase( strtok( pos, "\r\n" ) ); *message = response; } else { SP_HttpRequest * request = new SP_HttpRequest(); if( NULL != first ) request->setMethod( first ); if( NULL != second ) request->setURI( sp_strsep( &second, "?" ) ); if( NULL != pos ) request->setVersion( strtok( pos, "\r\n" ) ); char * params = second; for( ; NULL != params && '\0' != *params; ) { char * value = sp_strsep( ¶ms, "&" ); char * name = sp_strsep( &value, "=" ); request->addParam( name, NULL == value ? "" : value ); } *message = request; } free( line ); } return lineLen;}int SP_HttpMsgParser :: parseHeader( SP_HttpMessage * message, const void * buffer, int len ){ int lineLen = 0; char * pos = (char*)memchr( buffer, '\n', len ); if( NULL != pos ) { lineLen = pos - (char*)buffer + 1; char * line = (char*)malloc( lineLen + 1 ); memcpy( line, buffer, lineLen ); line[ lineLen ] = '\0'; pos = line; char * name = sp_strsep( &pos, ":" ); if( NULL != pos ) { pos = strtok( pos, "\r\n" ); pos += strspn( pos, " " ); message->addHeader( name, pos ); } free( line ); } return lineLen;}int SP_HttpMsgParser :: getLine( const void * buffer, int len, char * line, int size ){ int lineLen = 0; char * pos = (char*)memchr( buffer, '\n', len ); if( NULL != pos ) { lineLen = pos - (char*)buffer + 1; int realLen = size - 1; realLen = realLen > lineLen ? lineLen : realLen; memcpy( line, buffer, realLen ); line[ realLen ] = '\0'; strtok( line, "\r\n" ); } return lineLen;}int SP_HttpMsgParser :: parseChunked( SP_HttpMessage * message, const void * buffer, int len, int * status ){ int parsedLen = 0, hasChunk = 1; for( ; 0 != hasChunk && eCompleted != *status; ) { hasChunk = 0; char chunkSize[ 32 ] = { 0 }; int lineLen = getLine( ((char*)buffer) + parsedLen, len - parsedLen, chunkSize, sizeof( chunkSize ) ); int contentLen = strtol( chunkSize, NULL, 16 ); if( contentLen > 0 && ( len - parsedLen ) > ( contentLen + lineLen ) ) { int emptyLen = getLine( ((char*)buffer) + parsedLen + lineLen + contentLen, len - parsedLen - lineLen - contentLen, chunkSize, sizeof( chunkSize ) ); if( emptyLen > 0 ) { parsedLen += lineLen; message->appendContent( ((char*)buffer) + parsedLen, contentLen ); parsedLen += contentLen + emptyLen; hasChunk = 1; } } if( 0 == contentLen && lineLen > 0 ) { parsedLen += lineLen; *status = eCompleted; } } return parsedLen;}int SP_HttpMsgParser :: parseContent( SP_HttpMessage * message, const void * buffer, int len, int * status ){ int parsedLen = 0; const char * value = message->getHeaderValue( SP_HttpMessage::HEADER_CONTENT_LENGTH ); int contentLen = atoi( NULL == value ? "0" : value ); if( contentLen > 0 && len >= contentLen ) { message->appendContent( ((char*)buffer), contentLen ); parsedLen = contentLen; } if( contentLen == message->getContentLength() ) *status = eCompleted; return parsedLen;}int SP_HttpMsgParser :: append( const void * buffer, int len ){ int parsedLen = 0; if( eCompleted == mStatus ) return parsedLen; // parse start-line if( NULL == mMessage ) { parsedLen = parseStartLine( &mMessage, buffer, len ); if( parsedLen > 0 ) mStatus = eHeader; } if( NULL != mMessage ) { // parse header for( int headerLen = 1; eHeader == mStatus && headerLen > 0 && parsedLen < len; parsedLen += headerLen ) { headerLen = parseHeader( mMessage, ((char*)buffer) + parsedLen, len - parsedLen ); char ch = * ( ((char*)buffer) + parsedLen ); if( '\r' == ch || '\n' == ch ) mStatus = eContent; } if( SP_HttpMessage::eResponse == mMessage->getType() && eContent == mStatus && mIgnoreContent ) mStatus = eCompleted; // parse content if( eContent == mStatus ) { const char * encoding = mMessage->getHeaderValue( SP_HttpMessage::HEADER_TRANSFER_ENCODING ); if( NULL != encoding && 0 == strcasecmp( encoding, "chunked" ) ) { parsedLen += parseChunked( mMessage, ((char*)buffer) + parsedLen, len - parsedLen, &mStatus ); } else { parsedLen += parseContent( mMessage, ((char*)buffer) + parsedLen, len - parsedLen, &mStatus ); } } if( eCompleted == mStatus ) postProcess( mMessage ); } return parsedLen;}void SP_HttpMsgParser :: postProcess( SP_HttpMessage * message ){ if( SP_HttpMessage::eRequest == message->getType() ) { SP_HttpRequest * request = (SP_HttpRequest*)message; const char * contentType = request->getHeaderValue( SP_HttpMessage::HEADER_CONTENT_TYPE ); if( request->getContentLength() > 0 && NULL != contentType && 0 == strcasecmp( contentType, "application/x-www-form-urlencoded" ) ) { char * content = (char*)malloc( request->getContentLength() + 1 ); memcpy( content, request->getContent(), request->getContentLength() ); content[ request->getContentLength() ] = '\0'; char * params = content; for( ; NULL != params && '\0' != *params; ) { char * value = sp_strsep( ¶ms, "&" ); char * name = sp_strsep( &value, "=" ); request->addParam( name, NULL == value ? "" : value ); } free( content ); } }}int SP_HttpMsgParser :: isCompleted() const{ return eCompleted == mStatus;}SP_HttpRequest * SP_HttpMsgParser :: getRequest() const{ if( NULL != mMessage && SP_HttpMessage::eRequest == mMessage->getType() ) { return (SP_HttpRequest*)mMessage; } return NULL;}SP_HttpResponse * SP_HttpMsgParser :: getResponse() const{ if( NULL != mMessage && SP_HttpMessage::eResponse== mMessage->getType() ) { return (SP_HttpResponse*)mMessage; } return NULL;}//---------------------------------------------------------const char * SP_HttpMessage :: HEADER_CONTENT_LENGTH = "Content-Length";const char * SP_HttpMessage :: HEADER_CONTENT_TYPE = "Content-Type";const char * SP_HttpMessage :: HEADER_CONNECTION = "Connection";const char * SP_HttpMessage :: HEADER_PROXY_CONNECTION = "Proxy-Connection";const char * SP_HttpMessage :: HEADER_TRANSFER_ENCODING = "Transfer-Encoding";const char * SP_HttpMessage :: HEADER_DATE = "Date";const char * SP_HttpMessage :: HEADER_SERVER = "Server";SP_HttpMessage :: SP_HttpMessage( int type ) : mType( type ){ mContent = NULL; mContentLength = 0; mMaxLength = 0; mHeaderNameList = new SP_ArrayList(); mHeaderValueList = new SP_ArrayList(); snprintf( mVersion, sizeof( mVersion ), "%s", "HTTP/1.0" );}SP_HttpMessage :: ~SP_HttpMessage(){ for( int i = mHeaderNameList->getCount() - 1; i >= 0; i-- ) { free( mHeaderNameList->takeItem( i ) ); free( mHeaderValueList->takeItem( i ) ); } delete mHeaderNameList; delete mHeaderValueList; if( NULL != mContent ) free( mContent );}int SP_HttpMessage :: getType() const{ return mType;}void SP_HttpMessage :: setVersion( const char * version ){ snprintf( mVersion, sizeof( mVersion ), "%s", version );}const char * SP_HttpMessage :: getVersion() const{ return mVersion;}void SP_HttpMessage :: appendContent( const void * content, int length, int maxLength ){ if( length <= 0 ) length = strlen( (char*)content ); int realLength = mContentLength + length; realLength = realLength > maxLength ? realLength : maxLength; if( realLength > mMaxLength ) { if( NULL == mContent ) { mContent = malloc( realLength + 1 ); } else { mContent = realloc( mContent, realLength + 1 ); } mMaxLength = realLength; } memcpy( ((char*)mContent) + mContentLength, content, length ); mContentLength = mContentLength + length; ((char*)mContent)[ mContentLength ] = '\0';}void SP_HttpMessage :: setContent( const void * content, int length ){ mContentLength = 0; appendContent( content, length );}const void * SP_HttpMessage :: getContent() const{ return mContent;}int SP_HttpMessage :: getContentLength() const{ return mContentLength;}void SP_HttpMessage :: addHeader( const char * name, const char * value ){ mHeaderNameList->append( strdup( name ) ); mHeaderValueList->append( strdup( value ) );}int SP_HttpMessage :: removeHeader( const char * name ){ int ret = 0; for( int i = 0; i < mHeaderNameList->getCount() && 0 == ret; i++ ) { if( 0 == strcasecmp( name, (char*)mHeaderNameList->getItem( i ) ) ) { free( mHeaderNameList->takeItem( i ) ); free( mHeaderValueList->takeItem( i ) ); ret = 1; } } return ret;}int SP_HttpMessage :: getHeaderCount() const{ return mHeaderNameList->getCount();}const char * SP_HttpMessage :: getHeaderName( int index ) const{ return (char*)mHeaderNameList->getItem( index );}const char * SP_HttpMessage :: getHeaderValue( int index ) const{ return (char*)mHeaderValueList->getItem( index );}const char * SP_HttpMessage :: getHeaderValue( const char * name ) const{ const char * value = NULL; for( int i = 0; i < mHeaderNameList->getCount() && NULL == value; i++ ) { if( 0 == strcasecmp( name, (char*)mHeaderNameList->getItem( i ) ) ) { value = (char*)mHeaderValueList->getItem( i ); } } return value;}int SP_HttpMessage :: isKeepAlive() const{ const char * proxy = getHeaderValue( HEADER_PROXY_CONNECTION ); const char * local = getHeaderValue( HEADER_CONNECTION ); if( ( NULL != proxy && 0 == strcasecmp( proxy, "Keep-Alive" ) ) || ( NULL != local && 0 == strcasecmp( local, "Keep-Alive" ) ) ) { return 1; } return 0;}//---------------------------------------------------------SP_HttpRequest :: SP_HttpRequest() : SP_HttpMessage( eRequest ){ memset( mMethod, 0, sizeof( mMethod ) ); memset( mClientIP, 0, sizeof( mClientIP ) ); mURI = NULL; mParamNameList = new SP_ArrayList(); mParamValueList = new SP_ArrayList();}SP_HttpRequest :: ~SP_HttpRequest(){ if( NULL != mURI ) free( mURI ); for( int i = mParamNameList->getCount() - 1; i >= 0; i-- ) { free( mParamNameList->takeItem( i ) ); free( mParamValueList->takeItem( i ) ); } delete mParamNameList; delete mParamValueList;}void SP_HttpRequest :: setMethod( const char * method ){ snprintf( mMethod, sizeof( mMethod ), "%s", method );}const char * SP_HttpRequest :: getMethod() const{ return mMethod;}void SP_HttpRequest :: setURI( const char * uri ){ char * temp = mURI; mURI = strdup( uri ); if( NULL != temp ) free( mURI );}const char * SP_HttpRequest :: getURI() const{ return mURI;}void SP_HttpRequest :: setClinetIP( const char * clientIP ){ snprintf( mClientIP, sizeof( mClientIP ), "%s", clientIP );}const char * SP_HttpRequest :: getClientIP() const{ return mClientIP;}void SP_HttpRequest :: addParam( const char * name, const char * value ){ mParamNameList->append( strdup( name ) ); mParamValueList->append( strdup( value ) );}int SP_HttpRequest :: removeParam( const char * name ){ int ret = 0; for( int i = 0; i < mParamNameList->getCount() && 0 == ret; i++ ) { if( 0 == strcasecmp( name, (char*)mParamNameList->getItem( i ) ) ) { free( mParamNameList->takeItem( i ) ); free( mParamValueList->takeItem( i ) ); ret = 1; } } return ret;}int SP_HttpRequest :: getParamCount() const{ return mParamNameList->getCount();}const char * SP_HttpRequest :: getParamName( int index ) const{ return (char*)mParamNameList->getItem( index );}const char * SP_HttpRequest :: getParamValue( int index ) const{ return (char*)mParamValueList->getItem( index );}const char * SP_HttpRequest :: getParamValue( const char * name ) const{ const char * value = NULL; for( int i = 0; i < mParamNameList->getCount() && NULL == value; i++ ) { if( 0 == strcasecmp( name, (char*)mParamNameList->getItem( i ) ) ) { value = (char*)mParamValueList->getItem( i ); } } return value;}//---------------------------------------------------------SP_HttpResponse :: SP_HttpResponse() : SP_HttpMessage( eResponse ){ mStatusCode = 200; snprintf( mReasonPhrase, sizeof( mReasonPhrase ), "%s", "OK" );}SP_HttpResponse :: ~SP_HttpResponse(){}void SP_HttpResponse :: setStatusCode( int statusCode ){ mStatusCode = statusCode;}int SP_HttpResponse :: getStatusCode() const{ return mStatusCode;}void SP_HttpResponse :: setReasonPhrase( const char * reasonPhrase ){ snprintf( mReasonPhrase, sizeof( mReasonPhrase ), "%s", reasonPhrase );}const char * SP_HttpResponse :: getReasonPhrase() const{ return mReasonPhrase;}//---------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -