From 2ab1abccba9f97322f1b97be88bbb6a19eadc9da Mon Sep 17 00:00:00 2001 From: Tobias Blomberg Date: Mon, 20 Jul 2020 14:38:24 +0200 Subject: [PATCH] Add chunked mode to http connections --- src/async/ChangeLog | 2 + src/async/core/AsyncHttpServerConnection.cpp | 42 +++++++++++++++++--- src/async/core/AsyncHttpServerConnection.h | 25 +++++++++++- src/versions | 2 +- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/async/ChangeLog b/src/async/ChangeLog index e9383135..19e4ae5d 100644 --- a/src/async/ChangeLog +++ b/src/async/ChangeLog @@ -21,6 +21,8 @@ * Add a signal to the Config class so that one can subscribe to changes in the configuration. +* Chunked mode added to the Async::HttpServerConnection. + 1.6.0 -- 01 Sep 2019 diff --git a/src/async/core/AsyncHttpServerConnection.cpp b/src/async/core/AsyncHttpServerConnection.cpp index 5b0d971f..376bab8d 100644 --- a/src/async/core/AsyncHttpServerConnection.cpp +++ b/src/async/core/AsyncHttpServerConnection.cpp @@ -24,8 +24,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ - - /**************************************************************************** * * System Includes @@ -35,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include /**************************************************************************** @@ -114,7 +113,8 @@ using namespace Async; ****************************************************************************/ HttpServerConnection::HttpServerConnection(size_t recv_buf_len) - : TcpConnection(recv_buf_len), m_state(STATE_DISCONNECTED) + : TcpConnection(recv_buf_len), m_state(STATE_DISCONNECTED), + m_chunked(false) { TcpConnection::sendBufferFull.connect( sigc::mem_fun(*this, &HttpServerConnection::onSendBufferFull)); @@ -125,7 +125,7 @@ HttpServerConnection::HttpServerConnection( int sock, const IpAddress& remote_addr, uint16_t remote_port, size_t recv_buf_len) : TcpConnection(sock, remote_addr, remote_port, recv_buf_len), - m_state(STATE_EXPECT_START_LINE) + m_state(STATE_EXPECT_START_LINE), m_chunked(false) { } /* HttpServerConnection::HttpServerConnection */ @@ -193,6 +193,10 @@ bool HttpServerConnection::write(const Response& res) { os << (*it).first << ": " << (*it).second << "\r\n"; } + if (m_chunked) + { + os << "Transfer-encoding: chunked\r\n"; + } os << "\r\n"; if (res.sendContent()) { @@ -200,8 +204,32 @@ bool HttpServerConnection::write(const Response& res) } //std::cout << "### HttpServerConnection::write:" << std::endl; //std::cout << os.str() << std::endl; - int len = TcpConnection::write(os.str().c_str(), os.str().size()); - return len == static_cast(os.str().size()); + int len = os.str().size(); + return TcpConnection::write(os.str().c_str(), len) == len; +} /* HttpServerConnection::write */ + + +bool HttpServerConnection::write(const char* buf, int len) +{ + assert(len >= 0); + + int ret = -1; + if (m_chunked) + { + std::ostringstream os; + //os << hex << len << ";tg=240;talker=SM0SVX\r\n"; + os << hex << len << "\r\n"; + ret = TcpConnection::write(os.str().c_str(), os.str().size()); + ret += TcpConnection::write(buf, len); + ret += TcpConnection::write("\r\n", 2); + len += os.str().size() + 2; + } + else + { + ret = TcpConnection::write(buf, len); + } + + return ret == len; } /* HttpServerConnection::write */ @@ -412,6 +440,8 @@ const char* HttpServerConnection::codeToString(unsigned code) return "OK"; case 404: return "Not Found"; + case 406: + return "Not Acceptable"; case 501: return "Not Implemented"; default: diff --git a/src/async/core/AsyncHttpServerConnection.h b/src/async/core/AsyncHttpServerConnection.h index 040a79e5..e5767c8a 100644 --- a/src/async/core/AsyncHttpServerConnection.h +++ b/src/async/core/AsyncHttpServerConnection.h @@ -156,7 +156,7 @@ class HttpServerConnection : public TcpConnection class Response { public: - Response(void) : m_code(0), m_send_content(true) {} + Response(void) : m_code(0), m_send_content(false) {} unsigned code(void) const { return m_code; } void setCode(unsigned code) { m_code = code; } @@ -177,6 +177,7 @@ class HttpServerConnection : public TcpConnection m_content = content; setHeader("Content-type", content_type); setHeader("Content-length", m_content.size()); + setSendContent(true); } bool sendContent(void) const { return m_send_content; } void setSendContent(bool send_content) @@ -229,6 +230,15 @@ class HttpServerConnection : public TcpConnection */ virtual void disconnect(void); + /** + * @brief Send data with chunked transfer encoding + * + * Calling this function will enable data to be sent in chunks. The + * "Transfer-encoding: chunked" will be set in the header and each call to + * write() will send a chunk. + */ + void setChunked(void) { m_chunked = true; } + /** * @brief Send a HTTP response * @param res The response (@see Response) @@ -236,6 +246,18 @@ class HttpServerConnection : public TcpConnection */ virtual bool write(const Response& res); + /** + * @brief Write data to the socket + * @param buf The buffer containing the data to write + * @param len Then length of the data in the buffer + * @return Return \em true on success or else \em false + * + * If chunked mode has been set a chunked header and trailer will be added + * to the data. If not in chunked mode, the raw buffer will be sent without + * modification. + */ + virtual bool write(const char* buf, int len); + /** * @brief A signal that is emitted when a connection has been terminated * @param con The connection object @@ -309,6 +331,7 @@ class HttpServerConnection : public TcpConnection State m_state; std::string m_row; Request m_req; + bool m_chunked; HttpServerConnection(const HttpServerConnection&); HttpServerConnection& operator=(const HttpServerConnection&); diff --git a/src/versions b/src/versions index 9e4e89cb..4c03088b 100644 --- a/src/versions +++ b/src/versions @@ -8,7 +8,7 @@ QTEL=1.2.4 LIBECHOLIB=1.3.3 # Version for the Async library -LIBASYNC=1.6.0.99.4 +LIBASYNC=1.6.0.99.5 # SvxLink versions SVXLINK=1.7.99.22