mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-15 10:39:37 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a1700cb5e | ||
|
|
c03af246fc | ||
|
|
2c918f27ee | ||
|
|
924b5cecf0 |
No files matched your search
@@ -5604,6 +5604,18 @@ inline bool is_websocket_upgrade(const Request &req) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unpredictable bytes for masking keys (RFC 6455 Section 5.3) and nonces
|
||||
inline void fill_random_bytes(unsigned char *out, size_t n) {
|
||||
thread_local std::random_device rd;
|
||||
size_t filled = 0;
|
||||
while (filled < n) {
|
||||
auto v = rd();
|
||||
for (size_t b = 0; b < sizeof(v) && filled < n; ++b, ++filled) {
|
||||
out[filled] = static_cast<unsigned char>((v >> (b * 8)) & 0xFFu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode,
|
||||
const char *data, size_t len, bool fin,
|
||||
bool mask) {
|
||||
@@ -5639,10 +5651,8 @@ inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode,
|
||||
|
||||
if (mask) {
|
||||
// Generate random mask key
|
||||
thread_local std::mt19937 rng(std::random_device{}());
|
||||
uint8_t mask_key[4];
|
||||
auto r = rng();
|
||||
std::memcpy(mask_key, &r, 4);
|
||||
fill_random_bytes(mask_key, sizeof(mask_key));
|
||||
if (strm.write(reinterpret_cast<char *>(mask_key), 4) < 0) { return false; }
|
||||
|
||||
// Write masked payload in chunks
|
||||
@@ -9665,19 +9675,10 @@ inline std::string random_string(size_t length) {
|
||||
constexpr const char data[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
thread_local auto engine([]() {
|
||||
// std::random_device might actually be deterministic on some
|
||||
// platforms, but due to lack of support in the c++ standard library,
|
||||
// doing better requires either some ugly hacks or breaking portability.
|
||||
std::random_device seed_gen;
|
||||
// Request 128 bits of entropy for initialization
|
||||
std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
|
||||
return std::mt19937(seed_sequence);
|
||||
}());
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
result += data[engine() % (sizeof(data) - 1)];
|
||||
std::string result(length, '\0');
|
||||
fill_random_bytes(reinterpret_cast<unsigned char *>(&result[0]), length);
|
||||
for (auto &c : result) {
|
||||
c = data[static_cast<unsigned char>(c) % (sizeof(data) - 1)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -10364,13 +10365,10 @@ inline bool is_host(const std::string &s) {
|
||||
|
||||
inline bool perform_websocket_handshake(Stream &strm, Request &req,
|
||||
WebSocketUpgradeResponse &upgrade) {
|
||||
// Generate random Sec-WebSocket-Key
|
||||
thread_local std::mt19937 rng(std::random_device{}());
|
||||
// Generate a random 16-byte Sec-WebSocket-Key (RFC 6455 Section 4.1)
|
||||
std::string key_bytes(16, '\0');
|
||||
for (size_t i = 0; i < 16; i += 4) {
|
||||
auto r = rng();
|
||||
std::memcpy(&key_bytes[i], &r, (std::min)(size_t(4), size_t(16 - i)));
|
||||
}
|
||||
fill_random_bytes(reinterpret_cast<unsigned char *>(&key_bytes[0]),
|
||||
key_bytes.size());
|
||||
auto client_key = base64_encode(key_bytes);
|
||||
|
||||
req.headers.erase("Upgrade");
|
||||
@@ -13869,7 +13867,11 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
detail::FileStat stat(path);
|
||||
|
||||
if (stat.is_dir()) {
|
||||
res.set_redirect(sub_path + "/", StatusCode::MovedPermanently_301);
|
||||
// Relative, so "//dir" cannot name another host; "./" keeps a ':'
|
||||
// in the name from reading as a scheme.
|
||||
auto name = req.path.substr(req.path.rfind('/') + 1);
|
||||
res.set_redirect("./" + encode_path_component(name) + "/",
|
||||
StatusCode::MovedPermanently_301);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6660,6 +6660,20 @@ TEST_F(ServerTest, GetMethodOutOfBaseDirMountWithBackslash) {
|
||||
EXPECT_EQ(StatusCode::NotFound_404, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetMethodDirMountWithoutTrailingSlash) {
|
||||
auto res = cli_.Get("/mount/dir");
|
||||
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||
EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
|
||||
EXPECT_EQ("./dir/", res->get_header_value("Location"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetMethodDirWithLeadingDoubleSlash) {
|
||||
auto res = cli_.Get("//dir");
|
||||
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||
EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
|
||||
EXPECT_EQ("./dir/", res->get_header_value("Location"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostMethod303) {
|
||||
auto res = cli_.Post("/1", "body", "text/plain");
|
||||
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||
|
||||
Reference in new issue
Block a user