/* $Revision: 18 $ $Date: 18/08/06 17:57 $ Copyright © 2003-2007, FSL Technologies Limited. Contact "http://fost.3.felspar.com/". */ #include "stdafx.h" #include "FOST.com.hpp" #include "FOST.db.hpp" #include "FOST.internet.hpp" using namespace FSLib; namespace { const FSLib::Revision c_revision( L"$Archive: /FOST.3/F3Util/aspPage.cpp $", __DATE__, L"$Revision: 18 $", L"$Date: 18/08/06 17:57 $" ); } /* FSLib::InputCookie */ namespace { utf8 decode( utf32 ch ) { if ( ch >= '0' && ch <= '9' ) return utf8( ch - '0' ); if ( ch >= 'A' && ch <= 'F' ) return utf8( ch - 'A' + 10 ); if ( ch >= 'a' && ch <= 'f' ) return utf8( ch - 'a' + 10 ); throw FSLib::Exceptions::OutOfRange< utf32 >( L"Non hex digit found where one was expected in cookie value", 0, 16, ch ); } wstring decode( wstring str ) { string dec; for ( wstring::const_iterator it( str.begin() ); it != str.end(); ++it ) { if ( *it > 0xff ) throw FSLib::Exceptions::OutOfRange< utf32 >( L"Expecting only a UTF-8 string for cookie decoding", 0, 0xff, *it ); else if ( *it == '+' ) dec += ' '; else if ( *it == '%' ) { if ( ++it == str.end() ) throw FSLib::Exceptions::UnexpectedEOF( L"Cookie string terminates immediately after a '%'" ); utf8 ch = decode( *it ) << 4; if ( ++it == str.end() ) throw FSLib::Exceptions::UnexpectedEOF( L"Cookie string terminates after first hex digit after a '%'" ); dec += ch + decode( *it ); } else dec += utf8( *it ); } return widen( dec ); } } FSLib::InputCookie::InputCookie( const Input &server ) { parse( variant_cast< Nullable< wstring > >( server.safe( L"HTTP_COOKIE" ) ) ); } void FSLib::InputCookie::parse( const Nullable< wstring > &cookies ) { if ( cookies.isnull() ) return; for ( std::pair< Nullable< wstring >, Nullable< wstring > > line( partition( cookies.value(), L";" ) ); !line.first.isnull(); ) { std::pair< wstring, Nullable< wstring > > cookie( partition( line.first.value(), L"=" ) ); m_values[ std::make_pair( wstring(), decode( cookie.first ) ) ] = cookie.second.isnull() ? _variant_t() : _variant_t( decode( cookie.second.value() ).c_str() ); if ( !cookie.second.isnull() && cookie.second.value().find( '&' ) != std::wstring::npos ) { for ( std::pair< Nullable< wstring >, Nullable< wstring > > part( partition( cookie.second.value(), L"&" ) ); !part.first.isnull(); ) { std::pair< wstring, Nullable< wstring > > val( partition( part.first.value(), L"=" ) ); m_values[ std::make_pair( decode( cookie.first ), decode( val.first ) ) ] = val.second.isnull() ? _variant_t() : _variant_t( decode( val.second.value() ).c_str() ); part.first = part.second; if ( !part.first.isnull() ) part = partition( part.first.value(), L"&" ); } } line.first = line.second; if ( !line.first.isnull() ) line = partition( line.first.value(), L";" ); } } size_t FSLib::InputCookie::exists( const wstring &name, const Nullable< wstring > &partition ) const { if ( m_values.find( std::make_pair( partition.value( wstring() ), name ) ) != m_values.end() ) return 1; else return 0; } _variant_t FSLib::InputCookie::value( const wstring &name, const Nullable< size_t > &num, const FSLib::Nullable< FSLib::wstring > &partition ) const { if ( num.value( 0 ) ) throw FSLib::Exceptions::OutOfRange< __int64 >( L"The index number for fetching a cookie variable must be 0 or Null", 0, 1, num.value() ); std::map< std::pair< wstring, wstring >, _variant_t >::const_iterator pos( m_values.find( std::make_pair( partition.value( wstring() ), name ) ) ); if ( pos == m_values.end() ) throw FSLib::Exceptions::Field( L"Cookie was not found", concat( partition, L" - ", name ).value() ); return (*pos).second; } /* FSLib::InputGet */ namespace { utf8 digit( const string &t, const string::size_type p ) { if ( p >= t.size() ) throw FSLib::Exceptions::OutOfRange< __int64 >( L"Not enough characters in the string after reserved character", 0, t.size(), p ); if ( t.at( p ) >= L'0' && t.at( p ) <= L'9' ) return t.at( p ) - L'0'; else if ( t.at( p ) >= L'a' && t.at( p ) <= L'f' ) return t.at( p ) - L'a' + 10; else if ( t.at( p ) >= L'A' && t.at( p ) <= L'F' ) return t.at( p ) - L'A' + 10; else throw FSLib::Exceptions::StringDecode( L"Character ('" + widen( t.substr( p, 1 ) ) + L"') not allowed in a hex sequence" ); } void doParse( const Nullable< string > &q, std::map< wstring, std::vector< _variant_t > > &data ) { for ( std::pair< string, Nullable< string > > query = partition( q, "&" ); query.first.size(); query = partition( query.second, "&" ) ) { std::pair< string, Nullable< string > > cracked = partition( query.first, "=" ); wstring name( widen( cracked.first ) ); if ( cracked.second.isnull() ) data[ name ].push_back( _variant_t() ); else { try { string text = replaceAll( cracked.second.value(), "+", " "); string::size_type pos = 0; while ( ( pos = text.find( '%', pos ) ) != std::string::npos ) { utf8 ch = digit( text, pos + 1 ) * 16 + digit( text, pos + 2 ); text = text.substr( 0, pos ) + char( ch ) + text.substr( pos + 3 ); } data[ name ].push_back( widen( text ).c_str() ); } catch ( FSLib::Exceptions::Exception &e ) { e.info() << L"Decoding query string value named: " << name << std::endl; throw; } } } } } FSLib::InputGet::InputGet( const string &query ) : m_parsed( true ) { doParse( query, m_data ); } FSLib::InputGet::InputGet( ATL::CComPtr< IRequest > r ) : m_request( r ), m_parsed( false ) { } FSLib::InputGet::t_name FSLib::InputGet::begin() const { parse(); return m_data.begin(); } FSLib::InputGet::t_name FSLib::InputGet::end() const { parse(); return m_data.end(); } FSLib::InputGet::t_value FSLib::InputGet::begin( const t_name n ) const { parse(); return (*n).second.begin(); } FSLib::InputGet::t_value FSLib::InputGet::end( const t_name n ) const { parse(); return (*n).second.end(); } size_t FSLib::InputGet::exists( const FSLib::wstring &n, const FSLib::Nullable< FSLib::wstring > & ) const { parse(); std::map< wstring, std::vector< _variant_t > >::const_iterator pos( m_data.find( n ) ); if ( pos == m_data.end() ) return 0; else return (*pos).second.size(); } _variant_t FSLib::InputGet::value( const FSLib::wstring &n, const Nullable< size_t > &num, const FSLib::Nullable< FSLib::wstring > &p ) const { parse(); if ( exists( n, p ) <= num.value( 0 ) ) throw FSLib::Exceptions::Field( L"Field does not exist in GET data or index beyond end of value index", concat( p, L"/", n ).value() ); return m_data[ n ][ num.value( 0 ) ]; } void FSLib::InputGet::parse() const { if ( !m_parsed ) { m_parsed = true; Iis::InputServer server( m_request ); doParse( variant_cast< Nullable< string > >( server.value( L"QUERY_STRING" ) ), m_data ); } }