mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2025-05-10 09:43:51 +00:00
Code cleanup
This commit is contained in:
parent
fccb84f5e8
commit
849add5887
426
httplib.h
426
httplib.h
@ -445,75 +445,141 @@ private:
|
|||||||
*/
|
*/
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
inline bool is_hex(char c, int &v) {
|
||||||
inline bool can_compress(const std::string &content_type) {
|
if (0x20 <= c && isdigit(c)) {
|
||||||
return !content_type.find("text/") || content_type == "image/svg+xml" ||
|
v = c - '0';
|
||||||
content_type == "application/javascript" ||
|
return true;
|
||||||
content_type == "application/json" ||
|
} else if ('A' <= c && c <= 'F') {
|
||||||
content_type == "application/xml" ||
|
v = c - 'A' + 10;
|
||||||
content_type == "application/xhtml+xml";
|
return true;
|
||||||
|
} else if ('a' <= c && c <= 'f') {
|
||||||
|
v = c - 'a' + 10;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void compress(std::string &content) {
|
inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
|
||||||
z_stream strm;
|
int &val) {
|
||||||
strm.zalloc = Z_NULL;
|
if (i >= s.size()) { return false; }
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
|
|
||||||
auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
|
val = 0;
|
||||||
Z_DEFAULT_STRATEGY);
|
for (; cnt; i++, cnt--) {
|
||||||
if (ret != Z_OK) { return; }
|
if (!s[i]) { return false; }
|
||||||
|
int v = 0;
|
||||||
|
if (is_hex(s[i], v)) {
|
||||||
|
val = val * 16 + v;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
strm.avail_in = content.size();
|
inline std::string from_i_to_hex(uint64_t n) {
|
||||||
strm.next_in = (Bytef *)content.data();
|
const char *charset = "0123456789abcdef";
|
||||||
|
std::string ret;
|
||||||
std::string compressed;
|
|
||||||
|
|
||||||
const auto bufsiz = 16384;
|
|
||||||
char buff[bufsiz];
|
|
||||||
do {
|
do {
|
||||||
strm.avail_out = bufsiz;
|
ret = charset[n & 15] + ret;
|
||||||
strm.next_out = (Bytef *)buff;
|
n >>= 4;
|
||||||
deflate(&strm, Z_FINISH);
|
} while (n > 0);
|
||||||
compressed.append(buff, bufsiz - strm.avail_out);
|
return ret;
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
|
|
||||||
content.swap(compressed);
|
|
||||||
|
|
||||||
deflateEnd(&strm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void decompress(std::string &content) {
|
inline size_t to_utf8(int code, char *buff) {
|
||||||
z_stream strm;
|
if (code < 0x0080) {
|
||||||
strm.zalloc = Z_NULL;
|
buff[0] = (code & 0x7F);
|
||||||
strm.zfree = Z_NULL;
|
return 1;
|
||||||
strm.opaque = Z_NULL;
|
} else if (code < 0x0800) {
|
||||||
|
buff[0] = (0xC0 | ((code >> 6) & 0x1F));
|
||||||
|
buff[1] = (0x80 | (code & 0x3F));
|
||||||
|
return 2;
|
||||||
|
} else if (code < 0xD800) {
|
||||||
|
buff[0] = (0xE0 | ((code >> 12) & 0xF));
|
||||||
|
buff[1] = (0x80 | ((code >> 6) & 0x3F));
|
||||||
|
buff[2] = (0x80 | (code & 0x3F));
|
||||||
|
return 3;
|
||||||
|
} else if (code < 0xE000) { // D800 - DFFF is invalid...
|
||||||
|
return 0;
|
||||||
|
} else if (code < 0x10000) {
|
||||||
|
buff[0] = (0xE0 | ((code >> 12) & 0xF));
|
||||||
|
buff[1] = (0x80 | ((code >> 6) & 0x3F));
|
||||||
|
buff[2] = (0x80 | (code & 0x3F));
|
||||||
|
return 3;
|
||||||
|
} else if (code < 0x110000) {
|
||||||
|
buff[0] = (0xF0 | ((code >> 18) & 0x7));
|
||||||
|
buff[1] = (0x80 | ((code >> 12) & 0x3F));
|
||||||
|
buff[2] = (0x80 | ((code >> 6) & 0x3F));
|
||||||
|
buff[3] = (0x80 | (code & 0x3F));
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
// 15 is the value of wbits, which should be at the maximum possible value to
|
// NOTREACHED
|
||||||
// ensure that any gzip stream can be decoded. The offset of 16 specifies that
|
return 0;
|
||||||
// the stream to decompress will be formatted with a gzip wrapper.
|
}
|
||||||
auto ret = inflateInit2(&strm, 16 + 15);
|
|
||||||
if (ret != Z_OK) { return; }
|
inline bool is_file(const std::string &path) {
|
||||||
|
struct stat st;
|
||||||
strm.avail_in = content.size();
|
return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
|
||||||
strm.next_in = (Bytef *)content.data();
|
}
|
||||||
|
|
||||||
std::string decompressed;
|
inline bool is_dir(const std::string &path) {
|
||||||
|
struct stat st;
|
||||||
const auto bufsiz = 16384;
|
return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
|
||||||
char buff[bufsiz];
|
}
|
||||||
do {
|
|
||||||
strm.avail_out = bufsiz;
|
inline bool is_valid_path(const std::string &path) {
|
||||||
strm.next_out = (Bytef *)buff;
|
size_t level = 0;
|
||||||
inflate(&strm, Z_NO_FLUSH);
|
size_t i = 0;
|
||||||
decompressed.append(buff, bufsiz - strm.avail_out);
|
|
||||||
} while (strm.avail_out == 0);
|
// Skip slash
|
||||||
|
while (i < path.size() && path[i] == '/') {
|
||||||
content.swap(decompressed);
|
i++;
|
||||||
|
}
|
||||||
inflateEnd(&strm);
|
|
||||||
|
while (i < path.size()) {
|
||||||
|
// Read component
|
||||||
|
auto beg = i;
|
||||||
|
while (i < path.size() && path[i] != '/') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto len = i - beg;
|
||||||
|
assert(len > 0);
|
||||||
|
|
||||||
|
if (!path.compare(beg, len, ".")) {
|
||||||
|
;
|
||||||
|
} else if (!path.compare(beg, len, "..")) {
|
||||||
|
if (level == 0) { return false; }
|
||||||
|
level--;
|
||||||
|
} else {
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip slash
|
||||||
|
while (i < path.size() && path[i] == '/') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void read_file(const std::string &path, std::string &out) {
|
||||||
|
std::ifstream fs(path, std::ios_base::binary);
|
||||||
|
fs.seekg(0, std::ios_base::end);
|
||||||
|
auto size = fs.tellg();
|
||||||
|
fs.seekg(0);
|
||||||
|
out.resize(static_cast<size_t>(size));
|
||||||
|
fs.read(&out[0], size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string file_extension(const std::string &path) {
|
||||||
|
std::smatch m;
|
||||||
|
auto pat = std::regex("\\.([a-zA-Z0-9]+)$");
|
||||||
|
if (std::regex_search(path, m, pat)) { return m[1].str(); }
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class Fn> void split(const char *b, const char *e, char d, Fn fn) {
|
template <class Fn> void split(const char *b, const char *e, char d, Fn fn) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -783,69 +849,6 @@ inline std::string get_remote_addr(socket_t sock) {
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_file(const std::string &path) {
|
|
||||||
struct stat st;
|
|
||||||
return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_dir(const std::string &path) {
|
|
||||||
struct stat st;
|
|
||||||
return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_valid_path(const std::string &path) {
|
|
||||||
size_t level = 0;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
// Skip slash
|
|
||||||
while (i < path.size() && path[i] == '/') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i < path.size()) {
|
|
||||||
// Read component
|
|
||||||
auto beg = i;
|
|
||||||
while (i < path.size() && path[i] != '/') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto len = i - beg;
|
|
||||||
assert(len > 0);
|
|
||||||
|
|
||||||
if (!path.compare(beg, len, ".")) {
|
|
||||||
;
|
|
||||||
} else if (!path.compare(beg, len, "..")) {
|
|
||||||
if (level == 0) { return false; }
|
|
||||||
level--;
|
|
||||||
} else {
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip slash
|
|
||||||
while (i < path.size() && path[i] == '/') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void read_file(const std::string &path, std::string &out) {
|
|
||||||
std::ifstream fs(path, std::ios_base::binary);
|
|
||||||
fs.seekg(0, std::ios_base::end);
|
|
||||||
auto size = fs.tellg();
|
|
||||||
fs.seekg(0);
|
|
||||||
out.resize(static_cast<size_t>(size));
|
|
||||||
fs.read(&out[0], size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string file_extension(const std::string &path) {
|
|
||||||
std::smatch m;
|
|
||||||
auto pat = std::regex("\\.([a-zA-Z0-9]+)$");
|
|
||||||
if (std::regex_search(path, m, pat)) { return m[1].str(); }
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *find_content_type(const std::string &path) {
|
inline const char *find_content_type(const std::string &path) {
|
||||||
auto ext = file_extension(path);
|
auto ext = file_extension(path);
|
||||||
if (ext == "txt") {
|
if (ext == "txt") {
|
||||||
@ -896,6 +899,76 @@ inline const char *status_message(int status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
|
inline bool can_compress(const std::string &content_type) {
|
||||||
|
return !content_type.find("text/") || content_type == "image/svg+xml" ||
|
||||||
|
content_type == "application/javascript" ||
|
||||||
|
content_type == "application/json" ||
|
||||||
|
content_type == "application/xml" ||
|
||||||
|
content_type == "application/xhtml+xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void compress(std::string &content) {
|
||||||
|
z_stream strm;
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
|
||||||
|
auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
|
||||||
|
Z_DEFAULT_STRATEGY);
|
||||||
|
if (ret != Z_OK) { return; }
|
||||||
|
|
||||||
|
strm.avail_in = content.size();
|
||||||
|
strm.next_in = (Bytef *)content.data();
|
||||||
|
|
||||||
|
std::string compressed;
|
||||||
|
|
||||||
|
const auto bufsiz = 16384;
|
||||||
|
char buff[bufsiz];
|
||||||
|
do {
|
||||||
|
strm.avail_out = bufsiz;
|
||||||
|
strm.next_out = (Bytef *)buff;
|
||||||
|
deflate(&strm, Z_FINISH);
|
||||||
|
compressed.append(buff, bufsiz - strm.avail_out);
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
content.swap(compressed);
|
||||||
|
|
||||||
|
deflateEnd(&strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void decompress(std::string &content) {
|
||||||
|
z_stream strm;
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
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.
|
||||||
|
auto ret = inflateInit2(&strm, 16 + 15);
|
||||||
|
if (ret != Z_OK) { return; }
|
||||||
|
|
||||||
|
strm.avail_in = content.size();
|
||||||
|
strm.next_in = (Bytef *)content.data();
|
||||||
|
|
||||||
|
std::string decompressed;
|
||||||
|
|
||||||
|
const auto bufsiz = 16384;
|
||||||
|
char buff[bufsiz];
|
||||||
|
do {
|
||||||
|
strm.avail_out = bufsiz;
|
||||||
|
strm.next_out = (Bytef *)buff;
|
||||||
|
inflate(&strm, Z_NO_FLUSH);
|
||||||
|
decompressed.append(buff, bufsiz - strm.avail_out);
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
content.swap(decompressed);
|
||||||
|
|
||||||
|
inflateEnd(&strm);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
inline bool has_header(const Headers &headers, const char *key) {
|
inline bool has_header(const Headers &headers, const char *key) {
|
||||||
return headers.find(key) != headers.end();
|
return headers.find(key) != headers.end();
|
||||||
}
|
}
|
||||||
@ -1084,6 +1157,27 @@ template <typename T> inline void write_headers(Stream &strm, const T &info) {
|
|||||||
strm.write("\r\n");
|
strm.write("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void write_content_chunked(Stream &strm, const T& x) {
|
||||||
|
auto chunked_response = !x.has_header("Content-Length");
|
||||||
|
uint64_t offset = 0;
|
||||||
|
auto data_available = true;
|
||||||
|
while (data_available) {
|
||||||
|
auto chunk = x.streamcb(offset);
|
||||||
|
offset += chunk.size();
|
||||||
|
data_available = !chunk.empty();
|
||||||
|
|
||||||
|
// Emit chunked response header and footer for each chunk
|
||||||
|
if (chunked_response) {
|
||||||
|
chunk = from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strm.write(chunk.c_str(), chunk.size()) < 0) {
|
||||||
|
break; // Stop on error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string encode_url(const std::string &s) {
|
inline std::string encode_url(const std::string &s) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
@ -1115,79 +1209,6 @@ inline std::string encode_url(const std::string &s) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_hex(char c, int &v) {
|
|
||||||
if (0x20 <= c && isdigit(c)) {
|
|
||||||
v = c - '0';
|
|
||||||
return true;
|
|
||||||
} else if ('A' <= c && c <= 'F') {
|
|
||||||
v = c - 'A' + 10;
|
|
||||||
return true;
|
|
||||||
} else if ('a' <= c && c <= 'f') {
|
|
||||||
v = c - 'a' + 10;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
|
|
||||||
int &val) {
|
|
||||||
if (i >= s.size()) { return false; }
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
for (; cnt; i++, cnt--) {
|
|
||||||
if (!s[i]) { return false; }
|
|
||||||
int v = 0;
|
|
||||||
if (is_hex(s[i], v)) {
|
|
||||||
val = val * 16 + v;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string from_i_to_hex(uint64_t n) {
|
|
||||||
const char *charset = "0123456789abcdef";
|
|
||||||
std::string ret;
|
|
||||||
do {
|
|
||||||
ret = charset[n & 15] + ret;
|
|
||||||
n >>= 4;
|
|
||||||
} while (n > 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t to_utf8(int code, char *buff) {
|
|
||||||
if (code < 0x0080) {
|
|
||||||
buff[0] = (code & 0x7F);
|
|
||||||
return 1;
|
|
||||||
} else if (code < 0x0800) {
|
|
||||||
buff[0] = (0xC0 | ((code >> 6) & 0x1F));
|
|
||||||
buff[1] = (0x80 | (code & 0x3F));
|
|
||||||
return 2;
|
|
||||||
} else if (code < 0xD800) {
|
|
||||||
buff[0] = (0xE0 | ((code >> 12) & 0xF));
|
|
||||||
buff[1] = (0x80 | ((code >> 6) & 0x3F));
|
|
||||||
buff[2] = (0x80 | (code & 0x3F));
|
|
||||||
return 3;
|
|
||||||
} else if (code < 0xE000) { // D800 - DFFF is invalid...
|
|
||||||
return 0;
|
|
||||||
} else if (code < 0x10000) {
|
|
||||||
buff[0] = (0xE0 | ((code >> 12) & 0xF));
|
|
||||||
buff[1] = (0x80 | ((code >> 6) & 0x3F));
|
|
||||||
buff[2] = (0x80 | (code & 0x3F));
|
|
||||||
return 3;
|
|
||||||
} else if (code < 0x110000) {
|
|
||||||
buff[0] = (0xF0 | ((code >> 18) & 0x7));
|
|
||||||
buff[1] = (0x80 | ((code >> 12) & 0x3F));
|
|
||||||
buff[2] = (0x80 | ((code >> 6) & 0x3F));
|
|
||||||
buff[3] = (0x80 | (code & 0x3F));
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTREACHED
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string decode_url(const std::string &s) {
|
inline std::string decode_url(const std::string &s) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
@ -1694,18 +1715,7 @@ inline void Server::write_response(Stream &strm, bool last_connection,
|
|||||||
if (!res.body.empty()) {
|
if (!res.body.empty()) {
|
||||||
strm.write(res.body.c_str(), res.body.size());
|
strm.write(res.body.c_str(), res.body.size());
|
||||||
} else if (res.streamcb) {
|
} else if (res.streamcb) {
|
||||||
bool chunked_response = !res.has_header("Content-Length");
|
detail::write_content_chunked(strm, res);
|
||||||
uint64_t offset = 0;
|
|
||||||
bool data_available = true;
|
|
||||||
while (data_available) {
|
|
||||||
std::string chunk = res.streamcb(offset);
|
|
||||||
offset += chunk.size();
|
|
||||||
data_available = !chunk.empty();
|
|
||||||
// Emit chunked response header and footer for each chunk
|
|
||||||
if (chunked_response)
|
|
||||||
chunk = detail::from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n";
|
|
||||||
if (strm.write(chunk.c_str(), chunk.size()) < 0) break; // Stop on error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user