yhirose 5 years ago
parent
commit
ca5a50d2c9
2 changed files with 49 additions and 3 deletions
  1. 19 1
      README.md
  2. 30 2
      httplib.h

+ 19 - 1
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
 --------------
 

+ 30 - 2
httplib.h

@@ -448,6 +448,8 @@ public:
   using Handler = std::function<void(const Request &, Response &)>;
   using HandlerWithContentReader = std::function<void(
       const Request &, Response &, const ContentReader &content_reader)>;
+  using Expect100ContinueHandler =
+      std::function<int(const Request &, Response &)>;
 
   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; }