httplib: upgrade to git master (but use boost regex still)
This commit is contained in:
parent
944e3a03cb
commit
a202c47336
@ -1,42 +1,43 @@
|
|||||||
//
|
//
|
||||||
// httplib.h
|
// 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.
|
// Copyright (c) 2017 Yuji Hirose. All rights reserved.
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef _CPPHTTPLIB_HTTPLIB_H_
|
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||||
#define _CPPHTTPLIB_HTTPLIB_H_
|
#define CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif //_CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||||
#endif
|
#endif //_CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf_s
|
#define snprintf _snprintf_s
|
||||||
#endif
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#ifndef S_ISREG
|
#ifndef S_ISREG
|
||||||
#define S_ISREG(m) (((m)&S_IFREG)==S_IFREG)
|
#define S_ISREG(m) (((m)&S_IFREG)==S_IFREG)
|
||||||
#endif
|
#endif //S_ISREG
|
||||||
|
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
#define S_ISDIR(m) (((m)&S_IFDIR)==S_IFDIR)
|
#define S_ISDIR(m) (((m)&S_IFDIR)==S_IFDIR)
|
||||||
#endif
|
#endif //S_ISDIR
|
||||||
|
|
||||||
|
#define NOMINMAX
|
||||||
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
#ifndef strcasecmp
|
#ifndef strcasecmp
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif
|
#endif //strcasecmp
|
||||||
|
|
||||||
typedef SOCKET socket_t;
|
typedef SOCKET socket_t;
|
||||||
#else
|
#else
|
||||||
@ -52,7 +53,7 @@ typedef SOCKET socket_t;
|
|||||||
|
|
||||||
typedef int socket_t;
|
typedef int socket_t;
|
||||||
#define INVALID_SOCKET (-1)
|
#define INVALID_SOCKET (-1)
|
||||||
#endif
|
#endif //_WIN32
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -131,11 +132,13 @@ struct Request {
|
|||||||
Progress progress;
|
Progress progress;
|
||||||
|
|
||||||
bool has_header(const char* key) const;
|
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_header(const char* key, const char* val);
|
||||||
|
|
||||||
bool has_param(const char* key) const;
|
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;
|
bool has_file(const char* key) const;
|
||||||
MultipartFile get_file_value(const char* key) const;
|
MultipartFile get_file_value(const char* key) const;
|
||||||
@ -149,7 +152,8 @@ struct Response {
|
|||||||
std::function<std::string (uint64_t offset)> streamcb;
|
std::function<std::string (uint64_t offset)> streamcb;
|
||||||
|
|
||||||
bool has_header(const char* key) const;
|
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_header(const char* key, const char* val);
|
||||||
|
|
||||||
void set_redirect(const char* uri);
|
void set_redirect(const char* uri);
|
||||||
@ -165,7 +169,7 @@ 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;
|
||||||
virtual std::string get_remote_addr() = 0;
|
virtual std::string get_remote_addr() const = 0;
|
||||||
|
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
void write_format(const char* fmt, const Args& ...args);
|
void write_format(const char* fmt, const Args& ...args);
|
||||||
@ -179,12 +183,28 @@ public:
|
|||||||
virtual int read(char* ptr, size_t size);
|
virtual int read(char* ptr, size_t size);
|
||||||
virtual int write(const char* ptr, size_t size);
|
virtual int write(const char* ptr, size_t size);
|
||||||
virtual int write(const char* ptr);
|
virtual int write(const char* ptr);
|
||||||
virtual std::string get_remote_addr();
|
virtual std::string get_remote_addr() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
socket_t sock_;
|
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 {
|
class Server {
|
||||||
public:
|
public:
|
||||||
typedef std::function<void (const Request&, Response&)> Handler;
|
typedef std::function<void (const Request&, Response&)> Handler;
|
||||||
@ -303,6 +323,7 @@ private:
|
|||||||
void write_request(Stream& strm, Request& req);
|
void write_request(Stream& strm, Request& req);
|
||||||
|
|
||||||
virtual bool read_and_close_socket(socket_t sock, Request& req, Response& res);
|
virtual bool read_and_close_socket(socket_t sock, Request& req, Response& res);
|
||||||
|
virtual bool is_ssl() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
@ -314,7 +335,7 @@ public:
|
|||||||
virtual int read(char* ptr, size_t size);
|
virtual int read(char* ptr, size_t size);
|
||||||
virtual int write(const char* ptr, size_t size);
|
virtual int write(const char* ptr, size_t size);
|
||||||
virtual int write(const char* ptr);
|
virtual int write(const char* ptr);
|
||||||
virtual std::string get_remote_addr();
|
virtual std::string get_remote_addr() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
socket_t sock_;
|
socket_t sock_;
|
||||||
@ -341,7 +362,7 @@ class SSLClient : public Client {
|
|||||||
public:
|
public:
|
||||||
SSLClient(
|
SSLClient(
|
||||||
const char* host,
|
const char* host,
|
||||||
int port = 80,
|
int port = 443,
|
||||||
time_t timeout_sec = 300);
|
time_t timeout_sec = 300);
|
||||||
|
|
||||||
virtual ~SSLClient();
|
virtual ~SSLClient();
|
||||||
@ -350,6 +371,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool read_and_close_socket(socket_t sock, Request& req, Response& res);
|
virtual bool read_and_close_socket(socket_t sock, Request& req, Response& res);
|
||||||
|
virtual bool is_ssl() const;
|
||||||
|
|
||||||
SSL_CTX* ctx_;
|
SSL_CTX* ctx_;
|
||||||
std::mutex ctx_mutex_;
|
std::mutex ctx_mutex_;
|
||||||
@ -463,10 +485,10 @@ inline int select_read(socket_t sock, time_t sec, time_t usec)
|
|||||||
FD_SET(sock, &fds);
|
FD_SET(sock, &fds);
|
||||||
|
|
||||||
timeval tv;
|
timeval tv;
|
||||||
tv.tv_sec = sec;
|
tv.tv_sec = static_cast<long>(sec);
|
||||||
tv.tv_usec = usec;
|
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)
|
inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
|
||||||
@ -479,10 +501,10 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
|
|||||||
auto fdse = fdsr;
|
auto fdse = fdsr;
|
||||||
|
|
||||||
timeval tv;
|
timeval tv;
|
||||||
tv.tv_sec = sec;
|
tv.tv_sec = static_cast<long>(sec);
|
||||||
tv.tv_usec = usec;
|
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;
|
return false;
|
||||||
} else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) {
|
} else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) {
|
||||||
int error = 0;
|
int error = 0;
|
||||||
@ -752,9 +774,10 @@ inline bool has_header(const Headers& headers, const char* key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline const char* get_header_value(
|
inline const char* get_header_value(
|
||||||
const Headers& headers, const char* key, const char* def = nullptr)
|
const Headers& headers, const char* key, size_t id = 0, const char* def = nullptr)
|
||||||
{
|
{
|
||||||
auto it = headers.find(key);
|
auto it = headers.find(key);
|
||||||
|
std::advance(it, id);
|
||||||
if (it != headers.end()) {
|
if (it != headers.end()) {
|
||||||
return it->second.c_str();
|
return it->second.c_str();
|
||||||
}
|
}
|
||||||
@ -886,14 +909,14 @@ bool read_content(Stream& strm, T& x, Progress progress = Progress())
|
|||||||
if (has_header(x.headers, "Content-Length")) {
|
if (has_header(x.headers, "Content-Length")) {
|
||||||
auto len = get_header_value_int(x.headers, "Content-Length", 0);
|
auto len = get_header_value_int(x.headers, "Content-Length", 0);
|
||||||
if (len == 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")) {
|
if (!strcasecmp(encoding, "chunked")) {
|
||||||
return read_content_chunked(strm, x.body);
|
return read_content_chunked(strm, x.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return read_content_with_length(strm, x.body, len, progress);
|
return read_content_with_length(strm, x.body, len, progress);
|
||||||
} else {
|
} 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")) {
|
if (!strcasecmp(encoding, "chunked")) {
|
||||||
return read_content_chunked(strm, x.body);
|
return read_content_chunked(strm, x.body);
|
||||||
}
|
}
|
||||||
@ -917,7 +940,8 @@ inline std::string encode_url(const std::string& s)
|
|||||||
|
|
||||||
for (auto i = 0; s[i]; i++) {
|
for (auto i = 0; s[i]; i++) {
|
||||||
switch (s[i]) {
|
switch (s[i]) {
|
||||||
case ' ': result += "+"; break;
|
case ' ': result += "%20"; break;
|
||||||
|
case '+': result += "%2B"; break;
|
||||||
case '\'': result += "%27"; break;
|
case '\'': result += "%27"; break;
|
||||||
case ',': result += "%2C"; break;
|
case ',': result += "%2C"; break;
|
||||||
case ':': result += "%3A"; break;
|
case ':': result += "%3A"; break;
|
||||||
@ -1313,9 +1337,15 @@ inline bool Request::has_header(const char* key) const
|
|||||||
return detail::has_header(headers, key);
|
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)
|
inline void Request::set_header(const char* key, const char* val)
|
||||||
@ -1328,15 +1358,22 @@ inline bool Request::has_param(const char* key) const
|
|||||||
return params.find(key) != params.end();
|
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);
|
auto it = params.find(key);
|
||||||
|
std::advance(it, id);
|
||||||
if (it != params.end()) {
|
if (it != params.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
return std::string();
|
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
|
inline bool Request::has_file(const char* key) const
|
||||||
{
|
{
|
||||||
return files.find(key) != files.end();
|
return files.find(key) != files.end();
|
||||||
@ -1357,9 +1394,15 @@ inline bool Response::has_header(const char* key) const
|
|||||||
return headers.find(key) != headers.end();
|
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)
|
inline void Response::set_header(const char* key, const char* val)
|
||||||
@ -1427,12 +1470,12 @@ inline SocketStream::~SocketStream()
|
|||||||
|
|
||||||
inline int SocketStream::read(char* ptr, size_t size)
|
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)
|
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)
|
inline int SocketStream::write(const char* ptr)
|
||||||
@ -1440,10 +1483,42 @@ inline int SocketStream::write(const char* ptr)
|
|||||||
return write(ptr, strlen(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_);
|
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
|
// HTTP server implementation
|
||||||
inline Server::Server()
|
inline Server::Server()
|
||||||
: keep_alive_max_count_(5)
|
: keep_alive_max_count_(5)
|
||||||
@ -1593,7 +1668,16 @@ inline void Server::write_response(Stream& strm, bool last_connection, const Req
|
|||||||
res.set_header("Connection", "Keep-Alive");
|
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
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
// TODO: 'Accpet-Encoding' has gzip, not gzip;q=0
|
// TODO: 'Accpet-Encoding' has gzip, not gzip;q=0
|
||||||
const auto& encodings = req.get_header_value("Accept-Encoding");
|
const auto& encodings = req.get_header_value("Accept-Encoding");
|
||||||
@ -1610,11 +1694,6 @@ inline void Server::write_response(Stream& strm, bool last_connection, const Req
|
|||||||
|
|
||||||
auto length = std::to_string(res.body.size());
|
auto length = std::to_string(res.body.size());
|
||||||
res.set_header("Content-Length", length.c_str());
|
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);
|
detail::write_headers(strm, res);
|
||||||
@ -1673,7 +1752,7 @@ inline socket_t Server::create_server_socket(const char* host, int port, int soc
|
|||||||
{
|
{
|
||||||
return detail::create_socket(host, port,
|
return detail::create_socket(host, port,
|
||||||
[](socket_t sock, struct addrinfo& ai) -> bool {
|
[](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;
|
return false;
|
||||||
}
|
}
|
||||||
if (::listen(sock, 5)) { // Listen through 5 channels
|
if (::listen(sock, 5)) { // Listen through 5 channels
|
||||||
@ -1920,7 +1999,7 @@ inline socket_t Client::create_client_socket() const
|
|||||||
[=](socket_t sock, struct addrinfo& ai) -> bool {
|
[=](socket_t sock, struct addrinfo& ai) -> bool {
|
||||||
detail::set_nonblocking(sock, true);
|
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 (ret < 0) {
|
||||||
if (detail::is_connection_error() ||
|
if (detail::is_connection_error() ||
|
||||||
!detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) {
|
!detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) {
|
||||||
@ -1945,7 +2024,7 @@ inline bool Client::read_response_line(Stream& strm, Response& res)
|
|||||||
return false;
|
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;
|
boost::cmatch m;
|
||||||
if (boost::regex_match(reader.ptr(), m, re)) {
|
if (boost::regex_match(reader.ptr(), m, re)) {
|
||||||
@ -1972,15 +2051,29 @@ inline bool Client::send(Request& req, Response& res)
|
|||||||
|
|
||||||
inline void Client::write_request(Stream& strm, Request& req)
|
inline void Client::write_request(Stream& strm, Request& req)
|
||||||
{
|
{
|
||||||
auto path = detail::encode_url(req.path);
|
BufferStream bstrm;
|
||||||
|
|
||||||
// Request line
|
// Request line
|
||||||
strm.write_format("%s %s HTTP/1.1\r\n",
|
auto path = detail::encode_url(req.path);
|
||||||
|
|
||||||
|
bstrm.write_format("%s %s HTTP/1.1\r\n",
|
||||||
req.method.c_str(),
|
req.method.c_str(),
|
||||||
path.c_str());
|
path.c_str());
|
||||||
|
|
||||||
// Headers
|
// Headers
|
||||||
|
if (is_ssl()) {
|
||||||
|
if (port_ == 443) {
|
||||||
|
req.set_header("Host", host_.c_str());
|
||||||
|
} else {
|
||||||
req.set_header("Host", host_and_port_.c_str());
|
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")) {
|
if (!req.has_header("Accept")) {
|
||||||
req.set_header("Accept", "*/*");
|
req.set_header("Accept", "*/*");
|
||||||
@ -2008,17 +2101,16 @@ inline void Client::write_request(Stream& strm, Request& req)
|
|||||||
req.set_header("Content-Length", length.c_str());
|
req.set_header("Content-Length", length.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::write_headers(strm, req);
|
detail::write_headers(bstrm, req);
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
if (!req.body.empty()) {
|
if (!req.body.empty()) {
|
||||||
if (req.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
|
bstrm.write(req.body.c_str(), req.body.size());
|
||||||
auto str = detail::encode_url(req.body);
|
|
||||||
strm.write(str.c_str(), str.size());
|
|
||||||
} else {
|
|
||||||
strm.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)
|
inline bool Client::process_request(Stream& strm, Request& req, Response& res, bool& connection_close)
|
||||||
@ -2063,6 +2155,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)
|
inline std::shared_ptr<Response> Client::Get(const char* path, Progress progress)
|
||||||
{
|
{
|
||||||
return Get(path, Headers(), progress);
|
return Get(path, Headers(), progress);
|
||||||
@ -2302,7 +2399,7 @@ inline int SSLSocketStream::write(const char* ptr)
|
|||||||
return write(ptr, strlen(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_);
|
return detail::get_remote_addr(sock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2321,7 +2418,7 @@ inline SSLServer::SSLServer(const char* cert_path, const char* private_key_path)
|
|||||||
// SSL_CTX_set_tmp_ecdh(ctx_, ecdh);
|
// SSL_CTX_set_tmp_ecdh(ctx_, ecdh);
|
||||||
// EC_KEY_free(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_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != 1) {
|
||||||
SSL_CTX_free(ctx_);
|
SSL_CTX_free(ctx_);
|
||||||
ctx_ = nullptr;
|
ctx_ = nullptr;
|
||||||
@ -2386,10 +2483,15 @@ inline bool SSLClient::read_and_close_socket(socket_t sock, Request& req, Respon
|
|||||||
return process_request(strm, req, res, connection_close);
|
return process_request(strm, req, res, connection_close);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool SSLClient::is_ssl() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace httplib
|
} // namespace httplib
|
||||||
|
|
||||||
#endif
|
#endif //CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
||||||
|
Loading…
Reference in New Issue
Block a user