diff --git a/README.md b/README.md index b60c623..7b7fe6a 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ svr.set_logger([](const auto& req, const auto& res) { }); ``` -### Error Handler +### Error handler ```cpp svr.set_error_handler([](const auto& req, auto& res) { @@ -232,6 +232,24 @@ svr.new_task_queue = [] { }; ``` +### 'Expect: 100-continue' handler + +As default, the server sends `100 Continue` response for `Expect: 100-continue` header. + +```cpp +// Send a '417 Expectation Failed' response. +svr.set_expect_100_continue_handler([](const Request &req, Response &res) { + return 417; +}); +``` + +```cpp +// Send a final status without reading the message body. +svr.set_expect_100_continue_handler([](const Request &req, Response &res) { + return res.status = 401; +}); +``` + Client Example -------------- diff --git a/httplib.h b/httplib.h index f2a5c70..1d8910a 100644 --- a/httplib.h +++ b/httplib.h @@ -448,6 +448,8 @@ public: using Handler = std::function; using HandlerWithContentReader = std::function; + using Expect100ContinueHandler = + std::function; Server(); @@ -476,6 +478,8 @@ public: void set_error_handler(Handler handler); void set_logger(Logger logger); + void set_expect_100_continue_handler(Expect100ContinueHandler handler); + void set_keep_alive_max_count(size_t count); void set_read_timeout(time_t sec, time_t usec); void set_payload_max_length(size_t length); @@ -553,6 +557,7 @@ private: Handlers options_handlers_; Handler error_handler_; Logger logger_; + Expect100ContinueHandler expect_100_continue_handler_; }; class Client { @@ -1594,6 +1599,7 @@ find_content_type(const std::string &path, inline const char *status_message(int status) { switch (status) { + case 100: return "Continue"; case 200: return "OK"; case 202: return "Accepted"; case 204: return "No Content"; @@ -1610,6 +1616,7 @@ inline const char *status_message(int status) { case 414: return "Request-URI Too Long"; case 415: return "Unsupported Media Type"; case 416: return "Range Not Satisfiable"; + case 417: return "Expectation Failed"; case 503: return "Service Unavailable"; default: @@ -2931,6 +2938,11 @@ inline void Server::set_error_handler(Handler handler) { inline void Server::set_logger(Logger logger) { logger_ = std::move(logger); } +inline void +Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) { + expect_100_continue_handler_ = std::move(handler); +} + inline void Server::set_keep_alive_max_count(size_t count) { keep_alive_max_count_ = count; } @@ -3012,11 +3024,12 @@ inline bool Server::write_response(Stream &strm, bool last_connection, res.set_header("Connection", "Keep-Alive"); } - if (!res.has_header("Content-Type")) { + if (!res.has_header("Content-Type") && + (!res.body.empty() || res.content_length > 0)) { res.set_header("Content-Type", "text/plain"); } - if (!res.has_header("Accept-Ranges")) { + if (!res.has_header("Accept-Ranges") && req.method == "HEAD") { res.set_header("Accept-Ranges", "bytes"); } @@ -3491,6 +3504,21 @@ Server::process_request(Stream &strm, bool last_connection, if (setup_request) { setup_request(req); } + if (req.get_header_value("Expect") == "100-continue") { + auto status = 100; + if (expect_100_continue_handler_) { + status = expect_100_continue_handler_(req, res); + } + switch (status) { + case 100: + case 417: + strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status, + detail::status_message(status)); + break; + default: return write_response(strm, last_connection, req, res); + } + } + // Rounting if (routing(req, res, strm, last_connection)) { if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }