Rename boost_asio files

This commit is contained in:
Vinnie Falco
2013-09-05 08:16:46 -07:00
parent f79b34b2c9
commit 3f74cb76e9
51 changed files with 279 additions and 254 deletions

View File

@@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
class HandshakeDetectLogic
{
public:
HandshakeDetectLogic ()
: m_finished (false)
, m_success (false)
{
}
/** How many bytes maximum we might need.
This is the largest number of bytes that the detector
might need in order to come to a conclusion about
whether or not the handshake is a match. Depending
on the data, it could come to that conclusion sooner
though.
Use read_some instead of read so that the detect logic
can reject the handshake sooner if possible.
*/
virtual std::size_t max_needed () = 0;
/** How many bytes the handshake consumes.
If the detector processes the entire handshake this will
be non zero. The SSL detector would return 0, since we
want all the existing bytes to be passed on.
*/
virtual std::size_t bytes_consumed () = 0;
/** Return true if we have enough data to form a conclusion.
*/
bool finished () const noexcept
{
return m_finished;
}
/** Return true if we came to a conclusion and the data matched.
*/
bool success () const noexcept
{
return m_finished && m_success;
}
protected:
void conclude (bool success = true)
{
m_finished = true;
m_success = success;
}
void fail ()
{
conclude (false);
}
private:
bool m_finished;
bool m_success;
};
//------------------------------------------------------------------------------
/** Wraps the logic and exports it as an abstract interface.
*/
template <typename Logic>
class HandshakeDetectLogicType
{
public:
typedef Logic LogicType;
typedef typename Logic::arg_type arg_type;
explicit HandshakeDetectLogicType (arg_type const& arg = arg_type ())
: m_logic (arg)
{
}
LogicType& get ()
{
return m_logic;
}
std::size_t max_needed ()
{
return m_logic.max_needed ();
}
std::size_t bytes_consumed ()
{
return m_logic.bytes_consumed ();
}
bool finished ()
{
return m_logic.finished ();
}
/** If finished is true, this tells us if the handshake was detected.
*/
bool success ()
{
return m_logic.success ();
}
/** Analyze the buffer to match the Handshake.
Returns `true` if the analysis is complete.
*/
template <typename ConstBufferSequence>
bool analyze (ConstBufferSequence const& buffer)
{
bassert (! m_logic.finished ());
m_logic.analyze (buffer);
return m_logic.finished ();
}
private:
Logic m_logic;
};
#endif

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

View File

@@ -0,0 +1,159 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
/** Handshake detector for the PROXY protcol
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
*/
class HandshakeDetectLogicPROXY : public HandshakeDetectLogic
{
public:
typedef int arg_type;
enum
{
// This is for version 1. The largest number of bytes
// that we could possibly need to parse a valid handshake.
// We will reject it much sooner if there's an illegal value.
//
maxBytesNeeded = 107 // including CRLF, no null term
};
struct ProxyInfo
{
typedef InputParser::IPv4Address IPv4Address;
String protocol; // "TCP4", "TCP6", "UNKNOWN"
IPv4Address sourceAddress;
IPv4Address destAddress;
uint16 sourcePort;
uint16 destPort;
};
explicit HandshakeDetectLogicPROXY (arg_type const&)
: m_consumed (0)
{
}
ProxyInfo const& getInfo () const noexcept
{
return m_info;
}
std::size_t max_needed ()
{
return maxBytesNeeded;
}
std::size_t bytes_consumed ()
{
return m_consumed;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <maxBytesNeeded> in (buffer);
InputParser::State state;
analyze_input (in, state);
if (state.passed ())
{
m_consumed = in.used ();
conclude (true);
}
else if (state.failed ())
{
conclude (false);
}
}
void analyze_input (FixedInputBuffer& in, InputParser::State& state)
{
using namespace InputParser;
if (! match (in, "PROXY ", state))
return;
if (match (in, "TCP4 "))
{
m_info.protocol = "TCP4";
if (! read (in, m_info.sourceAddress, state))
return;
if (! match (in, " ", state))
return;
if (! read (in, m_info.destAddress, state))
return;
if (! match (in, " ", state))
return;
UInt16Str sourcePort;
if (! read (in, sourcePort, state))
return;
m_info.sourcePort = sourcePort.value;
if (! match (in, " ", state))
return;
UInt16Str destPort;
if (! read (in, destPort, state))
return;
m_info.destPort = destPort.value;
if (! match (in, "\r\n", state))
return;
state = State::pass;
return;
}
else if (match (in, "TCP6 "))
{
m_info.protocol = "TCP6";
state = State::fail;
return;
}
else if (match (in, "UNKNOWN "))
{
m_info.protocol = "UNKNOWN";
state = State::fail;
return;
}
state = State::fail;
}
private:
std::size_t m_consumed;
ProxyInfo m_info;
};
#endif

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
// Handshake for SSL 2
//
// http://tools.ietf.org/html/rfc5246#appendix-E.2
//
// uint8 V2CipherSpec[3];
// struct {
// uint16 msg_length;
// uint8 msg_type;
// Version version; Should be 'ProtocolVersion'?
// uint16 cipher_spec_length;
// uint16 session_id_length;
// uint16 challenge_length;
// ...
//
class HandshakeDetectLogicSSL2 : public HandshakeDetectLogic
{
public:
typedef int arg_type;
explicit HandshakeDetectLogicSSL2 (arg_type const&)
{
}
enum
{
bytesNeeded = 3
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <bytesNeeded> in (buffer);
{
uint8 byte;
if (! in.peek (&byte))
return;
// First byte must have the high bit set
//
if((byte & 0x80) != 0x80)
return fail ();
}
// The remaining bits contain the
// length of the following data in bytes.
//
uint16 msg_length;
if (! in.readNetworkInteger(&msg_length))
return;
// sizeof (msg_type +
// Version (ProtcolVersion?) +
// cipher_spec_length +
// session_id_length +
// challenge_length)
//
// Should be 9 or greater.
//
if (msg_length < 9)
return fail ();
uint8 msg_type;
if (! in.read (&msg_type))
return;
// The msg_type must be 0x01 for a version 2 ClientHello
//
if (msg_type != 0x01)
return fail ();
conclude ();
}
};
#endif

View File

@@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
// Handshake for SSL 3 (Also TLS 1.0 and 1.1)
//
// http://www.ietf.org/rfc/rfc2246.txt
//
// Section 7.4. Handshake protocol
//
class HandshakeDetectLogicSSL3 : public HandshakeDetectLogic
{
public:
typedef int arg_type; // dummy
explicit HandshakeDetectLogicSSL3 (arg_type const&)
{
}
enum
{
bytesNeeded = 6
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
uint16 version;
FixedInputBufferSize <bytesNeeded> in (buffer);
uint8 msg_type;
if (! in.read (&msg_type))
return;
// msg_type must be 0x16 = "SSL Handshake"
//
if (msg_type != 0x16)
return fail ();
if (! in.read (&version))
return;
version = fromNetworkByteOrder (version);
uint16 length;
if (! in.read (&length))
return;
length = fromNetworkByteOrder (length);
conclude ();
}
};
#endif

View File

@@ -0,0 +1,206 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
//------------------------------------------------------------------------------
/** A wrapper to decode the handshake data on a Stream.
Stream must meet these requirements
For detect:
SyncReadStream
For async_detect:
AsyncReadStream
Logic must meet this requirement:
HandshakeDetectLogic
*/
template <typename Stream, typename Logic>
class HandshakeDetectorType
{
protected:
typedef boost::system::error_code error_code;
public:
Logic& getLogic ()
{
return m_logic.get ();
}
//--------------------------------------------------------------------------
/** Synchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
*/
template <typename Allocator>
error_code detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer)
{
typedef boost::asio::basic_streambuf <Allocator> BufferType;
error_code ec;
do
{
m_logic.analyze (buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= buffer.size ());
buffer.consume (consumed);
break;
}
std::size_t const available = buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BufferType::mutable_buffers_type buffers (
buffer.prepare (needed - available));
buffer.commit (stream.read_some (buffers, ec));
}
}
while (! ec);
return ec;
}
//--------------------------------------------------------------------------
/** Asynchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
DetectHandler must have this signature:
void(error_code)
*/
template <typename DetectHandler, typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
BOOST_ASIO_MOVE_ARG(DetectHandler) handler)
{
async_detect <Allocator> (stream, buffer, SharedHandlerPtr (
new ErrorSharedHandlerType <DetectHandler> (
BOOST_ASIO_MOVE_CAST(DetectHandler)(handler))));
}
template <typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
SharedHandlerPtr handler)
{
typedef AsyncOp <Allocator> OpType;
OpType* const op = new AsyncOp <Allocator> (
m_logic, stream, buffer, handler);
stream.get_io_service ().wrap (SharedHandlerPtr (op))
(error_code (), 0);
}
private:
template <typename Allocator>
struct AsyncOp : ComposedAsyncOperation
{
typedef boost::asio::basic_streambuf <Allocator> BufferType;
AsyncOp (HandshakeDetectLogicType <Logic>& logic, Stream& stream,
BufferType& buffer, SharedHandlerPtr const& handler)
: ComposedAsyncOperation (sizeof (*this), handler)
, m_logic (logic)
, m_stream (stream)
, m_buffer (buffer)
, m_handler (handler)
, m_running (false)
{
}
// Set breakpoint to prove it gets destroyed
~AsyncOp ()
{
}
void operator() (error_code const& ec_, size_t bytes_transferred)
{
m_running = true;
error_code ec (ec_);
if (! ec)
{
m_buffer.commit (bytes_transferred);
m_logic.analyze (m_buffer.data ());
if (!m_logic.finished ())
{
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BufferType::mutable_buffers_type buffers (
m_buffer.prepare (needed - available));
m_stream.async_read_some (buffers, SharedHandlerPtr (this));
}
return;
}
std::size_t const consumed = m_logic.bytes_consumed ();
m_buffer.consume (consumed);
}
// Finalize with a call to the original handler.
m_stream.get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST (SharedHandlerPtr)(m_handler))
(ec);
}
bool is_continuation ()
{
return m_running
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
|| boost_asio_handler_cont_helpers::is_continuation (m_handler);
#endif
;
}
private:
HandshakeDetectLogicType <Logic>& m_logic;
Stream& m_stream;
BufferType& m_buffer;
SharedHandlerPtr m_handler;
bool m_running;
};
private:
HandshakeDetectLogicType <Logic> m_logic;
};
#endif

View File

@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_PROTOCOL_HTTPCLIENT_H_INCLUDED
#define BEAST_ASIO_PROTOCOL_HTTPCLIENT_H_INCLUDED
#endif

View File

@@ -0,0 +1,387 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
namespace InputParser
{
/** Tri-valued parsing state.
This is convertible to bool which means continue.
Or you can use stop() to decide if you should return.
After a stop you can use failed () to determine if parsing failed.
*/
struct State : SafeBool <State>
{
enum State_t
{
pass, // passed the parse
fail, // failed the parse
more // didn't fail but need more bytes
};
State () : m_state (more) { }
State (State_t state) : m_state (state) { }
/** Implicit construction from bool.
If condition is true then the parse passes, else need more.
*/
State (bool condition) : m_state (condition ? pass : more) { }
State& operator= (State_t state) { m_state = state; return *this; }
bool eof () const noexcept { return m_state == more; }
bool stop () const noexcept { return m_state != pass; }
bool passed () const noexcept { return m_state == pass; }
bool failed () const noexcept { return m_state == fail; }
bool asBoolean () const noexcept { return m_state == pass; } // for SafeBool<>
private:
State_t m_state;
};
//------------------------------------------------------------------------------
// Shortcut to save typing.
typedef FixedInputBuffer& Input;
/** Specializations implement the get() function. */
template <class T>
struct Get;
/** Specializations implement the match() function.
Default implementation of match tries to read it into a local.
*/
template <class T>
struct Match
{
static State func (Input in, T other)
{
T t;
State state = Get <T>::func (in, t);
if (state.passed ())
{
if (t == other)
return State::pass;
return State::fail;
}
return state;
}
};
/** Specializations implement the peek() function.
Default implementation of peek reads and rewinds.
*/
template <class T>
struct Peek
{
static State func (Input in, T& t)
{
Input dup (in);
return Get <T>::func (dup, t);
}
};
//------------------------------------------------------------------------------
//
// Free Functions
//
//------------------------------------------------------------------------------
// match a block of data in memory
//
static State match_buffer (Input in, void const* buffer, std::size_t bytes)
{
bassert (bytes > 0);
if (in.size () <= 0)
return State::more;
std::size_t const have = std::min (in.size (), bytes);
void const* data = in.peek (have);
bassert (data != nullptr);
int const compare = memcmp (data, buffer, have);
if (compare != 0)
return State::fail;
in.consume (have);
return have == bytes;
}
//------------------------------------------------------------------------------
//
// match
//
// Returns the state
template <class T>
State match (Input in, T t)
{
return Match <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool match (Input in, T t, State& state)
{
return (state = match (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// peek
//
// Returns the state
template <class T>
State peek (Input in, T& t)
{
return Peek <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool peek (Input in, T& t, State& state)
{
return (state = peek (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// read
//
// Returns the state
template <class T>
State read (Input in, T& t)
{
return Get <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool read (Input in, T& t, State& state)
{
return (state = read (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// Specializations for basic types
//
template <>
struct Match <char const*>
{
static State func (Input in, char const* text)
{
return InputParser::match_buffer (in, text, strlen (text));
}
};
//------------------------------------------------------------------------------
//
// Special types and their specializations
//
struct Digit
{
int value;
};
template <>
struct Get <Digit>
{
static State func (Input in, Digit& t)
{
char c;
if (! in.peek (&c))
return State::more;
if (! std::isdigit (c))
return State::fail;
in.consume (1);
t.value = c - '0';
return State::pass;
}
};
//------------------------------------------------------------------------------
// An unsigned 32 bit number expressed as a string
struct UInt32Str
{
uint32 value;
};
template <>
struct Get <UInt32Str>
{
static State func (Input in, UInt32Str& t)
{
State state;
uint32 value (0);
Digit digit;
// have to have at least one digit
if (! read (in, digit, state))
return state;
value = digit.value;
for (;;)
{
state = peek (in, digit);
if (state.failed ())
{
t.value = value;
return State::pass;
}
else if (state.eof ())
{
t.value = value;
return state;
}
// can't have a digit following a zero
if (value == 0)
return State::fail;
uint32 newValue = (value * 10) + digit.value;
// overflow
if (newValue < value)
return State::fail;
value = newValue;
}
return State::fail;
}
};
//------------------------------------------------------------------------------
// An unsigned 16 bit number expressed as a string
struct UInt16Str
{
uint16 value;
};
template <>
struct Get <UInt16Str>
{
static State func (Input in, UInt16Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 65535)
{
t.value = uint16(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An unsigned 8 bit number expressed as a string
struct UInt8Str
{
uint8 value;
};
template <>
struct Get <UInt8Str>
{
static State func (Input in, UInt8Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 255)
{
t.value = uint8(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An dotted IPv4 address
struct IPv4Address
{
uint8 value [4];
String toString () const
{
return String::fromNumber <int> (value [0]) + "." +
String::fromNumber <int> (value [1]) + "." +
String::fromNumber <int> (value [2]) + "." +
String::fromNumber <int> (value [3]);
}
};
template <>
struct Get <IPv4Address>
{
static State func (Input in, IPv4Address& t)
{
State state;
UInt8Str digit [4];
if (! read (in, digit [0], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [1], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [2], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [3], state))
return state;
t.value [0] = digit [0].value;
t.value [1] = digit [1].value;
t.value [2] = digit [2].value;
t.value [3] = digit [3].value;
return State::pass;
}
};
//------------------------------------------------------------------------------
}
#endif

View File

@@ -0,0 +1,197 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
/** Front-ends a stream with a provided block of data.
When read operations are performed on this object, bytes will first be
returned from the buffer provided on construction. When those bytes
are exhausted, read operations will then pass through to the underlying
stream.
Write operations are all simply passed through.
*/
template <typename Stream>
class PrefilledReadStream : public Uncopyable
{
protected:
typedef boost::system::error_code error_code;
void throw_error (error_code const& ec, char const* fileName, int lineNumber)
{
Throw (boost::system::system_error (ec), fileName, lineNumber);
}
public:
typedef typename boost::remove_reference <Stream>::type next_layer_type;
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/** Single argument constructor for when we are wrapped in something.
arg is passed through to the next layer's constructor.
*/
template <typename Arg>
explicit PrefilledReadStream (Arg& arg)
: m_next_layer (arg)
{
}
/** Construct with the buffer, and argument passed through.
This creates a copy of the data. The argument is passed through
to the constructor of Stream.
*/
template <typename Arg, typename ConstBufferSequence>
PrefilledReadStream (Arg& arg, ConstBufferSequence const& buffers)
: m_next_layer (arg)
{
fill (buffers);
}
/** Place some input into the prefilled buffer.
Note that this is in no way thread safe. The only reason this function
is here is for the case when you can't pass the buffer through the
constructor because there is another object wrapping this stream.
*/
template <typename ConstBufferSequence>
void fill (ConstBufferSequence const& buffers)
{
// We don't assume the caller's buffers will
// remain valid for the lifetime of this object.
//
using namespace boost;
m_buffer.commit (asio::buffer_copy (
m_buffer.prepare (asio::buffer_size (buffers)),
buffers));
}
next_layer_type& next_layer()
{
return m_next_layer;
}
next_layer_type const& next_layer() const
{
return m_next_layer;
}
lowest_layer_type& lowest_layer()
{
return m_next_layer.lowest_layer();
}
const lowest_layer_type& lowest_layer() const
{
return m_next_layer.lowest_layer();
}
boost::asio::io_service& get_io_service()
{
return m_next_layer.get_io_service();
}
void close()
{
error_code ec;
if (close(ec))
throw_error (ec, __FILE__, __LINE__);
return ec;
}
error_code close (error_code& ec)
{
// VFALCO NOTE This is questionable. We can't
// call m_next_layer.close() because Stream might not
// support that function. For example, ssl::stream has no close()
//
return lowest_layer ().close(ec);
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers)
{
error_code ec;
std::size_t const amount = read_some (buffers, ec);
if (ec)
throw_error (ec, __FILE__, __LINE__);
return amount;
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers, error_code& ec)
{
if (m_buffer.size () > 0)
{
ec = error_code ();
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
return bytes_transferred;
}
return m_next_layer.read_some (buffers, ec);
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers)
{
error_code ec;
std::size_t const amount = write_some (buffers, ec);
if (ec)
throw_error (ec, __FILE__, __LINE__);
return amount;
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers, error_code& ec)
{
return m_next_layer.write_some (buffers, ec);
}
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some (MutableBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
{
if (m_buffer.size () > 0)
{
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) (
error_code (), bytes_transferred);
return;
}
m_next_layer.async_read_some (buffers,
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
}
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some (ConstBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
{
m_next_layer.async_write_some (buffers,
BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
}
private:
Stream m_next_layer;
boost::asio::streambuf m_buffer;
};
#endif