httplib: upgrade to git master (but use boost regex still)
This commit is contained in:
parent
23c01303b4
commit
632f689b3e
@ -1,42 +1,43 @@
|
||||
//
|
||||
// httplib.h
|
||||
// Copyright (c) 2018 Albert S. All rights reserved.
|
||||
// Copyright (c) 2019 Albert S. All rights reserved.
|
||||
// Copyright (c) 2017 Yuji Hirose. All rights reserved.
|
||||
// MIT License
|
||||
//
|
||||
|
||||
#ifndef _CPPHTTPLIB_HTTPLIB_H_
|
||||
#define _CPPHTTPLIB_HTTPLIB_H_
|
||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||
#define CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif //_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#endif //_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf_s
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG)
|
||||
#endif
|
||||
#endif // S_ISREG
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
|
||||
#endif
|
||||
#endif // S_ISDIR
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#endif // strcasecmp
|
||||
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
@ -52,7 +53,7 @@ typedef SOCKET socket_t;
|
||||
|
||||
typedef int socket_t;
|
||||
#define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
#endif //_WIN32
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
@ -136,11 +137,13 @@ struct Request
|
||||
Progress progress;
|
||||
|
||||
bool has_header(const char *key) const;
|
||||
std::string get_header_value(const char *key) const;
|
||||
std::string get_header_value(const char *key, size_t id = 0) const;
|
||||
size_t get_header_value_count(const char *key) const;
|
||||
void set_header(const char *key, const char *val);
|
||||
|
||||
bool has_param(const char *key) const;
|
||||
std::string get_param_value(const char *key) const;
|
||||
std::string get_param_value(const char *key, size_t id = 0) const;
|
||||
size_t get_param_value_count(const char *key) const;
|
||||
|
||||
bool has_file(const char *key) const;
|
||||
MultipartFile get_file_value(const char *key) const;
|
||||
@ -155,7 +158,8 @@ struct Response
|
||||
std::function<std::string(uint64_t offset)> streamcb;
|
||||
|
||||
bool has_header(const char *key) const;
|
||||
std::string get_header_value(const char *key) const;
|
||||
std::string get_header_value(const char *key, size_t id = 0) const;
|
||||
size_t get_header_value_count(const char *key) const;
|
||||
void set_header(const char *key, const char *val);
|
||||
|
||||
void set_redirect(const char *uri);
|
||||
@ -176,7 +180,7 @@ class Stream
|
||||
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) = 0;
|
||||
virtual std::string get_remote_addr() = 0;
|
||||
virtual std::string get_remote_addr() const = 0;
|
||||
|
||||
template <typename... Args> void write_format(const char *fmt, const Args &...args);
|
||||
};
|
||||
@ -190,12 +194,33 @@ class SocketStream : public Stream
|
||||
virtual int read(char *ptr, size_t size);
|
||||
virtual int write(const char *ptr, size_t size);
|
||||
virtual int write(const char *ptr);
|
||||
virtual std::string get_remote_addr();
|
||||
virtual std::string get_remote_addr() const;
|
||||
|
||||
private:
|
||||
socket_t sock_;
|
||||
};
|
||||
|
||||
class BufferStream : public Stream
|
||||
{
|
||||
public:
|
||||
BufferStream()
|
||||
{
|
||||
}
|
||||
virtual ~BufferStream()
|
||||
{
|
||||
}
|
||||
|
||||
virtual int read(char *ptr, size_t size);
|
||||
virtual int write(const char *ptr, size_t size);
|
||||
virtual int write(const char *ptr);
|
||||
virtual std::string get_remote_addr() const;
|
||||
|
||||
const std::string &get_buffer() const;
|
||||
|
||||
private:
|
||||
std::string buffer;
|
||||
};
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
@ -315,6 +340,7 @@ class Client
|
||||
void write_request(Stream &strm, Request &req);
|
||||
|
||||
virtual bool read_and_close_socket(socket_t sock, Request &req, Response &res);
|
||||
virtual bool is_ssl() const;
|
||||
};
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@ -327,7 +353,7 @@ class SSLSocketStream : public Stream
|
||||
virtual int read(char *ptr, size_t size);
|
||||
virtual int write(const char *ptr, size_t size);
|
||||
virtual int write(const char *ptr);
|
||||
virtual std::string get_remote_addr();
|
||||
virtual std::string get_remote_addr() const;
|
||||
|
||||
private:
|
||||
socket_t sock_;
|
||||
@ -353,7 +379,7 @@ class SSLServer : public Server
|
||||
class SSLClient : public Client
|
||||
{
|
||||
public:
|
||||
SSLClient(const char *host, int port = 80, time_t timeout_sec = 300);
|
||||
SSLClient(const char *host, int port = 443, time_t timeout_sec = 300);
|
||||
|
||||
virtual ~SSLClient();
|
||||
|
||||
@ -361,6 +387,7 @@ class SSLClient : public Client
|
||||
|
||||
private:
|
||||
virtual bool read_and_close_socket(socket_t sock, Request &req, Response &res);
|
||||
virtual bool is_ssl() const;
|
||||
|
||||
SSL_CTX *ctx_;
|
||||
std::mutex ctx_mutex_;
|
||||
@ -495,10 +522,10 @@ inline int select_read(socket_t sock, time_t sec, time_t usec)
|
||||
FD_SET(sock, &fds);
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = sec;
|
||||
tv.tv_usec = usec;
|
||||
tv.tv_sec = static_cast<long>(sec);
|
||||
tv.tv_usec = static_cast<long>(usec);
|
||||
|
||||
return select(sock + 1, &fds, NULL, NULL, &tv);
|
||||
return select(static_cast<int>(sock + 1), &fds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
|
||||
@ -511,10 +538,10 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
|
||||
auto fdse = fdsr;
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = sec;
|
||||
tv.tv_usec = usec;
|
||||
tv.tv_sec = static_cast<long>(sec);
|
||||
tv.tv_usec = static_cast<long>(usec);
|
||||
|
||||
if(select(sock + 1, &fdsr, &fdsw, &fdse, &tv) < 0)
|
||||
if(select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -844,9 +871,10 @@ inline bool has_header(const Headers &headers, const char *key)
|
||||
return headers.find(key) != headers.end();
|
||||
}
|
||||
|
||||
inline const char *get_header_value(const Headers &headers, const char *key, const char *def = nullptr)
|
||||
inline const char *get_header_value(const Headers &headers, const char *key, size_t id = 0, const char *def = nullptr)
|
||||
{
|
||||
auto it = headers.find(key);
|
||||
std::advance(it, id);
|
||||
if(it != headers.end())
|
||||
{
|
||||
return it->second.c_str();
|
||||
@ -1000,7 +1028,7 @@ template <typename T> bool read_content(Stream &strm, T &x, Progress progress =
|
||||
auto len = get_header_value_int(x.headers, "Content-Length", 0);
|
||||
if(len == 0)
|
||||
{
|
||||
const auto &encoding = get_header_value(x.headers, "Transfer-Encoding", "");
|
||||
const auto &encoding = get_header_value(x.headers, "Transfer-Encoding", 0, "");
|
||||
if(!strcasecmp(encoding, "chunked"))
|
||||
{
|
||||
return read_content_chunked(strm, x.body);
|
||||
@ -1010,7 +1038,7 @@ template <typename T> bool read_content(Stream &strm, T &x, Progress progress =
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &encoding = get_header_value(x.headers, "Transfer-Encoding", "");
|
||||
const auto &encoding = get_header_value(x.headers, "Transfer-Encoding", 0, "");
|
||||
if(!strcasecmp(encoding, "chunked"))
|
||||
{
|
||||
return read_content_chunked(strm, x.body);
|
||||
@ -1038,7 +1066,10 @@ inline std::string encode_url(const std::string &s)
|
||||
switch(s[i])
|
||||
{
|
||||
case ' ':
|
||||
result += "+";
|
||||
result += "%20";
|
||||
break;
|
||||
case '+':
|
||||
result += "%2B";
|
||||
break;
|
||||
case '\'':
|
||||
result += "%27";
|
||||
@ -1506,9 +1537,15 @@ inline bool Request::has_header(const char *key) const
|
||||
return detail::has_header(headers, key);
|
||||
}
|
||||
|
||||
inline std::string Request::get_header_value(const char *key) const
|
||||
inline std::string Request::get_header_value(const char *key, size_t id) const
|
||||
{
|
||||
return detail::get_header_value(headers, key, "");
|
||||
return detail::get_header_value(headers, key, id, "");
|
||||
}
|
||||
|
||||
inline size_t Request::get_header_value_count(const char *key) const
|
||||
{
|
||||
auto r = headers.equal_range(key);
|
||||
return std::distance(r.first, r.second);
|
||||
}
|
||||
|
||||
inline void Request::set_header(const char *key, const char *val)
|
||||
@ -1521,9 +1558,10 @@ inline bool Request::has_param(const char *key) const
|
||||
return params.find(key) != params.end();
|
||||
}
|
||||
|
||||
inline std::string Request::get_param_value(const char *key) const
|
||||
inline std::string Request::get_param_value(const char *key, size_t id) const
|
||||
{
|
||||
auto it = params.find(key);
|
||||
std::advance(it, id);
|
||||
if(it != params.end())
|
||||
{
|
||||
return it->second;
|
||||
@ -1531,6 +1569,12 @@ inline std::string Request::get_param_value(const char *key) const
|
||||
return std::string();
|
||||
}
|
||||
|
||||
inline size_t Request::get_param_value_count(const char *key) const
|
||||
{
|
||||
auto r = params.equal_range(key);
|
||||
return std::distance(r.first, r.second);
|
||||
}
|
||||
|
||||
inline bool Request::has_file(const char *key) const
|
||||
{
|
||||
return files.find(key) != files.end();
|
||||
@ -1552,9 +1596,15 @@ inline bool Response::has_header(const char *key) const
|
||||
return headers.find(key) != headers.end();
|
||||
}
|
||||
|
||||
inline std::string Response::get_header_value(const char *key) const
|
||||
inline std::string Response::get_header_value(const char *key, size_t id) const
|
||||
{
|
||||
return detail::get_header_value(headers, key, "");
|
||||
return detail::get_header_value(headers, key, id, "");
|
||||
}
|
||||
|
||||
inline size_t Response::get_header_value_count(const char *key) const
|
||||
{
|
||||
auto r = headers.equal_range(key);
|
||||
return std::distance(r.first, r.second);
|
||||
}
|
||||
|
||||
inline void Response::set_header(const char *key, const char *val)
|
||||
@ -1626,12 +1676,12 @@ inline SocketStream::~SocketStream()
|
||||
|
||||
inline int SocketStream::read(char *ptr, size_t size)
|
||||
{
|
||||
return recv(sock_, ptr, size, 0);
|
||||
return recv(sock_, ptr, static_cast<int>(size), 0);
|
||||
}
|
||||
|
||||
inline int SocketStream::write(const char *ptr, size_t size)
|
||||
{
|
||||
return send(sock_, ptr, size, 0);
|
||||
return send(sock_, ptr, static_cast<int>(size), 0);
|
||||
}
|
||||
|
||||
inline int SocketStream::write(const char *ptr)
|
||||
@ -1639,11 +1689,44 @@ inline int SocketStream::write(const char *ptr)
|
||||
return write(ptr, strlen(ptr));
|
||||
}
|
||||
|
||||
inline std::string SocketStream::get_remote_addr()
|
||||
inline std::string SocketStream::get_remote_addr() const
|
||||
{
|
||||
return detail::get_remote_addr(sock_);
|
||||
}
|
||||
|
||||
// Buffer stream implementation
|
||||
inline int BufferStream::read(char *ptr, size_t size)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
return static_cast<int>(buffer._Copy_s(ptr, size, size));
|
||||
#else
|
||||
return static_cast<int>(buffer.copy(ptr, size));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int BufferStream::write(const char *ptr, size_t size)
|
||||
{
|
||||
buffer.append(ptr, size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
inline int BufferStream::write(const char *ptr)
|
||||
{
|
||||
size_t size = strlen(ptr);
|
||||
buffer.append(ptr, size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
inline std::string BufferStream::get_remote_addr() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
inline const std::string &BufferStream::get_buffer() const
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// HTTP server implementation
|
||||
inline Server::Server() : keep_alive_max_count_(5), is_running_(false), svr_sock_(INVALID_SOCKET), running_threads_(0)
|
||||
{
|
||||
@ -1793,7 +1876,22 @@ inline void Server::write_response(Stream &strm, bool last_connection, const Req
|
||||
res.set_header("Connection", "Keep-Alive");
|
||||
}
|
||||
|
||||
if(!res.body.empty())
|
||||
if(res.body.empty())
|
||||
{
|
||||
if(!res.has_header("Content-Length"))
|
||||
{
|
||||
if(res.streamcb)
|
||||
{
|
||||
// Streamed response
|
||||
res.set_header("Transfer-Encoding", "chunked");
|
||||
}
|
||||
else
|
||||
{
|
||||
res.set_header("Content-Length", "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
// TODO: 'Accpet-Encoding' has gzip, not gzip;q=0
|
||||
@ -1813,13 +1911,6 @@ inline void Server::write_response(Stream &strm, bool last_connection, const Req
|
||||
auto length = std::to_string(res.body.size());
|
||||
res.set_header("Content-Length", length.c_str());
|
||||
}
|
||||
else if(res.streamcb)
|
||||
{
|
||||
// Streamed response
|
||||
bool chunked_response = !res.has_header("Content-Length");
|
||||
if(chunked_response)
|
||||
res.set_header("Transfer-Encoding", "chunked");
|
||||
}
|
||||
|
||||
detail::write_headers(strm, res);
|
||||
|
||||
@ -1888,7 +1979,7 @@ inline socket_t Server::create_server_socket(const char *host, int port, int soc
|
||||
return detail::create_socket(
|
||||
host, port,
|
||||
[](socket_t sock, struct addrinfo &ai) -> bool {
|
||||
if(::bind(sock, ai.ai_addr, ai.ai_addrlen))
|
||||
if(::bind(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2177,7 +2268,7 @@ inline socket_t Client::create_client_socket() const
|
||||
return detail::create_socket(host_.c_str(), port_, [=](socket_t sock, struct addrinfo &ai) -> bool {
|
||||
detail::set_nonblocking(sock, true);
|
||||
|
||||
auto ret = connect(sock, ai.ai_addr, ai.ai_addrlen);
|
||||
auto ret = connect(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen));
|
||||
if(ret < 0)
|
||||
{
|
||||
if(detail::is_connection_error() || !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0))
|
||||
@ -2204,7 +2295,7 @@ inline bool Client::read_response_line(Stream &strm, Response &res)
|
||||
return false;
|
||||
}
|
||||
|
||||
const static boost::regex re("(HTTP/1\\.[01]) (\\d+?) .+\r\n");
|
||||
const static boost::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n");
|
||||
|
||||
boost::cmatch m;
|
||||
if(boost::regex_match(reader.ptr(), m, re))
|
||||
@ -2234,13 +2325,36 @@ inline bool Client::send(Request &req, Response &res)
|
||||
|
||||
inline void Client::write_request(Stream &strm, Request &req)
|
||||
{
|
||||
auto path = detail::encode_url(req.path);
|
||||
BufferStream bstrm;
|
||||
|
||||
// Request line
|
||||
strm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
|
||||
auto path = detail::encode_url(req.path);
|
||||
|
||||
bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
|
||||
|
||||
// Headers
|
||||
req.set_header("Host", host_and_port_.c_str());
|
||||
if(is_ssl())
|
||||
{
|
||||
if(port_ == 443)
|
||||
{
|
||||
req.set_header("Host", host_.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(!req.has_header("Accept"))
|
||||
{
|
||||
@ -2275,21 +2389,17 @@ inline void Client::write_request(Stream &strm, Request &req)
|
||||
req.set_header("Content-Length", length.c_str());
|
||||
}
|
||||
|
||||
detail::write_headers(strm, req);
|
||||
detail::write_headers(bstrm, req);
|
||||
|
||||
// Body
|
||||
if(!req.body.empty())
|
||||
{
|
||||
if(req.get_header_value("Content-Type") == "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());
|
||||
}
|
||||
bstrm.write(req.body.c_str(), req.body.size());
|
||||
}
|
||||
|
||||
// Flush buffer
|
||||
auto &data = bstrm.get_buffer();
|
||||
strm.write(data.data(), data.size());
|
||||
}
|
||||
|
||||
inline bool Client::process_request(Stream &strm, Request &req, Response &res, bool &connection_close)
|
||||
@ -2336,6 +2446,11 @@ inline bool Client::read_and_close_socket(socket_t sock, Request &req, Response
|
||||
});
|
||||
}
|
||||
|
||||
inline bool Client::is_ssl() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path, Progress progress)
|
||||
{
|
||||
return Get(path, Headers(), progress);
|
||||
@ -2578,7 +2693,7 @@ inline int SSLSocketStream::write(const char *ptr)
|
||||
return write(ptr, strlen(ptr));
|
||||
}
|
||||
|
||||
inline std::string SSLSocketStream::get_remote_addr()
|
||||
inline std::string SSLSocketStream::get_remote_addr() const
|
||||
{
|
||||
return detail::get_remote_addr(sock_);
|
||||
}
|
||||
@ -2597,7 +2712,7 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path)
|
||||
// SSL_CTX_set_tmp_ecdh(ctx_, ecdh);
|
||||
// EC_KEY_free(ecdh);
|
||||
|
||||
if(SSL_CTX_use_certificate_file(ctx_, cert_path, SSL_FILETYPE_PEM) != 1 ||
|
||||
if(SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
|
||||
SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != 1)
|
||||
{
|
||||
SSL_CTX_free(ctx_);
|
||||
@ -2656,10 +2771,15 @@ inline bool SSLClient::read_and_close_socket(socket_t sock, Request &req, Respon
|
||||
return process_request(strm, req, res, connection_close);
|
||||
});
|
||||
}
|
||||
|
||||
inline bool SSLClient::is_ssl() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace httplib
|
||||
|
||||
#endif
|
||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
||||
|
Loading…
Reference in New Issue
Block a user