diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index 1001acc0ec..3fab76e0d8 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -84,11 +84,21 @@ + + + + + + + + + + @@ -97,7 +107,6 @@ - @@ -350,6 +359,12 @@ true true + + true + true + true + true + true true @@ -361,6 +376,54 @@ true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true true @@ -373,12 +436,6 @@ true true - - true - true - true - true - true true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 7c2f61e5db..a4a31b7aaa 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -176,6 +176,9 @@ {c0724499-ab69-40c3-90e2-65242dbd2eaa} + + {f7252567-a5bb-4be2-bbd0-c9d9b62298de} + @@ -989,12 +992,39 @@ beast_asio\protocol - - beast_asio\protocol - beast_core\functional + + beast_asio\basics + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + @@ -1483,8 +1513,32 @@ beast_asio\protocol - - beast_asio\protocol + + beast_asio\basics + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http + + + beast_asio\http diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.cpp b/Subtrees/beast/modules/beast_asio/beast_asio.cpp index 4bb4c2b0d3..6301c1c2e6 100644 --- a/Subtrees/beast/modules/beast_asio/beast_asio.cpp +++ b/Subtrees/beast/modules/beast_asio/beast_asio.cpp @@ -28,6 +28,7 @@ namespace beast #include "async/SharedHandler.cpp" +#include "basics/ContentBodyBuffer.cpp" #include "basics/PeerRole.cpp" #include "basics/SSLContext.cpp" @@ -37,7 +38,15 @@ namespace beast #include "protocol/HandshakeDetectLogicPROXY.cpp" # include "parsehttp/http_parser.h" -#include "protocol/UniformResourceLocator.cpp" +# include "http/HTTPParserImpl.h" +#include "http/HTTPParser.cpp" +#include "http/UniformResourceLocator.cpp" +#include "http/HTTPClientType.cpp" +#include "http/HTTPField.cpp" +#include "http/HTTPHeaders.cpp" +#include "http/HTTPMessage.cpp" +#include "http/HTTPResponse.cpp" +#include "http/HTTPVersion.cpp" #include "tests/PeerTest.cpp" #include "tests/TestPeerBasics.cpp" diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.h b/Subtrees/beast/modules/beast_asio/beast_asio.h index 5ce86e8cbb..3ff63dac6f 100644 --- a/Subtrees/beast/modules/beast_asio/beast_asio.h +++ b/Subtrees/beast/modules/beast_asio/beast_asio.h @@ -63,7 +63,8 @@ namespace beast # include "async/ComposedAsyncOperation.h" #include "async/SharedHandlerAllocator.h" -#include "basics/BufferType.h" +# include "basics/BufferType.h" +#include "basics/ContentBodyBuffer.h" #include "basics/FixedInputBuffer.h" #include "basics/PeerRole.h" #include "basics/SSLContext.h" @@ -73,6 +74,15 @@ namespace beast # include "sockets/SocketWrapper.h" #include "sockets/SocketWrapperStrand.h" +# include "http/HTTPVersion.h" +# include "http/HTTPField.h" +# include "http/HTTPHeaders.h" +# include "http/HTTPMessage.h" +# include "http/HTTPResponse.h" +# include "http/HTTPParser.h" +# include "http/UniformResourceLocator.h" +#include "http/HTTPClientType.h" + # include "protocol/InputParser.h" # include "protocol/HandshakeDetectLogic.h" #include "protocol/HandshakeDetectLogicPROXY.h" @@ -80,7 +90,6 @@ namespace beast #include "protocol/HandshakeDetectLogicSSL3.h" #include "protocol/HandshakeDetector.h" #include "protocol/PrefilledReadStream.h" -#include "protocol/UniformResourceLocator.h" #include "tests/TestPeerBasics.h" #include "tests/TestPeer.h" diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp new file mode 100644 index 0000000000..143b19fdbe --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp @@ -0,0 +1,838 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +class HTTPClientType : public HTTPClientBase, public Uncopyable +{ +private: + using HTTPClientBase::Listener; + + typedef boost::system::error_code error_code; + + class ListenerHandler + { + public: + ListenerHandler () + : m_owner (nullptr) + , m_listener (nullptr) + { + } + + ListenerHandler (HTTPClientType* owner, Listener* listener = nullptr) + : m_owner (owner) + , m_listener (listener) + { + } + + ListenerHandler (ListenerHandler const& other) + : m_owner (other.m_owner) + , m_listener (other.m_listener) + { + } + + ListenerHandler& operator= (ListenerHandler const& other) + { + m_owner = other.m_owner; + m_listener = other.m_listener; + return *this; + } + + void operator() (error_code) + { + if (m_listener != nullptr) + m_listener->onHTTPRequestComplete ( + *m_owner, m_owner->result ()); + } + + private: + HTTPClientType* m_owner; + Listener* m_listener; + }; + +public: + //-------------------------------------------------------------------------- + + HTTPClientType ( + double timeoutSeconds, + std::size_t messageLimitBytes, + std::size_t bufferSize) + : m_timeoutSeconds (timeoutSeconds) + , m_messageLimitBytes (messageLimitBytes) + , m_bufferSize (bufferSize) + { + } + + ~HTTPClientType () + { + m_async_op = nullptr; + } + + Result const& result () const + { + return m_result; + } + + Result const& get (UniformResourceLocator const& url) + { + boost::asio::io_service io_service; + async_get (io_service, nullptr, url); + io_service.run (); + cancel (); + return result (); + } + + //-------------------------------------------------------------------------- + + void async_get (boost::asio::io_service& io_service, Listener* listener, + UniformResourceLocator const& url) + { + async_get (io_service, url, ListenerHandler (this, listener)); + } + + // Handler signature is void(error_code) + // + template + void async_get (boost::asio::io_service& io_service, + UniformResourceLocator const& url, + BOOST_ASIO_MOVE_ARG(Handler) handler) + { + async_get (io_service, url, newErrorHandler ( + BOOST_ASIO_MOVE_CAST(Handler)(handler))); + } + + void async_get (boost::asio::io_service& io_service, + UniformResourceLocator const& url, SharedHandlerPtr handler) + { + // This automatically dispatches + m_async_op = new AsyncGetOp ( + *this, io_service, url, handler, + m_timeoutSeconds, m_messageLimitBytes, m_bufferSize); + } + + void cancel () + { + if (m_async_op != nullptr) + { + m_async_op->cancel (); + m_async_op = nullptr; + } + } + +private: + //-------------------------------------------------------------------------- + + /** Helper function to get a const_buffer from a String. */ + static boost::asio::const_buffers_1 stringBuffer (String const& s) + { + return boost::asio::const_buffers_1 (s.getCharPointer (), s.length ()); + } + + /** Helper function to fill out a Query from a URL. */ + template + static Query queryFromURL (UniformResourceLocator const& url) + { + if (url.port () != 0) + { + return Query ( + url.host().toStdString(), + url.port_string().toStdString(), + Query::numeric_service); + } + + return Query ( + url.host().toStdString(), + url.scheme().toStdString()); + } + + //-------------------------------------------------------------------------- + + class AsyncGetOp : public ComposedAsyncOperation + { + private: + typedef boost::asio::ip::tcp Protocol; + typedef boost::system::error_code error_code; + + typedef Protocol::resolver resolver; + typedef resolver::query query; + typedef resolver::iterator iterator; + typedef iterator::value_type resolver_entry; + typedef Protocol::socket socket; + + //---------------------------------------------------------------------- + + enum State + { + stateStart, + stateResolveComplete, + stateConnectComplete, + stateHandshakeComplete, + stateWriteComplete, + stateShutdownComplete + }; + + //---------------------------------------------------------------------- + + struct TimerHandler : SharedHandlerPtr + { + explicit TimerHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + void operator() (error_code const& ec) + { + m_owner->timerCompletion (ec); + } + + AsyncGetOp* m_owner; + }; + + //---------------------------------------------------------------------- + + public: + AsyncGetOp (HTTPClientType& owner, + boost::asio::io_service& io_service, + UniformResourceLocator const& url, + SharedHandlerPtr const& handler, + double timeoutSeconds, + std::size_t messageLimitBytes, + std::size_t bufferSize) + : ComposedAsyncOperation (sizeof (*this), handler) + , m_owner (owner) + , m_io_service (io_service) + , m_strand (m_io_service) + , m_url (url) + , m_handler (handler) + , m_timer (io_service) + , m_resolver (io_service) + , m_socket (io_service) + , m_context (boost::asio::ssl::context::sslv23) + , m_buffer (bufferSize) + , m_parser (HTTPParser::typeResponse) + , m_timer_canceled (false) + , m_timer_expired (false) + , m_messageLimitBytes (messageLimitBytes) + , m_bytesReceived (0) + { + m_context.set_default_verify_paths (); + m_context.set_options ( + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use | + boost::asio::ssl::context::default_workarounds); + //m_context.set_verify_mode (boost::asio::ssl::verify_peer); + + if (timeoutSeconds > 0) + { + m_timer.expires_from_now ( + boost::posix_time::milliseconds ( + long (timeoutSeconds * 1000))); + + ++m_io_pending; + m_timer.async_wait (TimerHandler (this)); + } + + // Count as pending i/o + ++m_io_pending; + m_io_service.dispatch ( + m_strand.wrap (StartHandler (this))); + } + + ~AsyncGetOp () + { + } + + // Cancel all pending I/O, if any, and block until + // there are no more completion handler calls pending. + // + void cancel () + { + cancel_all (); + m_done.wait (); + } + + private: + //---------------------------------------------------------------------- + + // Counts a pending i/o as canceled + // + void cancel_io () + { + bassert (m_io_pending.get () > 0); + if (--m_io_pending == 0) + m_done.signal (); + } + + // Cancels the deadline timer. + // + void cancel_timer () + { + m_timer_canceled = true; + error_code ec; + m_timer.cancel (ec); + } + + // Called to notify the original handler the operation is complete. + // + void complete (error_code const& ec) + { + m_owner.m_result.error = ec; + + cancel_timer (); + + bassert (m_io_pending.get () > 0); + + cancel_io (); + + // We call the handler directly since we know + // we are already in the right context, and + // because we need to do some things afterwards. + // + m_handler->operator() (ec); + } + + // Called every time an async operation completes. + // The return value indicates if the handler should + // stop additional activity and return immediately. + // + bool io_complete (error_code const& ec) + { + if (m_timer_expired || + ec == boost::asio::error::operation_aborted) + { + cancel_io (); + return true; + } + else if (ec != 0 && ec != boost::asio::error::eof) + { + complete (ec); + return true; + } + + return false; + } + + // Cancels/closes all i/o objects. + // + void cancel_all () + { + cancel_timer (); + m_resolver.cancel (); + error_code ec; + m_socket.close (ec); + } + + // Called when the deadline timer expires or is canceled. + // + void timerCompletion (error_code ec) + { + if (ec == boost::asio::error::operation_aborted) + { + bassert (m_timer_canceled); + return cancel_io (); + } + + check_invariant (ec == 0); + + // Handle the case where the timer completion has already + // been queued for dispatch but we have finished the operation + // and queued the completion handler for dispatch. + // + if (! m_timer_canceled) + { + m_timer_expired = true; + + ec = error_code (boost::asio::error::timed_out, + boost::asio::error::get_system_category ()); + + complete (ec); + + io_complete (ec); + + m_resolver.cancel (); + m_socket.close (ec); + } + else + { + cancel_io (); + } + } + + //---------------------------------------------------------------------- + + struct StartHandler : SharedHandlerPtr + { + explicit StartHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() () + { + m_owner->start_complete (); + } + + AsyncGetOp* m_owner; + }; + + struct ResolveHandler : SharedHandlerPtr + { + explicit ResolveHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec, iterator iter) + { + m_owner->resolve_complete (ec, iter); + } + + AsyncGetOp* m_owner; + }; + + struct ConnectHandler : SharedHandlerPtr + { + explicit ConnectHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec) + { + m_owner->connect_complete (ec); + } + + AsyncGetOp* m_owner; + }; + + struct HandshakeHandler : SharedHandlerPtr + { + explicit HandshakeHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec) + { + m_owner->handshake_complete (ec); + } + + AsyncGetOp* m_owner; + }; + + struct WriteHandler : SharedHandlerPtr + { + explicit WriteHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec, std::size_t bytes_transferred) + { + m_owner->write_complete (ec, bytes_transferred); + } + + AsyncGetOp* m_owner; + }; + + struct ReadHandler : SharedHandlerPtr + { + explicit ReadHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec, std::size_t bytes_transferred) + { + m_owner->read_complete (ec, bytes_transferred); + } + + AsyncGetOp* m_owner; + }; + + struct ShutdownHandler : SharedHandlerPtr + { + explicit ShutdownHandler (AsyncGetOp* owner) + : SharedHandlerPtr (owner) + , m_owner (owner) + { + } + + void operator() (error_code const& ec) + { + m_owner->shutdown_complete (ec); + } + + AsyncGetOp* m_owner; + }; + + //---------------------------------------------------------------------- + + void async_read_some () + { + boost::asio::mutable_buffers_1 buf ( + m_buffer.getData (), m_buffer.getSize ()); + + m_stream->async_read_some (buf, + m_strand.wrap (ReadHandler (this))); + } + + // Called when the HTTP parser returns an error + void parse_error () + { + //unsigned char const http_errno (m_parser.error ()); + String const http_errmsg (m_parser.message ()); + + // VFALCO TODO put the parser error in ec + error_code ec ( + boost::system::errc::invalid_argument, + boost::system::system_category ()); + + complete (ec); + } + + // Called to create an error when the message is over the limit + error_code message_limit_error () + { + // VFALCO TODO Make a suitable error code + return error_code ( + boost::system::errc::invalid_argument, + boost::system::system_category ()); + } + + //---------------------------------------------------------------------- + + void start_complete () + { + query q (queryFromURL (m_url)); + m_resolver.async_resolve (q, + m_strand.wrap (ResolveHandler (this))); + } + + void resolve_complete (error_code ec, iterator iter) + { + if (io_complete (ec)) + return; + + resolver_entry const entry (*iter); + m_socket.async_connect (entry.endpoint (), + m_strand.wrap (ConnectHandler (this))); + } + + void connect_complete (error_code ec) + { + if (io_complete (ec)) + return; + + if (m_url.scheme () == "https") + { + typedef boost::asio::ssl::stream ssl_stream; + m_stream = new SocketWrapper (m_socket, m_context); + /* + m_stream->set_verify_mode ( + boost::asio::ssl::verify_peer | + boost::asio::ssl::verify_fail_if_no_peer_cert); + */ + m_stream->async_handshake ( + Socket::client, HandshakeHandler (this)); + return; + } + + m_stream = new SocketWrapper (m_socket); + handshake_complete (ec); + } + + void handshake_complete (error_code ec) + { + if (io_complete (ec)) + return; + + m_get_string = + "GET " + m_url.path() + " HTTP/1.1\r\n" + + "Host: " + m_url.host() + "\r\n" + + "Accept: */*\r\n" + + "Connection: close\r\n\r\n"; + + boost::asio::async_write ( + *m_stream, stringBuffer (m_get_string), + m_strand.wrap (WriteHandler (this))); + ++m_io_pending; + + async_read_some (); + } + + void write_complete (error_code ec, std::size_t) + { + if (io_complete (ec)) + return; + + if (! m_stream->needs_handshake ()) + { + m_socket.shutdown (socket::shutdown_send, ec); + if (ec != 0) + return complete (ec); + } + + // deduct one i/o since we aren't issuing any new one + cancel_io (); + } + + void read_complete (error_code ec, std::size_t bytes_transferred) + { + m_bytesReceived += bytes_transferred; + if (m_bytesReceived > m_messageLimitBytes) + ec = message_limit_error (); + + if (io_complete (ec)) + return; + + std::size_t const bytes_parsed (m_parser.process ( + m_buffer.getData (), bytes_transferred)); + + if (m_parser.error ()) + { + parse_error (); + return; + } + + if (bytes_parsed != bytes_transferred) + { + // VFALCO TODO put an appropriate error in ec + ec = error_code ( + boost::system::errc::invalid_argument, + boost::system::system_category ()); + return complete (ec); + } + + if (ec == boost::asio::error::eof) + { + m_parser.process_eof (); + } + + if (m_parser.finished ()) + { + m_state = stateShutdownComplete; + if (m_stream->needs_handshake ()) + m_stream->async_shutdown (ShutdownHandler (this)); + else + shutdown_complete (error_code ()); + return; + } + + async_read_some (); + } + + void shutdown_complete (error_code ec) + { + if (io_complete (ec)) + return; + + m_owner.m_result.response = m_parser.response (); + if (ec == boost::asio::error::eof) + ec = error_code (); + + return complete (ec); + } + + private: + WaitableEvent m_done; + Atomic m_io_pending; + HTTPClientType& m_owner; + boost::asio::io_service& m_io_service; + boost::asio::io_service& m_strand; + UniformResourceLocator m_url; + SharedHandlerPtr m_handler; + boost::asio::deadline_timer m_timer; + resolver m_resolver; + socket m_socket; + ScopedPointer m_stream; + boost::asio::ssl::context m_context; + MemoryBlock m_buffer; + State m_state; + HTTPParser m_parser; + String m_get_string; + bool m_timer_canceled; + bool m_timer_expired; + std::size_t m_messageLimitBytes; + std::size_t m_bytesReceived; + }; + + double m_timeoutSeconds; + std::size_t m_messageLimitBytes; + std::size_t m_bufferSize; + boost::asio::io_service m_io_service; + SharedPtr m_async_op; + Result m_result; +}; + +//------------------------------------------------------------------------------ + +HTTPClientBase* HTTPClientBase::New ( + double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize) +{ + ScopedPointer object (new HTTPClientType + (timeoutSeconds, messageLimitBytes, bufferSize)); + return object.release (); +} + +//------------------------------------------------------------------------------ + +class HTTPClientTests + : public UnitTest + , public HTTPClientBase::Listener +{ +public: + typedef boost::system::error_code error_code; + + //-------------------------------------------------------------------------- + + class IoServiceThread : protected Thread + { + public: + explicit IoServiceThread (String name = "io_service") + : Thread (name) + { + } + + ~IoServiceThread () + { + join (); + } + + boost::asio::io_service& get_io_service () + { + return m_service; + } + + void start () + { + startThread (); + } + + void join () + { + this->waitForThreadToExit (); + } + + private: + void run () + { + m_service.run (); + } + + private: + boost::asio::io_service m_service; + }; + + //-------------------------------------------------------------------------- + + void log (HTTPMessage const& m) + { + for (std::size_t i = 0; i < m.headers().size(); ++i) + { + HTTPField const f (m.headers()[i]); + String s; + s = "[ '" + f.name() + + "' , '" + f.value() + "' ]"; + logMessage (s); + } + } + + void log (HTTPClientBase::Result const& result) + { + if (result.error != 0) + { + logMessage (String ( + "HTTPClient error: '" + result.error.message() + "'")); + } + else if (! result.response.empty ()) + { + logMessage (String ("Status: ") + + String::fromNumber (result.response->status())); + + log (*result.response); + } + else + { + logMessage ("HTTPClient: no response"); + } + } + + //-------------------------------------------------------------------------- + + void onHTTPRequestComplete ( + HTTPClientBase const&, HTTPClientBase::Result const& result) + { + log (result); + } + + void testSync (String const& s, double timeoutSeconds) + { + ScopedPointer client ( + HTTPClientBase::New (timeoutSeconds)); + + log (client->get (ParsedURL (s).url ())); + } + + void testAsync (String const& s, double timeoutSeconds) + { + IoServiceThread t; + ScopedPointer client ( + HTTPClientBase::New (timeoutSeconds)); + + client->async_get (t.get_io_service (), this, + ParsedURL (s).url ()); + + t.start (); + t.join (); + } + + //-------------------------------------------------------------------------- + + void runTest () + { + beginTestCase ("HTTPClient::get"); + + testSync ( + "http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html", + 5); + + testAsync ( + "http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html", + 5); + + testAsync ( + "https://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html", + 5); + + pass (); + } + + HTTPClientTests () : UnitTest ("HttpClient", "beast", runManual) + { + } +}; + +static HTTPClientTests httpClientTests; + + diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h new file mode 100644 index 0000000000..5922813f38 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPCLIENTTYPE_H_INCLUDED +#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED + +class HTTPClientBase +{ +public: + struct Result + { + boost::system::error_code error; + SharedPtr response; + }; + + class Listener + { + public: + virtual void onHTTPRequestComplete ( + HTTPClientBase const& client, + Result const& result) = 0; + }; + + static HTTPClientBase* New ( + double timeoutSeconds = 30, + std::size_t messageLimitBytes = 256 * 1024, + std::size_t bufferSize = 16 * 1024); + + virtual ~HTTPClientBase () { } + + virtual Result const& result () const = 0; + + virtual Result const& get ( + UniformResourceLocator const& url) = 0; + + virtual void async_get (boost::asio::io_service& io_service, + Listener* listener, + UniformResourceLocator const& url) = 0; + + /** Cancel any pending asynchronous operations. + This must be called before destroying the container if there are + any pending asynchronous operations. This routine does nothing if + there are no pending operations. The call will block until all + pending i/o is canceled. + */ + virtual void cancel () = 0; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp new file mode 100644 index 0000000000..d026a55bcf --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPField::HTTPField () +{ +} + +HTTPField::HTTPField (String name_, String value_) + : m_name (name_) + , m_value (value_) +{ +} + +HTTPField::HTTPField (HTTPField const& other) + : m_name (other.m_name) + , m_value (other.m_value) +{ +} + +HTTPField& HTTPField::operator= (HTTPField const& other) +{ + m_name = other.m_name; + m_value = other.m_value; + return *this; +} + +String HTTPField::name () const +{ + return m_name; +} + +String HTTPField::value () const +{ + return m_value; +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPField.h b/Subtrees/beast/modules/beast_asio/http/HTTPField.h new file mode 100644 index 0000000000..048f71c1ea --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPField.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPFIELD_H_INCLUDED +#define BEAST_ASIO_HTTPFIELD_H_INCLUDED + +/** A single header. + The header is a field/value pair. + Time complexity of copies is constant. +*/ +class HTTPField +{ +public: + HTTPField (); + HTTPField (String name_, String value_); + HTTPField (HTTPField const& other); + HTTPField& operator= (HTTPField const& other); + String name () const; + String value () const; + +private: + String m_name; + String m_value; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp new file mode 100644 index 0000000000..f28f5113f2 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPHeaders::HTTPHeaders () +{ +} + +HTTPHeaders::HTTPHeaders (StringPairArray& fields) +{ + m_fields.swapWith (fields); +} + +HTTPHeaders::HTTPHeaders (StringPairArray const& fields) + : m_fields (fields) +{ +} + +HTTPHeaders::HTTPHeaders (HTTPHeaders const& other) + : m_fields (other.m_fields) +{ +} + +HTTPHeaders& HTTPHeaders::operator= (HTTPHeaders const& other) +{ + m_fields = other.m_fields; + return *this; +} + +bool HTTPHeaders::empty () const +{ + return m_fields.size () == 0; +} + +std::size_t HTTPHeaders::size () const +{ + return m_fields.size (); +} + +HTTPField HTTPHeaders::at (std::size_t index) const +{ + return HTTPField (m_fields.getAllKeys () [index], + m_fields.getAllValues () [index]); +} + +HTTPField HTTPHeaders::operator[] (std::size_t index) const +{ + return at (index); +} + +String HTTPHeaders::get (String const& field) const +{ + return m_fields [field]; +} + +String HTTPHeaders::operator[] (String const& field) const +{ + return get (field); +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h new file mode 100644 index 0000000000..d2a1a4cad1 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPHEADERS_H_INCLUDED +#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED + +/** A set of HTTP headers. */ +class HTTPHeaders +{ +public: + /** Construct an empty set of headers. */ + HTTPHeaders (); + + /** Construct headers taking ownership of a field array. + The callers value is overwritten. + */ + HTTPHeaders (StringPairArray& fields); + + /** Construct a copy of headers from an array.*/ + HTTPHeaders (StringPairArray const& fields); + + /** Construct a copy of headers. */ + HTTPHeaders (HTTPHeaders const& other); + + /** Assign a copy of headers. */ + HTTPHeaders& operator= (HTTPHeaders const& other); + + /** Returns `true` if the container is empty. */ + bool empty () const; + + /** Returns the number of fields in the container. */ + std::size_t size () const; + + /** Random access to fields by index. */ + /** @{ */ + HTTPField at (std::size_t index) const; + HTTPField operator[] (std::size_t index) const; + /** @} */ + + /** Associative access to fields by name. + If the field is not present, an empty string is returned. + */ + /** @{ */ + String get (String const& field) const; + String operator[] (String const& field) const; + /** @} */ + +private: + StringPairArray m_fields; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp new file mode 100644 index 0000000000..aeb743843e --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPMessage::HTTPMessage (HTTPVersion const& version_, + StringPairArray& fields, + ContentBodyBuffer& body) + : m_version (version_) + , m_headers (fields) +{ + m_body.swapWith (body); +} + +HTTPVersion const& HTTPMessage::version () const +{ + return m_version; +} + +HTTPHeaders const& HTTPMessage::headers () const +{ + return m_headers; +} + +ContentBodyBuffer const& HTTPMessage::body () const +{ + return m_body; +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h new file mode 100644 index 0000000000..549d7d43c1 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPMESSAGE_H_INCLUDED +#define BEAST_ASIO_HTTPMESSAGE_H_INCLUDED + +/** A complete HTTP message. + + This provides the information common to all HTTP messages, including + the version, content body, and headers. + Derived classes provide the request or response specific data. + + Because a single HTTP message can be a fairly expensive object to + make copies of, this is a SharedObject. + + @see HTTPRequest, HTTPResponse +*/ +class HTTPMessage : public SharedObject +{ +public: + /** Construct the common HTTP message parts from values. + Ownership of the fields and body parameters are + transferred from the caller. + */ + HTTPMessage (HTTPVersion const& version_, + StringPairArray& fields, + ContentBodyBuffer& body); + + /** Returns the HTTP version of this message. */ + HTTPVersion const& version () const; + + /** Returns the set of HTTP headers associated with this message. */ + HTTPHeaders const& headers () const; + + /** Returns the content-body. */ + ContentBodyBuffer const& body () const; + +private: + HTTPVersion m_version; + HTTPHeaders m_headers; + ContentBodyBuffer m_body; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp new file mode 100644 index 0000000000..5ca1c9ed83 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPParser::HTTPParser (Type type) + : m_type (type) + , m_impl (new HTTPParserImpl ( + (type == typeResponse) ? HTTP_RESPONSE : HTTP_REQUEST)) +{ +} + +HTTPParser::~HTTPParser () +{ +} + +unsigned char HTTPParser::error () const +{ + return m_impl->http_errno (); +} + +String HTTPParser::message () const +{ + return m_impl->http_errno_message (); +} + +std::size_t HTTPParser::process (void const* buf, std::size_t bytes) +{ + std::size_t const bytes_used (m_impl->process (buf, bytes)); + + if (m_impl->finished ()) + { + if (m_type == typeResponse) + { + m_response = new HTTPResponse ( + m_impl->version (), + m_impl->fields (), + m_impl->body (), + m_impl->status_code ()); + } + else + { + // m_request = new HTTPRequest ( + } + } + + return bytes_used; +} + +void HTTPParser::process_eof () +{ + m_impl->process_eof (); +} + +bool HTTPParser::finished () const +{ + return m_impl->finished(); +} + +SharedPtr const& HTTPParser::response () +{ + bassert (m_type == typeResponse); + + return m_response; +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParser.h b/Subtrees/beast/modules/beast_asio/http/HTTPParser.h new file mode 100644 index 0000000000..d6e3a287e2 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPParser.h @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPPARSER_H_INCLUDED +#define BEAST_ASIO_HTTPPARSER_H_INCLUDED + +class HTTPParserImpl; + +/** A parser for HTTPRequest and HTTPResponse objects. */ +class HTTPParser +{ +public: + enum Type + { + typeRequest, + typeResponse + }; + + /** Construct a new parser for the specified HTTPMessage type. */ + explicit HTTPParser (Type type); + + /** Destroy the parser. */ + ~HTTPParser (); + + /** Returns a non zero error code if parsing fails. */ + unsigned char error () const; + + /** Returns the error message text when error is non zero. */ + String message () const; + + /** Parse the buffer and return the amount used. + Typically it is an error when this returns less than + the amount passed in. + */ + std::size_t process (void const* buf, std::size_t bytes); + + /** Notify the parser that eof was received. + */ + void process_eof (); + + /** Returns `true` when parsing is successful and complete. */ + bool finished () const; + + /** Return the HTTPResponse object produce from the parsing. + Only valid after finished returns `true`. + */ + SharedPtr const& response (); + + //SharedPtr const& request (); + +private: + Type m_type; + ScopedPointer m_impl; + SharedPtr m_response; + //SharedPtr m_request; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h b/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h new file mode 100644 index 0000000000..c01fd58114 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h @@ -0,0 +1,256 @@ +//------------------------------------------------------------------------------ +/* + 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_HTTPPARSERIMPL_H_INCLUDED +#define BEAST_HTTPPARSERIMPL_H_INCLUDED + +class HTTPParserImpl +{ +public: + enum + { + stringReservation = 256 + }; + + explicit HTTPParserImpl (enum http_parser_type type) + : m_finished (false) + , m_was_value (false) + { + m_settings.on_message_begin = &HTTPParserImpl::on_message_begin; + m_settings.on_url = &HTTPParserImpl::on_url; + m_settings.on_status_complete = &HTTPParserImpl::on_status_complete; + m_settings.on_header_field = &HTTPParserImpl::on_header_field; + m_settings.on_header_value = &HTTPParserImpl::on_header_value; + m_settings.on_headers_complete = &HTTPParserImpl::on_headers_complete; + m_settings.on_body = &HTTPParserImpl::on_body; + m_settings.on_message_complete = &HTTPParserImpl::on_message_complete; + + m_field.reserve (stringReservation); + m_value.reserve (stringReservation); + + http_parser_init (&m_parser, type); + m_parser.data = this; + } + + ~HTTPParserImpl () + { + } + + unsigned char error () const + { + return m_parser.http_errno; + } + + String message () const + { + return String (http_errno_name (static_cast < + enum http_errno> (m_parser.http_errno))); + } + + std::size_t process (void const* buf, std::size_t bytes) + { + return http_parser_execute (&m_parser, + &m_settings, static_cast (buf), bytes); + } + + void process_eof () + { + http_parser_execute (&m_parser, &m_settings, nullptr, 0); + } + + bool finished () const + { + return m_finished; + } + + HTTPVersion version () const + { + return HTTPVersion ( + m_parser.http_major, m_parser.http_minor); + } + + // Only for HTTPResponse! + unsigned short status_code () const + { + return m_parser.status_code; + } + + // Only for HTTPRequest! + unsigned char method () const + { + return m_parser.method; + } + + unsigned char http_errno () const + { + return m_parser.http_errno; + } + + String http_errno_message () const + { + return String (http_errno_name ( + static_cast ( + m_parser.http_errno))); + } + + bool upgrade () const + { + return m_parser.upgrade != 0; + } + + StringPairArray& fields () + { + return m_fields; + } + + ContentBodyBuffer& body () + { + return m_body; + } + +private: + void addFieldValue () + { + if (m_field.size () > 0 && m_value.size () > 0) + m_fields.set (m_field, m_value); + m_field.resize (0); + m_value.resize (0); + } + + int onMessageBegin () + { + int ec (0); + return ec; + } + + int onUrl (char const*, std::size_t) + { + int ec (0); + // This is for HTTP Request + return ec; + } + + int onStatusComplete () + { + int ec (0); + return ec; + } + + int onHeaderField (char const* at, std::size_t length) + { + int ec (0); + if (m_was_value) + { + addFieldValue (); + m_was_value = false; + } + m_field.append (at, length); + return ec; + } + + int onHeaderValue (char const* at, std::size_t length) + { + int ec (0); + m_value.append (at, length); + m_was_value = true; + return ec; + } + + int onHeadersComplete () + { + int ec (0); + addFieldValue (); + return ec; + } + + int onBody (char const* at, std::size_t length) + { + m_body.commit (boost::asio::buffer_copy (m_body.prepare (length), + boost::asio::buffer (at, length))); + return 0; + } + + int onMessageComplete () + { + int ec (0); + m_finished = true; + return ec; + } + +private: + static int on_message_begin (http_parser* parser) + { + return static_cast (parser->data)-> + onMessageBegin (); + } + + static int on_url (http_parser* parser, const char *at, size_t length) + { + return static_cast (parser->data)-> + onUrl (at, length); + } + + static int on_status_complete (http_parser* parser) + { + return static_cast (parser->data)-> + onStatusComplete (); + } + + static int on_header_field (http_parser* parser, const char *at, size_t length) + { + return static_cast (parser->data)-> + onHeaderField (at, length); + } + + static int on_header_value (http_parser* parser, const char *at, size_t length) + { + return static_cast (parser->data)-> + onHeaderValue (at, length); + } + + static int on_headers_complete (http_parser* parser) + { + return static_cast (parser->data)-> + onHeadersComplete (); + } + + static int on_body (http_parser* parser, const char *at, size_t length) + { + return static_cast (parser->data)-> + onBody (at, length); + } + + static int on_message_complete (http_parser* parser) + { + return static_cast (parser->data)-> + onMessageComplete (); + } + +private: + bool m_finished; + http_parser_settings m_settings; + http_parser m_parser; + StringPairArray m_fields; + bool m_was_value; + std::string m_field; + std::string m_value; + ContentBodyBuffer m_body; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp new file mode 100644 index 0000000000..7396127b5c --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPResponse::HTTPResponse ( + HTTPVersion const& version_, + StringPairArray& fields, + ContentBodyBuffer& body, + unsigned short status_) + : HTTPMessage (version_, fields, body) + , m_status (status_) +{ +} + +unsigned short HTTPResponse::status () const +{ + return m_status; +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h new file mode 100644 index 0000000000..bb3f89cb11 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPRESPONSE_H_INCLUDED +#define BEAST_ASIO_HTTPRESPONSE_H_INCLUDED + +class HTTPResponse : public HTTPMessage +{ +public: + /** Construct a complete response from values. + Ownership of the fields and body parameters are + transferred from the caller. + */ + HTTPResponse ( + HTTPVersion const& version_, + StringPairArray& fields, + ContentBodyBuffer& body, + unsigned short status_); + + unsigned short status () const; + +private: + unsigned short m_status; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp new file mode 100644 index 0000000000..7fcf4dc5ad --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +HTTPVersion::HTTPVersion () + : m_major (0) + , m_minor (0) +{ +} + +HTTPVersion::HTTPVersion (unsigned short major_, unsigned short minor_) + : m_major (major_) + , m_minor (minor_) +{ +} + +HTTPVersion::HTTPVersion (HTTPVersion const& other) + : m_major (other.m_major) + , m_minor (other.m_minor) +{ +} + +HTTPVersion& HTTPVersion::operator= (HTTPVersion const& other) +{ + m_major = other.m_major; + m_minor = other.m_minor; + return *this; +} + +String HTTPVersion::toString () const +{ + return String::fromNumber (major ()) + "." + + String::fromNumber (minor ()); +} + +unsigned short HTTPVersion::major () const +{ + return m_major; +} + +unsigned short HTTPVersion::minor () const +{ + return m_minor; +} + +bool HTTPVersion::operator== (HTTPVersion const& rhs) const +{ + return (m_major == rhs.m_major) && (m_minor == rhs.m_minor); +} + +bool HTTPVersion::operator!= (HTTPVersion const& rhs) const +{ + return (m_major != rhs.m_major) || (m_minor != rhs.m_minor); +} + +bool HTTPVersion::operator> (HTTPVersion const& rhs) const +{ + return (m_major > rhs.m_major) || + ((m_major == rhs.m_major) && (m_minor > rhs.m_minor)); +} + +bool HTTPVersion::operator>= (HTTPVersion const& rhs) const +{ + return (m_major > rhs.m_major) || + ((m_major == rhs.m_major) && (m_minor >= rhs.m_minor)); +} + +bool HTTPVersion::operator< (HTTPVersion const& rhs) const +{ + return (m_major < rhs.m_major) || + ((m_major == rhs.m_major) && (m_minor < rhs.m_minor)); +} + +bool HTTPVersion::operator<= (HTTPVersion const& rhs) const +{ + return (m_major < rhs.m_major) || + ((m_major == rhs.m_major) && (m_minor <= rhs.m_minor)); +} diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h new file mode 100644 index 0000000000..c3e2a196c3 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +/* + 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_ASIO_HTTPVERSION_H_INCLUDED +#define BEAST_ASIO_HTTPVERSION_H_INCLUDED + +/** The HTTP version. This is the major.minor version number. */ +class HTTPVersion +{ +public: + HTTPVersion (); + HTTPVersion (unsigned short major_, unsigned short minor_); + HTTPVersion (HTTPVersion const& other); + HTTPVersion& operator= (HTTPVersion const& other); + String toString () const; + unsigned short major () const; + unsigned short minor () const; + bool operator== (HTTPVersion const& rhs) const; + bool operator!= (HTTPVersion const& rhs) const; + bool operator> (HTTPVersion const& rhs) const; + bool operator>= (HTTPVersion const& rhs) const; + bool operator< (HTTPVersion const& rhs) const; + bool operator<= (HTTPVersion const& rhs) const; + +private: + unsigned short m_major; + unsigned short m_minor;; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.cpp b/Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.cpp similarity index 100% rename from Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.cpp rename to Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.cpp diff --git a/Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.h b/Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.h similarity index 100% rename from Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.h rename to Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.h