summaryrefslogtreecommitdiff
path: root/gcsdk/http.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gcsdk/http.cpp')
-rw-r--r--gcsdk/http.cpp710
1 files changed, 710 insertions, 0 deletions
diff --git a/gcsdk/http.cpp b/gcsdk/http.cpp
new file mode 100644
index 0000000..29f4e67
--- /dev/null
+++ b/gcsdk/http.cpp
@@ -0,0 +1,710 @@
+//====== Copyright � 1996-2010, Valve Corporation, All rights reserved. =======
+//
+// Purpose: HTTP related enums and objects, stuff that both clients and server use should go here
+//
+//=============================================================================
+
+#include "stdafx.h"
+#include <time.h>
+
+#include "msgprotobuf.h"
+#include "rtime.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace GCSDK;
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if the given status code is one that by spec allows a body, or is
+// one that "MUST NOT" include an entity body
+//-----------------------------------------------------------------------------
+bool CHTTPUtil::BStatusCodeAllowsBody( EHTTPStatusCode eHTTPStatus )
+{
+ switch( eHTTPStatus )
+ {
+ case k_EHTTPStatusCode100Continue:
+ case k_EHTTPStatusCode101SwitchingProtocols:
+ case k_EHTTPStatusCode204NoContent:
+ case k_EHTTPStatusCode205ResetContent:
+ case k_EHTTPStatusCode304NotModified:
+ return false;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Wrapper to ease use of Steam Web APIs
+//-----------------------------------------------------------------------------
+CSteamAPIRequest::CSteamAPIRequest( EHTTPMethod eMethod, const char *pchInterface, const char *pchMethod, int nVersion ) :
+ CHTTPRequest( eMethod, "api.steampowered.com", CFmtStr( "/%s/%s/v%04d/", pchInterface, pchMethod, nVersion ) )
+{
+ if ( k_EHTTPMethodPOST == eMethod )
+ {
+ SetPOSTParamString( "format", "vdf" );
+ SetPOSTParamString( "key", GGCBase()->GetSteamAPIKey() );
+ }
+ else
+ {
+ SetGETParamString( "format", "vdf" );
+ SetGETParamString( "key", GGCBase()->GetSteamAPIKey() );
+ }
+
+ EUniverse universe = GGCHost()->GetUniverse();
+ if ( universe == k_EUniverseBeta )
+ {
+ SetHostname( "api-beta.steampowered.com" );
+ }
+ else if ( universe == k_EUniverseDev )
+ {
+ // Set this to your dev universe API endpoint if not local
+ SetHostname( "localhost:8282" );
+ }
+}
+
+CHTTPRequest::CHTTPRequest( CMsgHttpRequest* pProto )
+{
+ Init( pProto );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Construct a request object, it's invalid until data is setup
+//-----------------------------------------------------------------------------
+CHTTPRequest::CHTTPRequest()
+{
+ Init( NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Common init code
+//-----------------------------------------------------------------------------
+void CHTTPRequest::Init( CMsgHttpRequest* pProto )
+{
+ //see if we are wrapping a proto that already exists
+ if( pProto )
+ {
+ m_pProto = pProto;
+ m_bOwnProto = false;
+ }
+ else
+ {
+ m_pProto = new CMsgHttpRequest;
+ m_bOwnProto = true;
+
+ SetEHTTPMethod( k_EHTTPMethodInvalid );
+ // Default URL
+ SetURL( "/" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHTTPRequest::CHTTPRequest( EHTTPMethod eMethod, const char *pchHost, const char *pchRelativeURL )
+{
+ Init( NULL );
+
+ SetEHTTPMethod( eMethod );
+ SetHostname( pchHost );
+ SetURL( pchRelativeURL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHTTPRequest::CHTTPRequest( EHTTPMethod eMethod, const char *pchAbsoluteURL )
+{
+ Init( NULL );
+
+ SetEHTTPMethod( eMethod );
+
+ // We need to break the URL down into host + relativeURL
+ const char *pchHost = Q_strstr( pchAbsoluteURL, "://" );
+ if ( pchHost )
+ {
+ // Skip past protocol
+ pchHost += 3;
+
+ // Find the next /, that is the beginning of the actual URL
+ const char *pchURL = Q_strstr( pchHost, "/");
+ if ( !pchURL )
+ {
+ // No URL specified after host? just default to / then.
+ SetURL( "/" );
+ }
+ else
+ {
+ // Ok, now we must remove the query string
+ const char *pchQueryString = Q_strstr( pchURL, "?" );
+ if ( !pchQueryString )
+ {
+ // No query string, full thing is the URL
+ SetURL( pchURL );
+ }
+ else
+ {
+ // URL is everything before query string
+ SetURLDirect( pchURL, pchQueryString - pchURL );
+
+ Assert( *pchQueryString == '?' );
+ pchQueryString++;
+ if( *pchQueryString )
+ {
+ m_pProto->mutable_get_params()->Clear();
+ CUtlVector<CMsgHttpRequest_QueryParam> vecParams;
+ RetrieveURLEncodedData( pchQueryString, Q_strlen( pchQueryString ), vecParams );
+ FOR_EACH_VEC( vecParams, i )
+ {
+ *m_pProto->add_get_params() = vecParams[i];
+ }
+ }
+ }
+ }
+
+ // Is there a userinfo separator in the hostname portion? We don't support
+ // username/password authentication in the URL, but we must still skip it.
+ const char *pchUserinfoSep = strchr( pchHost, '@' );
+ if ( pchUserinfoSep && ( !pchURL || pchUserinfoSep < pchURL ) )
+ {
+ pchHost = pchUserinfoSep + 1;
+ }
+
+ // If we found a URL only set upto that, otherwise set everything as host
+ if ( pchURL )
+ SetHostnameDirect( pchHost, pchURL-pchHost );
+ else
+ SetHostname( pchHost );
+ }
+ else
+ {
+ AssertMsg( false, "Bad absolute URL to CHTTPRequest constructor, must start with protocol://" );
+ EmitError( SPEW_GC, "Bad absolute URL to CHTTPRequest constructor, must start with protocol://" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CHTTPRequest::~CHTTPRequest()
+{
+ if( m_bOwnProto )
+ delete m_pProto;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+const CMsgHttpRequest_QueryParam *CHTTPRequest::GetGETParam( const char *pchGetParamName, bool bMatchCase ) const
+{
+ const uint32 nNumParams = m_pProto->get_params_size();
+ for( uint32 nParam = 0; nParam < nNumParams; nParam++ )
+ {
+ const CMsgHttpRequest_QueryParam& param = m_pProto->get_params( nParam );
+ if ( bMatchCase )
+ {
+ if ( Q_strcmp( param.name().c_str(), pchGetParamName ) == 0 )
+ return &param;
+ }
+ else
+ {
+ if ( Q_stricmp( param.name().c_str(), pchGetParamName ) == 0 )
+ return &param;
+ }
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+const char *CHTTPRequest::GetGETParamString( const char *pchGetParamName, const char *pchDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return pchDefault;
+
+ return pParam->value().c_str();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+bool CHTTPRequest::GetGETParamBool( const char *pchGetParamName, bool bDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return bDefault;
+
+ return ( Q_atoi( pParam->value().c_str() ) != 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+int32 CHTTPRequest::GetGETParamInt32( const char *pchGetParamName, int32 nDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return nDefault;
+
+ return Q_atoi( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+uint32 CHTTPRequest::GetGETParamUInt32( const char *pchGetParamName, uint32 unDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return unDefault;
+
+ return (uint32)V_atoui64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+int64 CHTTPRequest::GetGETParamInt64( const char *pchGetParamName, int64 nDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return nDefault;
+
+ return V_atoi64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+uint64 CHTTPRequest::GetGETParamUInt64( const char *pchGetParamName, uint64 unDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return unDefault;
+
+ return V_atoui64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a GET parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+float CHTTPRequest::GetGETParamFloat( const char *pchGetParamName, float fDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetGETParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return fDefault;
+
+ return Q_atof( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+const CMsgHttpRequest_QueryParam *CHTTPRequest::GetPOSTParam( const char *pchPostParamName, bool bMatchCase ) const
+{
+ const uint32 nNumParams = m_pProto->post_params_size();
+ for( uint32 nParam = 0; nParam < nNumParams; nParam++ )
+ {
+ const CMsgHttpRequest_QueryParam& param = m_pProto->post_params( nParam );
+ if ( bMatchCase )
+ {
+ if ( Q_strcmp( param.name().c_str(), pchPostParamName ) == 0 )
+ return &param;
+ }
+ else
+ {
+ if ( Q_stricmp( param.name().c_str(), pchPostParamName ) == 0 )
+ return &param;
+ }
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+const char *CHTTPRequest::GetPOSTParamString( const char *pchGetParamName, const char *pchDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return pchDefault;
+
+ return pParam->value().c_str();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+bool CHTTPRequest::GetPOSTParamBool( const char *pchGetParamName, bool bDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return bDefault;
+
+ return ( Q_atoi( pParam->value().c_str() ) != 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+int32 CHTTPRequest::GetPOSTParamInt32( const char *pchGetParamName, int32 nDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return nDefault;
+
+ return Q_atoi( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+uint32 CHTTPRequest::GetPOSTParamUInt32( const char *pchGetParamName, uint32 unDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return unDefault;
+
+ return (uint32)V_atoui64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+int64 CHTTPRequest::GetPOSTParamInt64( const char *pchGetParamName, int64 nDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return nDefault;
+
+ return V_atoi64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+uint64 CHTTPRequest::GetPOSTParamUInt64( const char *pchGetParamName, uint64 unDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return unDefault;
+
+ return V_atoui64( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the value of a POST parameter, this is case-insensitive by default.
+//-----------------------------------------------------------------------------
+float CHTTPRequest::GetPOSTParamFloat( const char *pchGetParamName, float fDefault, bool bMatchCase ) const
+{
+ const CMsgHttpRequest_QueryParam *pParam = GetPOSTParam( pchGetParamName, bMatchCase );
+ if ( !pParam )
+ return fDefault;
+
+ return Q_atof( pParam->value().c_str() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a GET param to the request
+//-----------------------------------------------------------------------------
+void CHTTPRequest::SetGETParamRaw( const char *pchGetParamName, uint8 *pData, uint32 cubDataLen )
+{
+ // See if it already exists, and overwrite then (case sensitive!)
+ CMsgHttpRequest_QueryParam *pParam = const_cast< CMsgHttpRequest_QueryParam* >( GetGETParam( pchGetParamName, true ) );
+ if ( !pParam )
+ {
+ // Add a new one then
+ pParam = m_pProto->add_get_params();
+ pParam->set_name( pchGetParamName );
+ }
+
+ pParam->set_value( pData, cubDataLen );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a POST param to the request given a string for the name and value
+//-----------------------------------------------------------------------------
+void CHTTPRequest::SetPOSTParamRaw( const char *pchPostParamName, uint8 *pData, uint32 cubDataLen )
+{
+ // See if it already exists, and overwrite then (case sensitive!)
+ CMsgHttpRequest_QueryParam *pParam = const_cast< CMsgHttpRequest_QueryParam* >( GetPOSTParam( pchPostParamName, true ) );
+ if ( !pParam )
+ {
+ // Add a new one then
+ pParam = m_pProto->add_post_params();
+ pParam->set_name( pchPostParamName );
+ }
+
+ pParam->set_value( pData, cubDataLen );
+}
+
+
+//-----------------------------------------------------------------------------
+// Fetch a request headers value by header name
+//-----------------------------------------------------------------------------
+const char * CHTTPRequest::GetRequestHeaderValue( const char *pchRequestHeaderName, const char *pchDefault ) const
+{
+ const uint32 nNumHeaders = m_pProto->headers_size();
+ for( uint32 nHeader = 0; nHeader < nNumHeaders; nHeader++ )
+ {
+ const CMsgHttpRequest_RequestHeader& header = m_pProto->headers( nHeader );
+ if( Q_stricmp( header.name().c_str(), pchRequestHeaderName ) == 0 )
+ {
+ return header.value().c_str();
+ }
+ }
+
+ return pchDefault;
+}
+
+//-----------------------------------------------------------------------------
+// Set a header field for the request
+//-----------------------------------------------------------------------------
+void CHTTPRequest::SetRequestHeaderValue( const char *pchHeaderName, const char *pchHeaderString )
+{
+ const uint32 nNumHeaders = m_pProto->headers_size();
+ for( uint32 nHeader = 0; nHeader < nNumHeaders; nHeader++ )
+ {
+ CMsgHttpRequest_RequestHeader* pHeader = m_pProto->mutable_headers( nHeader );
+ if( Q_stricmp( pHeader->name().c_str(), pchHeaderName ) == 0 )
+ {
+ pHeader->set_value( pchHeaderString );
+ return;
+ }
+ }
+
+ CMsgHttpRequest_RequestHeader* pHeader = m_pProto->add_headers();
+ pHeader->set_name( pchHeaderName );
+ pHeader->set_value( pchHeaderString );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fetch a request header by header name and convert it to a time value
+// This is just a helpful wrapper of GetRequestHeaderValue that deals with
+// parsing the time value
+//-----------------------------------------------------------------------------
+RTime32 CHTTPRequest::GetRequestHeaderTimeValue( const char *pchRequestHeaderName, RTime32 rtDefault ) const
+{
+ const char *pchValue = GetRequestHeaderValue( pchRequestHeaderName );
+ if( !pchValue )
+ return rtDefault;
+
+ return CRTime::RTime32FromHTTPDateString( pchValue );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the body data for the request
+//-----------------------------------------------------------------------------
+void CHTTPRequest::SetBodyData( const void *pubData, uint32 cubData )
+{
+ m_pProto->set_body( pubData, cubData );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get data out of a query string
+//-----------------------------------------------------------------------------
+void CHTTPRequest::RetrieveURLEncodedData( const char *pchQueryString, int nQueryStrLen, CUtlVector<CMsgHttpRequest_QueryParam> &vecParams )
+{
+ CUtlBuffer bufParamName( 0, 64 );
+ CUtlBuffer bufParamValue( 0, 128 );
+
+ // We shouldn't get passed the ? from a query string, but if we do just skip it and parse ok anyway
+ if ( nQueryStrLen && pchQueryString[0] == '?' )
+ {
+ ++pchQueryString;
+ --nQueryStrLen;
+ }
+
+ bool bInParamValue = false;
+ int iTokenStart = 0;
+ for( int i=0; i < nQueryStrLen; ++i )
+ {
+ if ( pchQueryString[i] == '=' && !bInParamValue )
+ {
+ // = switches to value from name, starts a new value token
+ bufParamName.Put( &pchQueryString[iTokenStart], i - iTokenStart );
+ bInParamValue = true;
+ iTokenStart = i + 1;
+ }
+ else if ( pchQueryString[i] == '&' )
+ {
+ // & terminates a value and starts a new name token
+ if ( bInParamValue )
+ {
+ bufParamValue.Put( &pchQueryString[iTokenStart], i - iTokenStart );
+
+ int iIndex = vecParams.AddToTail();
+ CMsgHttpRequest_QueryParam *pParam = &vecParams[iIndex];
+
+ uint32 unNameLen = Q_URLDecode( (char*)bufParamName.Base(), bufParamName.TellPut(), (const char*)bufParamName.Base(), bufParamName.TellPut() );
+ pParam->set_name( (const char*)bufParamName.Base(), unNameLen );
+
+ uint32 unDataLen = (uint32)Q_URLDecode( (char*)bufParamValue.Base(), bufParamValue.TellPut(), (const char*)bufParamValue.Base(), bufParamValue.TellPut() );
+ pParam->set_value( (const uint8*)bufParamValue.Base(), unDataLen );
+ }
+ bufParamName.Clear();
+ bufParamValue.Clear();
+ bInParamValue = false;
+ iTokenStart = i+1;
+ }
+ }
+
+ // Use any left over value from the end of the query string
+ if ( bInParamValue )
+ {
+ bufParamValue.Put( &pchQueryString[iTokenStart], nQueryStrLen - iTokenStart );
+
+ int iIndex = vecParams.AddToTail();
+ CMsgHttpRequest_QueryParam *pParam = &vecParams[iIndex];
+
+ uint32 unNameLen = Q_URLDecode( (char*)bufParamName.Base(), bufParamName.TellPut(), (const char*)bufParamName.Base(), bufParamName.TellPut() );
+ pParam->set_name( (const char*)bufParamName.Base(), unNameLen );
+
+ uint32 unDataLen = (uint32)Q_URLDecode( (char*)bufParamValue.Base(), bufParamValue.TellPut(), (const char*)bufParamValue.Base(), bufParamValue.TellPut() );
+ pParam->set_value( (const uint8*)bufParamValue.Base(), unDataLen );
+ }
+}
+
+
+//----------------------------------------------------------------------------
+// Purpose: Gets a singleton buffer pool for HTTP responses
+//----------------------------------------------------------------------------
+static GCConVar http_response_max_pool_size_mb( "http_response_max_pool_size_mb", "10", "Maximum size in bytes of the HTTP Response buffer pool" );
+static GCConVar http_response_init_buffer_size( "http_response_init_buffer_size", "65536", "Initial buffer size for buffers in the HTTP Response buffer pool" );
+/*static*/ CBufferPool &CHTTPResponse::GetBufferPool()
+{
+ static CBufferPool s_bufferPool( "HTTP Response", http_response_max_pool_size_mb, http_response_init_buffer_size, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::CONTAINS_CRLF );
+ return s_bufferPool;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Construct a response object, it defaults to being a 500 internal server error response
+//-----------------------------------------------------------------------------
+CHTTPResponse::CHTTPResponse() :
+m_pbufBody( GetBufferPool().GetBuffer() ),
+m_eStatusCode( k_EHTTPStatusCode500InternalServerError )
+{
+ m_pkvResponseHeaders = new KeyValues( "ResponseHeaders" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CHTTPResponse::~CHTTPResponse()
+{
+ GetBufferPool().ReturnBuffer( m_pbufBody );
+ m_pbufBody = NULL;
+
+ if ( m_pkvResponseHeaders )
+ m_pkvResponseHeaders->deleteThis();
+
+ m_pkvResponseHeaders = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the "expiration" response header to a given number of seconds
+// ahead or behind the current time. You can set the Expires header directly as well,
+// this is just a helper so you don't have to deal with time formatting.
+//-----------------------------------------------------------------------------
+void CHTTPResponse::SetExpirationHeaderDeltaFromNow( int32 nSecondsFromNow )
+{
+ time_t rawtime;
+ time( &rawtime );
+ rawtime += nSecondsFromNow;
+ SetHeaderTimeValue( "expires", rawtime );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Formats a time value and sets it as a header. This is a helper so
+// you don't have to deal with time formatting
+//-----------------------------------------------------------------------------
+void CHTTPResponse::SetHeaderTimeValue( const char *pchHeaderName, RTime32 rtTimestamp )
+{
+ char rgchDate[128];
+ struct tm tmStruct;
+ time_t rawtime = rtTimestamp;
+ Plat_gmtime( &rawtime, &tmStruct );
+ DbgVerify( strftime( rgchDate, 128, "%a, %d %b %Y %H:%M:%S GMT", &tmStruct ) );
+ SetResponseHeaderValue( pchHeaderName, rgchDate );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Serializes the response into a message object (for proxying between
+// back-end Steam servers).
+//-----------------------------------------------------------------------------
+void CHTTPResponse::SerializeIntoProtoBuf( CMsgHttpResponse & response ) const
+{
+ MEM_ALLOC_CREDIT();
+ response.set_status_code( m_eStatusCode );
+
+ FOR_EACH_VALUE( m_pkvResponseHeaders, pkvRequestHeader )
+ {
+ const char *pchName = pkvRequestHeader->GetName();
+ const char *pchValue = pkvRequestHeader->GetString();
+
+ if ( pchName && pchValue )
+ {
+ CMsgHttpResponse_ResponseHeader *pHeader = response.add_headers();
+ pHeader->set_name( pchName );
+ pHeader->set_value( pchValue );
+ }
+ }
+
+ if( m_pbufBody->TellPut() > 0 )
+ response.set_body( m_pbufBody->Base(), m_pbufBody->TellPut() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deserializes the response from a message object (for proxying between
+// back-end Steam servers).
+//-----------------------------------------------------------------------------
+void CHTTPResponse::DeserializeFromProtoBuf( const CMsgHttpResponse & response )
+{
+ m_eStatusCode = (EHTTPStatusCode)response.status_code();
+
+ for( int i=0; i<response.headers_size(); i++ )
+ {
+ m_pkvResponseHeaders->SetString( response.headers(i).name().c_str(), response.headers(i).value().c_str() );
+ }
+
+ if( response.has_body() )
+ m_pbufBody->Put( response.body().data(), response.body().size() );
+}
+