sync httplib.h with its current master, but replace std::regex with boost:regex again
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
//
 | 
			
		||||
//  httplib.h
 | 
			
		||||
//  Copyright (c) 2019 Albert S. All rights reserved.
 | 
			
		||||
//  Copyright (c) 2017 Yuji Hirose. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2019 Yuji Hirose. All rights reserved.
 | 
			
		||||
//  MIT License
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
@@ -29,32 +29,38 @@
 | 
			
		||||
#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
 | 
			
		||||
#endif // S_ISDIR
 | 
			
		||||
 | 
			
		||||
#ifndef NOMINMAX
 | 
			
		||||
#define NOMINMAX
 | 
			
		||||
#endif // NOMINMAX
 | 
			
		||||
 | 
			
		||||
#include <io.h>
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#include <ws2tcpip.h>
 | 
			
		||||
 | 
			
		||||
#pragma comment(lib, "ws2_32.lib")
 | 
			
		||||
 | 
			
		||||
#ifndef strcasecmp
 | 
			
		||||
#define strcasecmp _stricmp
 | 
			
		||||
#endif // strcasecmp
 | 
			
		||||
 | 
			
		||||
typedef SOCKET socket_t;
 | 
			
		||||
#else
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/select.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
typedef int socket_t;
 | 
			
		||||
#define INVALID_SOCKET (-1)
 | 
			
		||||
#endif //_WIN32
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <map>
 | 
			
		||||
@@ -62,12 +68,11 @@ typedef int socket_t;
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <boost/regex.hpp>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 | 
			
		||||
#include <openssl/err.h>
 | 
			
		||||
#include <openssl/ssl.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -80,6 +85,9 @@ typedef int socket_t;
 | 
			
		||||
 */
 | 
			
		||||
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
 | 
			
		||||
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0
 | 
			
		||||
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
 | 
			
		||||
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
 | 
			
		||||
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH std::numeric_limits<uint64_t>::max()
 | 
			
		||||
 | 
			
		||||
namespace httplib
 | 
			
		||||
{
 | 
			
		||||
@@ -237,6 +245,7 @@ class Server
 | 
			
		||||
	Server &Post(const char *pattern, Handler handler);
 | 
			
		||||
 | 
			
		||||
	Server &Put(const char *pattern, Handler handler);
 | 
			
		||||
	Server &Patch(const char *pattern, Handler handler);
 | 
			
		||||
	Server &Delete(const char *pattern, Handler handler);
 | 
			
		||||
	Server &Options(const char *pattern, Handler handler);
 | 
			
		||||
 | 
			
		||||
@@ -246,6 +255,7 @@ class Server
 | 
			
		||||
	void set_logger(Logger logger);
 | 
			
		||||
 | 
			
		||||
	void set_keep_alive_max_count(size_t count);
 | 
			
		||||
	void set_payload_max_length(uint64_t length);
 | 
			
		||||
 | 
			
		||||
	int bind_to_any_port(const char *host, int socket_flags = 0);
 | 
			
		||||
	bool listen_after_bind();
 | 
			
		||||
@@ -259,6 +269,7 @@ class Server
 | 
			
		||||
	bool process_request(Stream &strm, bool last_connection, bool &connection_close);
 | 
			
		||||
 | 
			
		||||
	size_t keep_alive_max_count_;
 | 
			
		||||
	size_t payload_max_length_;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
	typedef std::vector<std::pair<boost::regex, Handler>> Handlers;
 | 
			
		||||
@@ -282,6 +293,7 @@ class Server
 | 
			
		||||
	Handlers get_handlers_;
 | 
			
		||||
	Handlers post_handlers_;
 | 
			
		||||
	Handlers put_handlers_;
 | 
			
		||||
	Handlers patch_handlers_;
 | 
			
		||||
	Handlers delete_handlers_;
 | 
			
		||||
	Handlers options_handlers_;
 | 
			
		||||
	Handler error_handler_;
 | 
			
		||||
@@ -318,6 +330,10 @@ class Client
 | 
			
		||||
	std::shared_ptr<Response> Put(const char *path, const Headers &headers, const std::string &body,
 | 
			
		||||
								  const char *content_type);
 | 
			
		||||
 | 
			
		||||
	std::shared_ptr<Response> Patch(const char *path, const std::string &body, const char *content_type);
 | 
			
		||||
	std::shared_ptr<Response> Patch(const char *path, const Headers &headers, const std::string &body,
 | 
			
		||||
									const char *content_type);
 | 
			
		||||
 | 
			
		||||
	std::shared_ptr<Response> Delete(const char *path);
 | 
			
		||||
	std::shared_ptr<Response> Delete(const char *path, const Headers &headers);
 | 
			
		||||
 | 
			
		||||
@@ -443,6 +459,18 @@ class stream_line_reader
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t size() const
 | 
			
		||||
	{
 | 
			
		||||
		if(glowable_buffer_.empty())
 | 
			
		||||
		{
 | 
			
		||||
			return fixed_buffer_used_size_;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return glowable_buffer_.size();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool getline()
 | 
			
		||||
	{
 | 
			
		||||
		fixed_buffer_used_size_ = 0;
 | 
			
		||||
@@ -858,6 +886,10 @@ inline const char *status_message(int status)
 | 
			
		||||
		return "Forbidden";
 | 
			
		||||
	case 404:
 | 
			
		||||
		return "Not Found";
 | 
			
		||||
	case 413:
 | 
			
		||||
		return "Payload Too Large";
 | 
			
		||||
	case 414:
 | 
			
		||||
		return "Request-URI Too Long";
 | 
			
		||||
	case 415:
 | 
			
		||||
		return "Unsupported Media Type";
 | 
			
		||||
	default:
 | 
			
		||||
@@ -882,12 +914,12 @@ inline const char *get_header_value(const Headers &headers, const char *key, siz
 | 
			
		||||
	return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int get_header_value_int(const Headers &headers, const char *key, int def = 0)
 | 
			
		||||
inline uint64_t get_header_value_uint64(const Headers &headers, const char *key, int def = 0)
 | 
			
		||||
{
 | 
			
		||||
	auto it = headers.find(key);
 | 
			
		||||
	if(it != headers.end())
 | 
			
		||||
	{
 | 
			
		||||
		return std::stoi(it->second);
 | 
			
		||||
		return std::strtoull(it->second.data(), nullptr, 10);
 | 
			
		||||
	}
 | 
			
		||||
	return def;
 | 
			
		||||
}
 | 
			
		||||
@@ -1021,11 +1053,13 @@ inline bool read_content_chunked(Stream &strm, std::string &out)
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T> bool read_content(Stream &strm, T &x, Progress progress = Progress())
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool read_content(Stream &strm, T &x, uint64_t payload_max_length, bool &exceed_payload_max_length,
 | 
			
		||||
				  Progress progress = Progress())
 | 
			
		||||
{
 | 
			
		||||
	if(has_header(x.headers, "Content-Length"))
 | 
			
		||||
	{
 | 
			
		||||
		auto len = get_header_value_int(x.headers, "Content-Length", 0);
 | 
			
		||||
		auto len = get_header_value_uint64(x.headers, "Content-Length", 0);
 | 
			
		||||
		if(len == 0)
 | 
			
		||||
		{
 | 
			
		||||
			const auto &encoding = get_header_value(x.headers, "Transfer-Encoding", 0, "");
 | 
			
		||||
@@ -1034,6 +1068,15 @@ template <typename T> bool read_content(Stream &strm, T &x, Progress progress =
 | 
			
		||||
				return read_content_chunked(strm, x.body);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if((len > payload_max_length) ||
 | 
			
		||||
		   // For 32-bit platform
 | 
			
		||||
		   (sizeof(size_t) < sizeof(uint64_t) && len > std::numeric_limits<size_t>::max()))
 | 
			
		||||
		{
 | 
			
		||||
			exceed_payload_max_length = true;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return read_content_with_length(strm, x.body, len, progress);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
@@ -1071,6 +1114,12 @@ inline std::string encode_url(const std::string &s)
 | 
			
		||||
		case '+':
 | 
			
		||||
			result += "%2B";
 | 
			
		||||
			break;
 | 
			
		||||
		case '\r':
 | 
			
		||||
			result += "%0D";
 | 
			
		||||
			break;
 | 
			
		||||
		case '\n':
 | 
			
		||||
			result += "%0A";
 | 
			
		||||
			break;
 | 
			
		||||
		case '\'':
 | 
			
		||||
			result += "%27";
 | 
			
		||||
			break;
 | 
			
		||||
@@ -1470,9 +1519,9 @@ inline void decompress(std::string &content)
 | 
			
		||||
	strm.zfree = Z_NULL;
 | 
			
		||||
	strm.opaque = Z_NULL;
 | 
			
		||||
 | 
			
		||||
	// 15 is the value of wbits, which should be at the maximum possible value to ensure
 | 
			
		||||
	// that any gzip stream can be decoded. The offset of 16 specifies that the stream
 | 
			
		||||
	// to decompress will be formatted with a gzip wrapper.
 | 
			
		||||
	// 15 is the value of wbits, which should be at the maximum possible value to
 | 
			
		||||
	// ensure that any gzip stream can be decoded. The offset of 16 specifies that
 | 
			
		||||
	// the stream to decompress will be formatted with a gzip wrapper.
 | 
			
		||||
	auto ret = inflateInit2(&strm, 16 + 15);
 | 
			
		||||
	if(ret != Z_OK)
 | 
			
		||||
	{
 | 
			
		||||
@@ -1728,7 +1777,9 @@ inline const std::string &BufferStream::get_buffer() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTTP server implementation
 | 
			
		||||
inline Server::Server() : keep_alive_max_count_(5), is_running_(false), svr_sock_(INVALID_SOCKET), running_threads_(0)
 | 
			
		||||
inline Server::Server()
 | 
			
		||||
	: keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT), payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH),
 | 
			
		||||
	  is_running_(false), svr_sock_(INVALID_SOCKET), running_threads_(0)
 | 
			
		||||
{
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
	signal(SIGPIPE, SIG_IGN);
 | 
			
		||||
@@ -1757,6 +1808,12 @@ inline Server &Server::Put(const char *pattern, Handler handler)
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Server &Server::Patch(const char *pattern, Handler handler)
 | 
			
		||||
{
 | 
			
		||||
	patch_handlers_.push_back(std::make_pair(boost::regex(pattern), handler));
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Server &Server::Delete(const char *pattern, Handler handler)
 | 
			
		||||
{
 | 
			
		||||
	delete_handlers_.push_back(std::make_pair(boost::regex(pattern), handler));
 | 
			
		||||
@@ -1794,6 +1851,11 @@ inline void Server::set_keep_alive_max_count(size_t count)
 | 
			
		||||
	keep_alive_max_count_ = count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::set_payload_max_length(uint64_t length)
 | 
			
		||||
{
 | 
			
		||||
	payload_max_length_ = length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int Server::bind_to_any_port(const char *host, int socket_flags)
 | 
			
		||||
{
 | 
			
		||||
	return bind_internal(host, 0, socket_flags);
 | 
			
		||||
@@ -1830,7 +1892,8 @@ inline void Server::stop()
 | 
			
		||||
 | 
			
		||||
inline bool Server::parse_request_line(const char *s, Request &req)
 | 
			
		||||
{
 | 
			
		||||
	static boost::regex re("(GET|HEAD|POST|PUT|DELETE|OPTIONS) (([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n");
 | 
			
		||||
	static boost::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) "
 | 
			
		||||
						   "(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n");
 | 
			
		||||
 | 
			
		||||
	boost::cmatch m;
 | 
			
		||||
	if(boost::regex_match(s, m, re))
 | 
			
		||||
@@ -2119,6 +2182,10 @@ inline bool Server::routing(Request &req, Response &res)
 | 
			
		||||
	{
 | 
			
		||||
		return dispatch_request(req, res, put_handlers_);
 | 
			
		||||
	}
 | 
			
		||||
	else if(req.method == "PATCH")
 | 
			
		||||
	{
 | 
			
		||||
		return dispatch_request(req, res, patch_handlers_);
 | 
			
		||||
	}
 | 
			
		||||
	else if(req.method == "DELETE")
 | 
			
		||||
	{
 | 
			
		||||
		return dispatch_request(req, res, delete_handlers_);
 | 
			
		||||
@@ -2164,6 +2231,14 @@ inline bool Server::process_request(Stream &strm, bool last_connection, bool &co
 | 
			
		||||
 | 
			
		||||
	res.version = "HTTP/1.1";
 | 
			
		||||
 | 
			
		||||
	// Check if the request URI doesn't exceed the limit
 | 
			
		||||
	if(reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH)
 | 
			
		||||
	{
 | 
			
		||||
		res.status = 414;
 | 
			
		||||
		write_response(strm, last_connection, req, res);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Request line and headers
 | 
			
		||||
	if(!parse_request_line(reader.ptr(), req) || !detail::read_headers(strm, req.headers))
 | 
			
		||||
	{
 | 
			
		||||
@@ -2180,13 +2255,14 @@ inline bool Server::process_request(Stream &strm, bool last_connection, bool &co
 | 
			
		||||
	req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str());
 | 
			
		||||
 | 
			
		||||
	// Body
 | 
			
		||||
	if(req.method == "POST" || req.method == "PUT")
 | 
			
		||||
	if(req.method == "POST" || req.method == "PUT" || req.method == "PATCH")
 | 
			
		||||
	{
 | 
			
		||||
		if(!detail::read_content(strm, req))
 | 
			
		||||
		bool exceed_payload_max_length = false;
 | 
			
		||||
		if(!detail::read_content(strm, req, payload_max_length_, exceed_payload_max_length))
 | 
			
		||||
		{
 | 
			
		||||
			res.status = 400;
 | 
			
		||||
			res.status = exceed_payload_max_length ? 413 : 400;
 | 
			
		||||
			write_response(strm, last_connection, req, res);
 | 
			
		||||
			return true;
 | 
			
		||||
			return !exceed_payload_max_length;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const auto &content_type = req.get_header_value("Content-Type");
 | 
			
		||||
@@ -2333,26 +2409,29 @@ inline void Client::write_request(Stream &strm, Request &req)
 | 
			
		||||
	bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
 | 
			
		||||
 | 
			
		||||
	// Headers
 | 
			
		||||
	if(is_ssl())
 | 
			
		||||
	if(!req.has_header("Host"))
 | 
			
		||||
	{
 | 
			
		||||
		if(port_ == 443)
 | 
			
		||||
		if(is_ssl())
 | 
			
		||||
		{
 | 
			
		||||
			req.set_header("Host", host_.c_str());
 | 
			
		||||
			if(port_ == 443)
 | 
			
		||||
			{
 | 
			
		||||
				req.set_header("Host", host_.c_str());
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				req.set_header("Host", host_and_port_.c_str());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			req.set_header("Host", host_and_port_.c_str());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if(port_ == 80)
 | 
			
		||||
		{
 | 
			
		||||
			req.set_header("Host", host_.c_str());
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			req.set_header("Host", host_and_port_.c_str());
 | 
			
		||||
			if(port_ == 80)
 | 
			
		||||
			{
 | 
			
		||||
				req.set_header("Host", host_.c_str());
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				req.set_header("Host", host_and_port_.c_str());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -2373,7 +2452,7 @@ inline void Client::write_request(Stream &strm, Request &req)
 | 
			
		||||
 | 
			
		||||
	if(req.body.empty())
 | 
			
		||||
	{
 | 
			
		||||
		if(req.method == "POST" || req.method == "PUT")
 | 
			
		||||
		if(req.method == "POST" || req.method == "PUT" || req.method == "PATCH")
 | 
			
		||||
		{
 | 
			
		||||
			req.set_header("Content-Length", "0");
 | 
			
		||||
		}
 | 
			
		||||
@@ -2385,8 +2464,11 @@ inline void Client::write_request(Stream &strm, Request &req)
 | 
			
		||||
			req.set_header("Content-Type", "text/plain");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto length = std::to_string(req.body.size());
 | 
			
		||||
		req.set_header("Content-Length", length.c_str());
 | 
			
		||||
		if(!req.has_header("Content-Length"))
 | 
			
		||||
		{
 | 
			
		||||
			auto length = std::to_string(req.body.size());
 | 
			
		||||
			req.set_header("Content-Length", length.c_str());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	detail::write_headers(bstrm, req);
 | 
			
		||||
@@ -2421,7 +2503,9 @@ inline bool Client::process_request(Stream &strm, Request &req, Response &res, b
 | 
			
		||||
	// Body
 | 
			
		||||
	if(req.method != "HEAD")
 | 
			
		||||
	{
 | 
			
		||||
		if(!detail::read_content(strm, res, req.progress))
 | 
			
		||||
		bool exceed_payload_max_length = false;
 | 
			
		||||
		if(!detail::read_content(strm, res, std::numeric_limits<uint64_t>::max(), exceed_payload_max_length,
 | 
			
		||||
								 req.progress))
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
@@ -2550,6 +2634,27 @@ inline std::shared_ptr<Response> Client::Put(const char *path, const Headers &he
 | 
			
		||||
	return send(req, *res) ? res : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::shared_ptr<Response> Client::Patch(const char *path, const std::string &body, const char *content_type)
 | 
			
		||||
{
 | 
			
		||||
	return Patch(path, Headers(), body, content_type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::shared_ptr<Response> Client::Patch(const char *path, const Headers &headers, const std::string &body,
 | 
			
		||||
											   const char *content_type)
 | 
			
		||||
{
 | 
			
		||||
	Request req;
 | 
			
		||||
	req.method = "PATCH";
 | 
			
		||||
	req.headers = headers;
 | 
			
		||||
	req.path = path;
 | 
			
		||||
 | 
			
		||||
	req.headers.emplace("Content-Type", content_type);
 | 
			
		||||
	req.body = body;
 | 
			
		||||
 | 
			
		||||
	auto res = std::make_shared<Response>();
 | 
			
		||||
 | 
			
		||||
	return send(req, *res) ? res : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::shared_ptr<Response> Client::Delete(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	return Delete(path, Headers());
 | 
			
		||||
@@ -2663,6 +2768,11 @@ class SSLInit
 | 
			
		||||
		SSL_load_error_strings();
 | 
			
		||||
		SSL_library_init();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~SSLInit()
 | 
			
		||||
	{
 | 
			
		||||
		ERR_free_strings();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static SSLInit sslinit_;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user