From c221d22ca173c21a95ca96703f6bd8d05c67da9f Mon Sep 17 00:00:00 2001 From: Frank Hessel Date: Mon, 23 Mar 2020 19:56:40 +0100 Subject: [PATCH 1/2] Normalize case of header names. Resolve #73 --- src/HTTPHeader.cpp | 26 +++++++++++++++++++++++++- src/HTTPHeader.hpp | 9 +++++++++ src/HTTPHeaders.cpp | 6 ++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/HTTPHeader.cpp b/src/HTTPHeader.cpp index dfb968e..af75844 100644 --- a/src/HTTPHeader.cpp +++ b/src/HTTPHeader.cpp @@ -1,9 +1,13 @@ #include "HTTPHeader.hpp" +#include +#include +#include + namespace httpsserver { HTTPHeader::HTTPHeader(const std::string &name, const std::string &value): - _name(name), + _name(normalizeHeaderName(name)), _value(value) { } @@ -16,4 +20,24 @@ std::string HTTPHeader::print() { return _name + ": " + _value; } +std::string normalizeHeaderName(std::string const &name) { + std::locale loc; + std::stringbuf buf; + std::ostream oBuf(&buf); + bool upper = true; + std::string::size_type len = name.length(); + for (std::string::size_type i = 0; i < len; ++i) { + if (upper) { + oBuf << std::toupper(name[i], loc); + upper = false; + } else { + oBuf << std::tolower(name[i], loc); + if (!std::isalnum(name[i], loc)) { + upper=true; + } + } + } + return buf.str(); +} + } /* namespace httpsserver */ diff --git a/src/HTTPHeader.hpp b/src/HTTPHeader.hpp index eaee0ca..0e0432c 100644 --- a/src/HTTPHeader.hpp +++ b/src/HTTPHeader.hpp @@ -18,6 +18,15 @@ class HTTPHeader { std::string print(); }; +/** + * \brief Normalizes case in header names + * + * It converts the first letter and every letter after a non-alnum character + * to uppercase. For example, "content-length" becomes "Content-Length" and + * "HOST" becomes "Host". + */ +std::string normalizeHeaderName(std::string const &name); + } /* namespace httpsserver */ #endif /* SRC_HTTPHEADER_HPP_ */ diff --git a/src/HTTPHeaders.cpp b/src/HTTPHeaders.cpp index 26dda1a..c06f6c6 100644 --- a/src/HTTPHeaders.cpp +++ b/src/HTTPHeaders.cpp @@ -13,8 +13,9 @@ HTTPHeaders::~HTTPHeaders() { } HTTPHeader * HTTPHeaders::get(std::string const &name) { + std::string normalizedName = normalizeHeaderName(name); for(std::vector::iterator header = _headers->begin(); header != _headers->end(); ++header) { - if ((*header)->_name.compare(name)==0) { + if ((*header)->_name.compare(normalizedName)==0) { return (*header); } } @@ -22,8 +23,9 @@ HTTPHeader * HTTPHeaders::get(std::string const &name) { } std::string HTTPHeaders::getValue(std::string const &name) { + std::string normalizedName = normalizeHeaderName(name); for(std::vector::iterator header = _headers->begin(); header != _headers->end(); ++header) { - if ((*header)->_name.compare(name)==0) { + if ((*header)->_name.compare(normalizedName)==0) { return ((*header)->_value); } } From 50c0f5909ea845dd231917b97e31e520934a08dc Mon Sep 17 00:00:00 2001 From: Frank Hessel Date: Mon, 23 Mar 2020 20:57:35 +0100 Subject: [PATCH 2/2] Allow to set connection: close to disable keep-alive. Resolve #75 --- src/HTTPConnection.cpp | 6 ++++++ src/HTTPResponse.cpp | 9 +++++++++ src/HTTPResponse.hpp | 1 + 3 files changed, 16 insertions(+) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 31ed841..0ab739c 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -529,9 +529,15 @@ void HTTPConnection::loop() { // Now we need to check if we can use keep-alive to reuse the SSL connection // However, if the client did not set content-size or defined connection: close, // we have no chance to do so. + // Also, the programmer may have explicitly set Connection: close for the response. + std::string hConnection = res.getHeader("Connection"); + if (hConnection == "close") { + _isKeepAlive = false; + } if (!_isKeepAlive) { // No KeepAlive -> We are done. Transition to next state. if (!isClosed()) { + res.finalize(); _connectionState = STATE_BODY_FINISHED; } } else { diff --git a/src/HTTPResponse.cpp b/src/HTTPResponse.cpp index b47e945..baabc39 100644 --- a/src/HTTPResponse.cpp +++ b/src/HTTPResponse.cpp @@ -52,6 +52,15 @@ void HTTPResponse::setHeader(std::string const &name, std::string const &value) _headers.set(new HTTPHeader(name, value)); } +std::string HTTPResponse::getHeader(std::string const &name) { + HTTPHeader * h = _headers.get(name); + if (h != NULL) { + return h->_value; + } else { + return std::string(); + } +} + bool HTTPResponse::isHeaderWritten() { return _headerWritten; } diff --git a/src/HTTPResponse.hpp b/src/HTTPResponse.hpp index 1ba0c6e..7bd1758 100644 --- a/src/HTTPResponse.hpp +++ b/src/HTTPResponse.hpp @@ -32,6 +32,7 @@ class HTTPResponse : public Print { uint16_t getStatusCode(); std::string getStatusText(); void setHeader(std::string const &name, std::string const &value); + std::string getHeader(std::string const &name); bool isHeaderWritten(); void printStd(std::string const &str);