Browse Source

Add option to bypass URL encode of path (#934)

Alex Hornung 4 years ago
parent
commit
e00ad37580
2 changed files with 48 additions and 1 deletions
  1. 12 1
      httplib.h
  2. 36 0
      test/test.cc

+ 12 - 1
httplib.h

@@ -1005,6 +1005,8 @@ public:
   void set_keep_alive(bool on);
   void set_keep_alive(bool on);
   void set_follow_location(bool on);
   void set_follow_location(bool on);
 
 
+  void set_url_encode(bool on);
+
   void set_compress(bool on);
   void set_compress(bool on);
 
 
   void set_decompress(bool on);
   void set_decompress(bool on);
@@ -1101,6 +1103,8 @@ protected:
   bool keep_alive_ = false;
   bool keep_alive_ = false;
   bool follow_location_ = false;
   bool follow_location_ = false;
 
 
+  bool url_encode_ = true;
+
   int address_family_ = AF_UNSPEC;
   int address_family_ = AF_UNSPEC;
   bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
   bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
   SocketOptions socket_options_ = nullptr;
   SocketOptions socket_options_ = nullptr;
@@ -1318,6 +1322,8 @@ public:
   void set_keep_alive(bool on);
   void set_keep_alive(bool on);
   void set_follow_location(bool on);
   void set_follow_location(bool on);
 
 
+  void set_url_encode(bool on);
+
   void set_compress(bool on);
   void set_compress(bool on);
 
 
   void set_decompress(bool on);
   void set_decompress(bool on);
@@ -5276,6 +5282,7 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
 #endif
 #endif
   keep_alive_ = rhs.keep_alive_;
   keep_alive_ = rhs.keep_alive_;
   follow_location_ = rhs.follow_location_;
   follow_location_ = rhs.follow_location_;
+  url_encode_ = rhs.url_encode_;
   tcp_nodelay_ = rhs.tcp_nodelay_;
   tcp_nodelay_ = rhs.tcp_nodelay_;
   socket_options_ = rhs.socket_options_;
   socket_options_ = rhs.socket_options_;
   compress_ = rhs.compress_;
   compress_ = rhs.compress_;
@@ -5703,7 +5710,7 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
   {
   {
     detail::BufferStream bstrm;
     detail::BufferStream bstrm;
 
 
-    const auto &path = detail::encode_url(req.path);
+    const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path;
     bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
     bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
 
 
     detail::write_headers(bstrm, req.headers);
     detail::write_headers(bstrm, req.headers);
@@ -6432,6 +6439,8 @@ inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
 
 
 inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
 inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
 
 
+inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
+
 inline void ClientImpl::set_default_headers(Headers headers) {
 inline void ClientImpl::set_default_headers(Headers headers) {
   default_headers_ = std::move(headers);
   default_headers_ = std::move(headers);
 }
 }
@@ -7560,6 +7569,8 @@ inline void Client::set_follow_location(bool on) {
   cli_->set_follow_location(on);
   cli_->set_follow_location(on);
 }
 }
 
 
+inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); }
+
 inline void Client::set_compress(bool on) { cli_->set_compress(on); }
 inline void Client::set_compress(bool on) { cli_->set_compress(on); }
 
 
 inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }
 inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }

+ 36 - 0
test/test.cc

@@ -965,6 +965,42 @@ TEST(RedirectFromPageWithContent, Redirect) {
 
 
 #endif
 #endif
 
 
+TEST(PathUrlEncodeTest, PathUrlEncode) {
+  Server svr;
+
+  svr.Get("/foo", [](const Request & req, Response &res) {
+    auto a = req.params.find("a");
+    if (a != req.params.end()) {
+      res.set_content((*a).second, "text/plain");
+      res.status = 200;
+    } else {
+      res.status = 400;
+    }
+  });
+
+  auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+  // Give GET time to get a few messages.
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+
+  {
+    Client cli(HOST, PORT);
+    cli.set_url_encode(false);
+
+    auto res = cli.Get("/foo?a=explicitly+encoded");
+    ASSERT_TRUE(res);
+    EXPECT_EQ(200, res->status);
+    // This expects it back with a space, as the `+` won't have been
+    // url-encoded, and server-side the params get decoded turning `+`
+    // into spaces.
+    EXPECT_EQ("explicitly encoded", res->body);
+  }
+
+  svr.stop();
+  thread.join();
+  ASSERT_FALSE(svr.is_running());
+}
+
 TEST(BindServerTest, BindDualStack) {
 TEST(BindServerTest, BindDualStack) {
   Server svr;
   Server svr;