diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj
index 6b28e276a..9017ba1d7 100644
--- a/Builds/VisualStudio2012/beast.vcxproj
+++ b/Builds/VisualStudio2012/beast.vcxproj
@@ -77,10 +77,11 @@
+
-
+
@@ -309,7 +310,7 @@
true
-
+
true
true
true
diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters
index c9094c3bb..b57b3da3d 100644
--- a/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -836,9 +836,6 @@
beast_asio\streams
-
- beast_asio\handshake
-
beast_asio\handshake
@@ -854,6 +851,12 @@
beast_asio\handshake
+
+ beast_asio\handshake
+
+
+ beast_asio\handshake
+
@@ -1312,7 +1315,7 @@
beast_asio\basics
-
+
beast_asio\handshake
diff --git a/modules/beast_asio/basics/beast_FixedInputBuffer.h b/modules/beast_asio/basics/beast_FixedInputBuffer.h
index ce0a96805..a7c06d6e7 100644
--- a/modules/beast_asio/basics/beast_FixedInputBuffer.h
+++ b/modules/beast_asio/basics/beast_FixedInputBuffer.h
@@ -24,68 +24,88 @@
This provides a convenient interface for doing a bytewise
verification/reject test on a handshake protocol.
*/
-template
-struct FixedInputBuffer
+/** @{ */
+class FixedInputBuffer
{
- template
- explicit FixedInputBuffer (ConstBufferSequence const& buffer)
- : m_buffer (boost::asio::buffer (m_storage))
- , m_size (boost::asio::buffer_copy (m_buffer, buffer))
- , m_data (boost::asio::buffer_cast (m_buffer))
+protected:
+ struct CtorParams
+ {
+ CtorParams (uint8 const* begin_, std::size_t bytes_)
+ : begin (begin_)
+ , bytes (bytes_)
+ {
+ }
+
+ uint8 const* begin;
+ std::size_t bytes;
+ };
+
+ FixedInputBuffer (CtorParams const& params)
+ : m_begin (params.begin)
+ , m_iter (m_begin)
+ , m_end (m_begin + params.bytes)
{
}
- uint8 operator[] (std::size_t index) const noexcept
+public:
+ FixedInputBuffer (FixedInputBuffer const& other)
+ : m_begin (other.m_begin)
+ , m_iter (other.m_iter)
+ , m_end (other.m_end)
{
- bassert (index >= 0 && index < m_size);
- return m_data [index];
}
- bool peek (std::size_t bytes) const noexcept
+ FixedInputBuffer& operator= (FixedInputBuffer const& other)
{
- if (m_size >= bytes)
- return true;
- return false;
+ m_begin = other.m_begin;
+ m_iter = other.m_iter;
+ m_end = other.m_end;
+ return *this;
+ }
+
+ // Returns the number of bytes consumed
+ std::size_t used () const noexcept
+ {
+ return m_iter - m_begin;
+ }
+
+ // Returns the size of what's remaining
+ std::size_t size () const noexcept
+ {
+ return m_end - m_iter;
+ }
+
+ void const* peek (std::size_t bytes)
+ {
+ return peek_impl (bytes, nullptr);
}
template
- bool peek (T* t) noexcept
+ bool peek (T* t) const noexcept
{
- std::size_t const bytes = sizeof (T);
- if (m_size >= bytes)
- {
- std::copy (m_data, m_data + bytes, t);
- return true;
- }
- return false;
+ return peek_impl (sizeof (T), t) != nullptr;
}
bool consume (std::size_t bytes) noexcept
{
- if (m_size >= bytes)
- {
- m_data += bytes;
- m_size -= bytes;
- return true;
- }
- return false;
+ return read_impl (bytes, nullptr) != nullptr;
+ }
+
+ bool read (std::size_t bytes) noexcept
+ {
+ return read_impl (bytes, nullptr) != nullptr;
}
template
bool read (T* t) noexcept
{
- std::size_t const bytes = sizeof (T);
- if (m_size >= bytes)
- {
- //this causes a stack corruption.
- //std::copy (m_data, m_data + bytes, t);
+ return read_impl (sizeof (T), t) != nullptr;
+ }
- memcpy (t, m_data, bytes);
- m_data += bytes;
- m_size -= bytes;
- return true;
- }
- return false;
+ uint8 operator[] (std::size_t index) const noexcept
+ {
+ bassert (index >= 0 && index < size ());
+ return m_iter [index];
}
// Reads an integraltype in network byte order
@@ -97,16 +117,77 @@ struct FixedInputBuffer
//static_bassert (std::is_integral ::value);
IntegerType networkValue;
if (! read (&networkValue))
- return;
+ return false;
*value = fromNetworkByteOrder (networkValue);
return true;
}
+protected:
+ void const* peek_impl (std::size_t bytes, void* buffer) const noexcept
+ {
+ if (size () >= bytes)
+ {
+ if (buffer != nullptr)
+ memcpy (buffer, m_iter, bytes);
+ return m_iter;
+ }
+ return nullptr;
+ }
+
+ void const* read_impl (std::size_t bytes, void* buffer) noexcept
+ {
+ if (size () >= bytes)
+ {
+ if (buffer != nullptr)
+ memcpy (buffer, m_iter, bytes);
+ void const* data = m_iter;
+ m_iter += bytes;
+ return data;
+ }
+ return nullptr;
+ }
+
+private:
+ uint8 const* m_begin;
+ uint8 const* m_iter;
+ uint8 const* m_end;
+};
+
+//------------------------------------------------------------------------------
+
+template
+class FixedInputBufferSize : public FixedInputBuffer
+{
+protected:
+ struct SizedCtorParams
+ {
+ template
+ SizedCtorParams (ConstBufferSequence const& buffers, Storage& storage)
+ {
+ MutableBuffer buffer (boost::asio::buffer (storage));
+ data = boost::asio::buffer_cast (buffer);
+ bytes = boost::asio::buffer_copy (buffer, buffers);
+ }
+
+ operator CtorParams () const noexcept
+ {
+ return CtorParams (data, bytes);
+ }
+
+ uint8 const* data;
+ std::size_t bytes;
+ };
+
+public:
+ template
+ explicit FixedInputBufferSize (ConstBufferSequence const& buffers)
+ : FixedInputBuffer (SizedCtorParams (buffers, m_storage))
+ {
+ }
+
private:
boost::array m_storage;
MutableBuffer m_buffer;
- std::size_t m_size;
- uint8 const* m_data;
};
#endif
diff --git a/modules/beast_asio/beast_asio.cpp b/modules/beast_asio/beast_asio.cpp
index 64d811048..c22b3b6dc 100644
--- a/modules/beast_asio/beast_asio.cpp
+++ b/modules/beast_asio/beast_asio.cpp
@@ -30,7 +30,7 @@ namespace beast
#include "sockets/beast_Socket.cpp"
#include "sockets/beast_SslContext.cpp"
-#include "handshake/beast_ProxyHandshake.cpp"
+#include "handshake/beast_HandshakeDetectLogicPROXY.cpp"
#include "tests/beast_TestPeerBasics.cpp"
#include "tests/beast_TestPeerLogic.cpp"
diff --git a/modules/beast_asio/beast_asio.h b/modules/beast_asio/beast_asio.h
index acba94323..3ab9fc29b 100644
--- a/modules/beast_asio/beast_asio.h
+++ b/modules/beast_asio/beast_asio.h
@@ -60,8 +60,9 @@ namespace beast
#include "sockets/beast_SocketWrapper.h"
#include "sockets/beast_SslContext.h"
-#include "handshake/beast_ProxyHandshake.h"
- #include "handshake/beast_HandshakeDetectLogic.h"
+ #include "handshake/beast_InputParser.h"
+ #include "handshake/beast_HandshakeDetectLogic.h"
+#include "handshake/beast_HandshakeDetectLogicPROXY.h"
#include "handshake/beast_HandshakeDetectLogicSSL2.h"
#include "handshake/beast_HandshakeDetectLogicSSL3.h"
#include "handshake/beast_HandshakeDetectStream.h"
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectLogic.h b/modules/beast_asio/handshake/beast_HandshakeDetectLogic.h
index 62eae110d..8855928e2 100644
--- a/modules/beast_asio/handshake/beast_HandshakeDetectLogic.h
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectLogic.h
@@ -42,6 +42,13 @@ public:
*/
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
@@ -94,19 +101,24 @@ public:
return m_logic;
}
- std::size_t max_needed () noexcept
+ std::size_t max_needed ()
{
return m_logic.max_needed ();
}
- bool finished () noexcept
+ 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 () noexcept
+ bool success ()
{
return m_logic.success ();
}
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.cpp b/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.cpp
new file mode 100644
index 000000000..b95e38c58
--- /dev/null
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.cpp
@@ -0,0 +1,20 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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.
+*/
+//==============================================================================
+
+
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.h b/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.h
new file mode 100644
index 000000000..4b65e9bb9
--- /dev/null
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectLogicPROXY.h
@@ -0,0 +1,159 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
+#define BEAST_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
+ void analyze (ConstBufferSequence const& buffer)
+ {
+ FixedInputBufferSize 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
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL2.h b/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL2.h
index 49f63eeb9..47a6d68df 100644
--- a/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL2.h
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL2.h
@@ -53,10 +53,15 @@ public:
return bytesNeeded;
}
+ std::size_t bytes_consumed ()
+ {
+ return 0;
+ }
+
template
void analyze (ConstBufferSequence const& buffer)
{
- FixedInputBuffer in (buffer);
+ FixedInputBufferSize in (buffer);
{
uint8 byte;
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL3.h b/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL3.h
index c2314f04a..839c053c2 100644
--- a/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL3.h
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectLogicSSL3.h
@@ -45,11 +45,16 @@ public:
return bytesNeeded;
}
+ std::size_t bytes_consumed ()
+ {
+ return 0;
+ }
+
template
void analyze (ConstBufferSequence const& buffer)
{
uint16 version;
- FixedInputBuffer in (buffer);
+ FixedInputBufferSize in (buffer);
uint8 msg_type;
if (! in.read (&msg_type))
diff --git a/modules/beast_asio/handshake/beast_HandshakeDetectStream.h b/modules/beast_asio/handshake/beast_HandshakeDetectStream.h
index 82c59c45a..34c1e3aca 100644
--- a/modules/beast_asio/handshake/beast_HandshakeDetectStream.h
+++ b/modules/beast_asio/handshake/beast_HandshakeDetectStream.h
@@ -97,6 +97,18 @@ public:
{
}
+ // This puts bytes that you already have into the detector buffer
+ // Any leftovers will be given to the callback.
+ // A copy of the data is made.
+ //
+ template
+ void fill (ConstBufferSequence const& buffers)
+ {
+ m_buffer.commit (boost::asio::buffer_copy (
+ m_buffer.prepare (boost::asio::buffer_size (buffers)),
+ buffers));
+ }
+
// basic_io_object
boost::asio::io_service& get_io_service ()
@@ -203,6 +215,10 @@ public:
if (m_logic.finished ())
{
+ // consume what we used (for SSL its 0)
+ std::size_t const consumed = m_logic.bytes_consumed ();
+ bassert (consumed <= m_buffer.size ());
+ m_buffer.consume (consumed);
m_callback->on_detect (m_logic.get (), ec,
ConstBuffers (m_buffer.data ()));
break;
@@ -240,10 +256,16 @@ public:
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
- m_logic.analyze (m_buffer.data ());
+ if (bytes_transferred > 0)
+ m_logic.analyze (m_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 <= m_buffer.size ());
+ m_buffer.consume (consumed);
+
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
if (! m_origBufferedHandler.isNull ())
{
diff --git a/modules/beast_asio/handshake/beast_InputParser.h b/modules/beast_asio/handshake/beast_InputParser.h
new file mode 100644
index 000000000..f79f23afc
--- /dev/null
+++ b/modules/beast_asio/handshake/beast_InputParser.h
@@ -0,0 +1,379 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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_INPUTPARSER_H_INCLUDED
+#define BEAST_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
+{
+ 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
+struct Get;
+
+/** Specializations implement the match() function.
+ Default implementation of match tries to read it into a local.
+*/
+template
+struct Match
+{
+ static State func (Input in, T other)
+ {
+ T t;
+ State state = Get ::func (in, t);
+ if (state.passed ())
+ {
+ if (t == other)
+ return State::passed;
+ return State::failed;
+ }
+ return state;
+ }
+};
+
+/** Specializations implement the peek() function.
+ Default implementation of peek reads and rewinds.
+*/
+template
+struct Peek
+{
+ static State func (Input in, T& t)
+ {
+ Input dup (in);
+ return Get ::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
+State match (Input in, T t)
+{
+ return Match ::func (in, t);
+}
+
+// Stores the state in the argument and returns true if its a pass
+template
+bool match (Input in, T t, State& state)
+{
+ return (state = match (in, t)).passed ();
+}
+
+//------------------------------------------------------------------------------
+//
+// peek
+//
+
+// Returns the state
+template
+State peek (Input in, T& t)
+{
+ return Peek ::func (in, t);
+}
+
+// Stores the state in the argument and returns true if its a pass
+template
+bool peek (Input in, T& t, State& state)
+{
+ return (state = peek (in, t)).passed ();
+}
+
+//------------------------------------------------------------------------------
+//
+// read
+//
+
+// Returns the state
+template
+State read (Input in, T& t)
+{
+ return Get ::func (in, t);
+}
+
+// Stores the state in the argument and returns true if its a pass
+template
+bool read (Input in, T& t, State& state)
+{
+ return (state = read (in, t)).passed ();
+}
+
+//------------------------------------------------------------------------------
+//
+// Specializations for basic types
+//
+
+template <>
+struct Match
+{
+ 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
+{
+ 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
+{
+ 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
+{
+ 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
+{
+ 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];
+};
+
+template <>
+struct Get
+{
+ 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
diff --git a/modules/beast_asio/handshake/beast_ProxyHandshake.cpp b/modules/beast_asio/handshake/beast_ProxyHandshake.cpp
deleted file mode 100644
index 94856fcbc..000000000
--- a/modules/beast_asio/handshake/beast_ProxyHandshake.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of Beast: https://github.com/vinniefalco/Beast
- Copyright 2013, Vinnie Falco
-
- 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.
-*/
-//==============================================================================
-
-ProxyHandshake::ProxyHandshake (bool expectHandshake)
- : m_status (expectHandshake ? statusHandshake : statusNone)
- , m_gotCR (false)
-{
- m_buffer.preallocateBytes (maxVersion1Bytes);
-}
-
-ProxyHandshake::~ProxyHandshake ()
-{
-}
-
-std::size_t ProxyHandshake::feed (void const* inputBuffer, size_t inputBytes)
-{
- std::size_t bytesConsumed = 0;
-
- char const* p = static_cast (inputBuffer);
-
- if (m_status == statusHandshake)
- {
- if (! m_gotCR)
- {
- while (inputBytes > 0 && m_buffer.length () < maxVersion1Bytes - 1)
- {
- beast_wchar c = *p++;
- ++bytesConsumed;
- --inputBytes;
- m_buffer += c;
-
- if (c == '\r')
- {
- m_gotCR = true;
- break;
- }
- else if (c == '\n')
- {
- m_status = statusFailed;
- }
- }
-
- if (m_buffer.length () > maxVersion1Bytes - 1)
- {
- m_status = statusFailed;
- }
- }
- }
-
- if (m_status == statusHandshake)
- {
- if (inputBytes > 0 && m_gotCR)
- {
- bassert (m_buffer.length () < maxVersion1Bytes);
-
- char const lf ('\n');
-
- if (*p == lf)
- {
- ++bytesConsumed;
- --inputBytes;
- m_buffer += lf;
-
- parseLine ();
- }
- else
- {
- m_status = statusFailed;
- }
- }
- }
-
- return bytesConsumed;
-}
-
-void ProxyHandshake::parseLine ()
-{
- Version1 p;
-
- bool success = p.parse (m_buffer.getCharPointer (), m_buffer.length ());
-
- if (success)
- {
- m_endpoints = p.endpoints;
- m_status = statusOk;
- }
- else
- {
- m_status = statusFailed;
- }
-}
-
-int ProxyHandshake::indexOfFirstNonNumber (String const& input)
-{
- bassert (input.length () > 0);
-
- int i = 0;
- for (; i < input.length (); ++i)
- {
- if (! CharacterFunctions::isDigit (input [i]))
- break;
- }
-
- return i;
-}
-
-bool ProxyHandshake::chop (String const& what, String& input)
-{
- if (input.startsWith (what))
- {
- input = input.substring (what.length ());
-
- return true;
- }
-
- return false;
-}
-
-bool ProxyHandshake::chopUInt (int* value, int limit, String& input)
-{
- if (input.length () <= 0)
- return false;
-
- String const s = input.substring (0, indexOfFirstNonNumber (input));
-
- if (s.length () <= 0)
- return false;
-
- int const n = s.getIntValue ();
-
- // Leading zeroes disallowed as per spec, to prevent confusion with octal
- if (String (n) != s)
- return false;
-
- if (n < 0 || n > limit)
- return false;
-
- input = input.substring (s.length ());
-
- *value = n;
-
- return true;
-}
-
-//------------------------------------------------------------------------------
-
-/*
-
-steps:
-
-Proxy protocol lets us filter attackers by learning the source ip and port
-
-1. Determine if we should use the proxy on a connection
- - Port just for proxy protocol connections
- - Filter on source IPs
-
-2. Read a line from the connection to get the proxy information
-
-3. Parse the line (human or binary?)
-
-4. Code Interface to retrieve proxy information (ip/port) on connection
-
-*/
-
-ProxyHandshake::Version1::Version1 ()
-{
-}
-
-bool ProxyHandshake::IPv4::Addr::chop (String& input)
-{
- if (!ProxyHandshake::chopUInt (&a, 255, input))
- return false;
-
- if (!ProxyHandshake::chop (".", input))
- return false;
-
- if (!ProxyHandshake::chopUInt (&b, 255, input))
- return false;
-
- if (!ProxyHandshake::chop (".", input))
- return false;
-
- if (!ProxyHandshake::chopUInt (&c, 255, input))
- return false;
-
- if (!ProxyHandshake::chop (".", input))
- return false;
-
- if (!ProxyHandshake::chopUInt (&d, 255, input))
- return false;
-
- return true;
-}
-
-bool ProxyHandshake::Version1::parse (void const* headerData, size_t headerBytes)
-{
- String input (static_cast (headerData), headerBytes);
-
- if (input.length () < 2)
- return false;
-
- if (! input.endsWith ("\r\n"))
- return false;
-
- input = input.dropLastCharacters (2);
-
- if (! ProxyHandshake::chop ("PROXY ", input))
- return false;
-
- if (ProxyHandshake::chop ("UNKNOWN", input))
- {
- endpoints.proto = protoUnknown;
-
- input = "";
- }
- else
- {
- if (ProxyHandshake::chop ("TCP4 ", input))
- {
- endpoints.proto = protoTcp4;
-
- if (! endpoints.ipv4.sourceAddr.chop (input))
- return false;
-
- if (! ProxyHandshake::chop (" ", input))
- return false;
-
- if (! endpoints.ipv4.destAddr.chop (input))
- return false;
-
- if (! ProxyHandshake::chop (" ", input))
- return false;
-
- if (! ProxyHandshake::chopUInt (&endpoints.ipv4.sourcePort, 65535, input))
- return false;
-
- if (! ProxyHandshake::chop (" ", input))
- return false;
-
- if (! ProxyHandshake::chopUInt (&endpoints.ipv4.destPort, 65535, input))
- return false;
- }
- else if (ProxyHandshake::chop ("TCP6 ", input))
- {
- endpoints.proto = protoTcp6;
-
- //bassertfalse;
-
- return false;
- }
- else
- {
- return false;
- }
- }
-
- // Can't have anything extra between the last port number and the CRLF
- if (input.length () > 0)
- return false;
-
- return true;
-}
-
-//------------------------------------------------------------------------------
-
-class ProxyHandshakeTests : public UnitTest
-{
-public:
- ProxyHandshakeTests () : UnitTest ("ProxyHandshake", "beast")
- {
- }
-
- static std::string goodIpv4 ()
- {
- return "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; // 56 chars
- }
-
- static std::string goodIpv6 ()
- {
- return "PROXY TCP6 fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
- //1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 4 (104 chars)
- }
-
- static std::string goodUnknown ()
- {
- return "PROXY UNKNOWN\r\n";
- }
-
- static std::string goodUnknownBig ()
- {
- return "PROXY UNKNOWN fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
- //1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 7 (107 chars)
- }
-
- void testHandshake (std::string const& s, bool shouldSucceed)
- {
- if (s.size () > 1)
- {
- ProxyHandshake h (true);
-
- expect (h.getStatus () == ProxyHandshake::statusHandshake);
-
- for (std::size_t i = 0; i < s.size () && h.getStatus () == ProxyHandshake::statusHandshake ; ++i)
- {
- std::size_t const bytesConsumed = h.feed (& s[i], 1);
-
- if (i != s.size () - 1)
- expect (h.getStatus () == ProxyHandshake::statusHandshake);
-
- expect (bytesConsumed == 1);
- }
-
- if (shouldSucceed)
- {
- expect (h.getStatus () == ProxyHandshake::statusOk);
- }
- else
- {
- expect (h.getStatus () == ProxyHandshake::statusFailed);
- }
- }
- else
- {
- bassertfalse;
- }
- }
-
- void testVersion1String (std::string const& s, bool shouldSucceed)
- {
- ProxyHandshake::Version1 p;
-
- if (shouldSucceed)
- {
- expect (p.parse (s.c_str (), s.size ()));
- }
- else
- {
- unexpected (p.parse (s.c_str (), s.size ()));
- }
-
- for (std::size_t i = 1; i < s.size () - 1; ++i)
- {
- String const partial = String (s).dropLastCharacters (i);
- std::string ss (partial.toStdString ());
-
- expect (! p.parse (ss.c_str (), ss.size ()));
- }
-
- testHandshake (s, shouldSucceed);
- }
-
- void testVersion1 ()
- {
- beginTestCase ("version1");
-
- testVersion1String (goodIpv4 (), true);
- testVersion1String (goodIpv6 (), false);
- testVersion1String (goodUnknown (), true);
- testVersion1String (goodUnknownBig (), true);
- }
-
- void runTest ()
- {
- testVersion1 ();
- }
-};
-
-static ProxyHandshakeTests proxyHandshakeTests;
diff --git a/modules/beast_asio/handshake/beast_ProxyHandshake.h b/modules/beast_asio/handshake/beast_ProxyHandshake.h
deleted file mode 100644
index eea2e480d..000000000
--- a/modules/beast_asio/handshake/beast_ProxyHandshake.h
+++ /dev/null
@@ -1,164 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of Beast: https://github.com/vinniefalco/Beast
- Copyright 2013, Vinnie Falco
-
- 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_PROXYYHANDSHAKE_H_INCLUDED
-#define BEAST_PROXYYHANDSHAKE_H_INCLUDED
-
-/** PROXY protocol handshake state machine.
-
- The PROXY Protocol:
- http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
-*/
-class ProxyHandshake
-{
-public:
- /** Status of the handshake state machine. */
- enum Status
- {
- statusNone, // No handshake expected
- statusHandshake, // Handshake in progress
- statusFailed, // Handshake failed
- statusOk, // Handshake succeeded
- };
-
- enum Proto
- {
- protoTcp4,
- protoTcp6,
- protoUnknown
- };
-
- /** PROXY information for IPv4 families. */
- struct IPv4
- {
- struct Addr
- {
- int a;
- int b;
- int c;
- int d;
-
- bool chop (String& input);
- };
-
- Addr sourceAddr;
- Addr destAddr;
- int sourcePort;
- int destPort;
- };
-
- /** PROXY information for IPv6 families. */
- struct IPv6
- {
- struct Addr
- {
- int a;
- int b;
- int c;
- int d;
- };
-
- Addr sourceAddr;
- Addr destAddr;
- int sourcePort;
- int destPort;
- };
-
- /** Fully decoded PROXY information. */
- struct Endpoints
- {
- Endpoints ()
- : proto (protoUnknown)
- {
- }
-
- Proto proto;
- IPv4 ipv4; // valid if proto == protoTcp4
- IPv6 ipv6; // valid if proto == protoTcp6;
- };
-
- //--------------------------------------------------------------------------
-
- /** Parser for PROXY version 1. */
- struct Version1
- {
- enum
- {
- // Maximum input buffer size needed, including a null
- // terminator, as per the PROXY protocol specification.
- maxBufferBytes = 108
- };
-
- Endpoints endpoints;
-
- Version1 ();
-
- /** Parse the header.
- @param rawHeader a pointer to the header data
- @return `true` If it was parsed successfully.
- */
- bool parse (void const* headerData, size_t headerBytes);
- };
-
- //--------------------------------------------------------------------------
-
- /** Create the handshake state.
- If a handshake is expected, then it is required.
- @param wantHandshake `false` to skip handshaking.
- */
- explicit ProxyHandshake (bool expectHandshake = false);
-
- ~ProxyHandshake ();
-
- inline Status getStatus () const noexcept
- {
- return m_status;
- }
-
- inline Endpoints const& getEndpoints () const noexcept
- {
- return m_endpoints;
- };
-
- /** Feed the handshaking state engine.
- @return The number of bytes consumed in the input buffer.
- */
- std::size_t feed (void const* inputBuffer, std::size_t inputBytes);
-
- // Utility functions used by parsers
- static int indexOfFirstNonNumber (String const& input);
- static bool chop (String const& what, String& input);
- static bool chopUInt (int* value, int limit, String& input);
-
-private:
- void parseLine ();
-
-private:
- enum
- {
- maxVersion1Bytes = 107 // including crlf, not including null term
- };
-
- Status m_status;
- String m_buffer;
- bool m_gotCR;
- Endpoints m_endpoints;
-};
-
-#endif
diff --git a/modules/beast_asio/tests/beast_TestPeerLogicProxyClient.cpp b/modules/beast_asio/tests/beast_TestPeerLogicProxyClient.cpp
index 1f9a5ae81..e7a438d1d 100644
--- a/modules/beast_asio/tests/beast_TestPeerLogicProxyClient.cpp
+++ b/modules/beast_asio/tests/beast_TestPeerLogicProxyClient.cpp
@@ -24,7 +24,7 @@ TestPeerLogicProxyClient::TestPeerLogicProxyClient (Socket& socket)
void TestPeerLogicProxyClient::on_pre_handshake ()
{
- ProxyHandshake h;
+ //ProxyHandshakeParser h;
static std::string line (
"PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"