yhirose 8 years ago
parent
commit
459f197ed0
1 changed files with 81 additions and 71 deletions
  1. 81 71
      httplib.h

+ 81 - 71
httplib.h

@@ -130,6 +130,9 @@ public:
     virtual int read(char* ptr, size_t size) = 0;
     virtual int read(char* ptr, size_t size) = 0;
     virtual int write(const char* ptr, size_t size1) = 0;
     virtual int write(const char* ptr, size_t size1) = 0;
     virtual int write(const char* ptr) = 0;
     virtual int write(const char* ptr) = 0;
+
+    template <typename ...Args>
+    void write_format(const char* fmt, const Args& ...args);
 };
 };
 
 
 class SocketStream : public Stream {
 class SocketStream : public Stream {
@@ -209,7 +212,7 @@ protected:
 
 
 private:
 private:
     bool read_response_line(Stream& strm, Response& res);
     bool read_response_line(Stream& strm, Response& res);
-    void add_default_headers(Request& req);
+    void write_request(Stream& strm, const Request& req, const char* ver);
 
 
     virtual bool read_and_close_socket(socket_t sock, const Request& req, Response& res);
     virtual bool read_and_close_socket(socket_t sock, const Request& req, Response& res);
 };
 };
@@ -277,6 +280,8 @@ void split(const char* b, const char* e, char d, Fn fn)
     }
     }
 }
 }
 
 
+// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
+// to store data. The call can set memory on stack for performance.
 class stream_line_reader {
 class stream_line_reader {
 public:
 public:
     stream_line_reader(Stream& strm, char* fixed_buffer, size_t fixed_buffer_size)
     stream_line_reader(Stream& strm, char* fixed_buffer, size_t fixed_buffer_size)
@@ -341,32 +346,6 @@ private:
     std::string glowable_buffer_;
     std::string glowable_buffer_;
 };
 };
 
 
-template <typename ...Args>
-inline void stream_write_format(Stream& strm, const char* fmt, const Args& ...args)
-{
-    const auto bufsiz = 2048;
-    char buf[bufsiz];
-
-    auto n = snprintf(buf, bufsiz - 1, fmt, args...);
-    if (n > 0) {
-        if (n >= bufsiz - 1) {
-            std::vector<char> glowable_buf(bufsiz);
-
-            while (n >= static_cast<int>(glowable_buf.size() - 1)) {
-                glowable_buf.resize(glowable_buf.size() * 2);
-#if defined(_MSC_VER) && _MSC_VER < 1900
-                n = _snprintf_s(&glowable_buf[0], glowable_buf.size(), glowable_buf.size() - 1, fmt, args...);
-#else
-                n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...);
-#endif
-            }
-            strm.write(&glowable_buf[0], n);
-        } else {
-            strm.write(buf, n);
-        }
-    }
-}
-
 inline int close_socket(socket_t sock)
 inline int close_socket(socket_t sock)
 {
 {
 #ifdef _WIN32
 #ifdef _WIN32
@@ -733,25 +712,13 @@ inline void write_headers(Stream& strm, const T& info)
 
 
     for (const auto& x: info.headers) {
     for (const auto& x: info.headers) {
         if (x.first != "Content-Type" && x.first != "Content-Length") {
         if (x.first != "Content-Type" && x.first != "Content-Length") {
-            stream_write_format(strm, "%s: %s\r\n", x.first.c_str(), x.second.c_str());
+            strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
         }
         }
     }
     }
 
 
     auto t = get_header_value(info.headers, "Content-Type", "text/plain");
     auto t = get_header_value(info.headers, "Content-Type", "text/plain");
-    stream_write_format(strm, "Content-Type: %s\r\n", t);
-    stream_write_format(strm, "Content-Length: %ld\r\n", info.body.size());
-    strm.write("\r\n");
-}
-
-inline void write_response(Stream& strm, const Request& req, const Response& res)
-{
-    stream_write_format(strm, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
-
-    write_headers(strm, res);
-
-    if (!res.body.empty() && req.method != "HEAD") {
-        strm.write(res.body.c_str(), res.body.size());
-    }
+    strm.write_format("Content-Type: %s\r\n", t);
+    strm.write_format("Content-Length: %ld\r\n", info.body.size());
 }
 }
 
 
 inline std::string encode_url(const std::string& s)
 inline std::string encode_url(const std::string& s)
@@ -886,23 +853,6 @@ inline std::string decode_url(const std::string& s)
     return result;
     return result;
 }
 }
 
 
-inline void write_request(Stream& strm, const Request& req, const char* ver)
-{
-    auto path = encode_url(req.path);
-    stream_write_format(strm, "%s %s %s\r\n", req.method.c_str(), path.c_str(), ver);
-
-    write_headers(strm, req);
-
-    if (!req.body.empty()) {
-        if (req.has_header("application/x-www-form-urlencoded")) {
-            auto str = encode_url(req.body);
-            strm.write(str.c_str(), str.size());
-        } else {
-            strm.write(req.body.c_str(), req.body.size());
-        }
-    }
-}
-
 inline void parse_query_text(const std::string& s, MultiMap& params)
 inline void parse_query_text(const std::string& s, MultiMap& params)
 {
 {
     split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
     split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
@@ -1110,6 +1060,33 @@ inline void Response::set_content(const std::string& s, const char* content_type
     set_header("Content-Type", content_type);
     set_header("Content-Type", content_type);
 }
 }
 
 
+// Rstream implementation
+template <typename ...Args>
+inline void Stream::write_format(const char* fmt, const Args& ...args)
+{
+    const auto bufsiz = 2048;
+    char buf[bufsiz];
+
+    auto n = snprintf(buf, bufsiz - 1, fmt, args...);
+    if (n > 0) {
+        if (n >= bufsiz - 1) {
+            std::vector<char> glowable_buf(bufsiz);
+
+            while (n >= static_cast<int>(glowable_buf.size() - 1)) {
+                glowable_buf.resize(glowable_buf.size() * 2);
+#if defined(_MSC_VER) && _MSC_VER < 1900
+                n = _snprintf_s(&glowable_buf[0], glowable_buf.size(), glowable_buf.size() - 1, fmt, args...);
+#else
+                n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...);
+#endif
+            }
+            write(&glowable_buf[0], n);
+        } else {
+            write(buf, n);
+        }
+    }
+}
+
 // Socket stream implementation
 // Socket stream implementation
 inline SocketStream::SocketStream(socket_t sock): sock_(sock)
 inline SocketStream::SocketStream(socket_t sock): sock_(sock)
 {
 {
@@ -1252,7 +1229,16 @@ inline void Server::write_response(Stream& strm, const Request& req, Response& r
         error_handler_(req, res);
         error_handler_(req, res);
     }
     }
 
 
-    detail::write_response(strm, req, res);
+    strm.write_format(
+        "HTTP/1.0 %d %s\r\n",
+        res.status, detail::status_message(res.status));
+
+    detail::write_headers(strm, res);
+    strm.write("\r\n");
+
+    if (!res.body.empty() && req.method != "HEAD") {
+        strm.write(res.body.c_str(), res.body.size());
+    }
 
 
     if (logger_) {
     if (logger_) {
         logger_(req, res);
         logger_(req, res);
@@ -1410,11 +1396,45 @@ inline bool Client::send(const Request& req, Response& res)
     return read_and_close_socket(sock, req, res);
     return read_and_close_socket(sock, req, res);
 }
 }
 
 
+inline void Client::write_request(Stream& strm, const Request& req, const char* ver)
+{
+    auto path = detail::encode_url(req.path);
+
+    // Request line
+    strm.write_format(
+        "%s %s %s\r\n", req.method.c_str(), path.c_str(), ver);
+
+    // Headers
+    strm.write_format("Host: %s\r\n", host_and_port_.c_str());
+
+    if (!req.has_header("Accept")) {
+        strm.write("Accept: */*\r\n");
+    }
+
+    if (!req.has_header("User-Agent")) {
+        strm.write("User-Agent: cpp-httplib/0.1\r\n");
+    }
+
+    detail::write_headers(strm, req);
+
+    strm.write("\r\n");
+
+    // Body
+    if (!req.body.empty()) {
+        if (req.has_header("application/x-www-form-urlencoded")) {
+            auto str = detail::encode_url(req.body);
+            strm.write(str.c_str(), str.size());
+        } else {
+            strm.write(req.body.c_str(), req.body.size());
+        }
+    }
+}
+
 inline bool Client::process_request(Stream& strm, const Request& req, Response& res)
 inline bool Client::process_request(Stream& strm, const Request& req, Response& res)
 {
 {
     // Send request
     // Send request
     auto ver = detail::http_version_strings[static_cast<size_t>(http_version_)];
     auto ver = detail::http_version_strings[static_cast<size_t>(http_version_)];
-    detail::write_request(strm, req, ver);
+    write_request(strm, req, ver);
 
 
     // Receive response
     // Receive response
     if (!read_response_line(strm, res) ||
     if (!read_response_line(strm, res) ||
@@ -1438,20 +1458,12 @@ inline bool Client::read_and_close_socket(socket_t sock, const Request& req, Res
     });
     });
 }
 }
 
 
-inline void Client::add_default_headers(Request& req)
-{
-    req.set_header("Host", host_and_port_.c_str());
-    req.set_header("Accept", "*/*");
-    req.set_header("User-Agent", "cpp-httplib/0.1");
-}
-
 inline std::shared_ptr<Response> Client::get(const char* path, Progress callback)
 inline std::shared_ptr<Response> Client::get(const char* path, Progress callback)
 {
 {
     Request req;
     Request req;
     req.method = "GET";
     req.method = "GET";
     req.path = path;
     req.path = path;
     req.progress = callback;
     req.progress = callback;
-    add_default_headers(req);
 
 
     auto res = std::make_shared<Response>();
     auto res = std::make_shared<Response>();
 
 
@@ -1463,7 +1475,6 @@ inline std::shared_ptr<Response> Client::head(const char* path)
     Request req;
     Request req;
     req.method = "HEAD";
     req.method = "HEAD";
     req.path = path;
     req.path = path;
-    add_default_headers(req);
 
 
     auto res = std::make_shared<Response>();
     auto res = std::make_shared<Response>();
 
 
@@ -1476,7 +1487,6 @@ inline std::shared_ptr<Response> Client::post(
     Request req;
     Request req;
     req.method = "POST";
     req.method = "POST";
     req.path = path;
     req.path = path;
-    add_default_headers(req);
 
 
     req.set_header("Content-Type", content_type);
     req.set_header("Content-Type", content_type);
     req.body = body;
     req.body = body;