|
3 | 3 | #include <signal.h>
|
4 | 4 |
|
5 | 5 | #ifndef _WIN32
|
| 6 | +#include <arpa/inet.h> |
6 | 7 | #include <curl/curl.h>
|
| 8 | +#include <netinet/in.h> |
| 9 | +#include <sys/socket.h> |
| 10 | +#include <unistd.h> |
7 | 11 | #endif
|
8 | 12 | #include <gtest/gtest.h>
|
9 | 13 |
|
@@ -3823,6 +3827,50 @@ TEST_F(ServerTest, TooLongHeader) {
|
3823 | 3827 | EXPECT_EQ(StatusCode::OK_200, res->status);
|
3824 | 3828 | }
|
3825 | 3829 |
|
| 3830 | +TEST_F(ServerTest, HeaderCountAtLimit) { |
| 3831 | + // Test with headers just under the 100 limit |
| 3832 | + httplib::Headers headers; |
| 3833 | + |
| 3834 | + // Add 95 custom headers (the client will add Host, User-Agent, Accept, etc.) |
| 3835 | + // This should keep us just under the 100 header limit |
| 3836 | + for (int i = 0; i < 95; i++) { |
| 3837 | + std::string name = "X-Test-Header-" + std::to_string(i); |
| 3838 | + std::string value = "value" + std::to_string(i); |
| 3839 | + headers.emplace(name, value); |
| 3840 | + } |
| 3841 | + |
| 3842 | + // This should work fine as we're under the limit |
| 3843 | + auto res = cli_.Get("/hi", headers); |
| 3844 | + EXPECT_TRUE(res); |
| 3845 | + if (res) { |
| 3846 | + EXPECT_EQ(StatusCode::OK_200, res->status); |
| 3847 | + } |
| 3848 | +} |
| 3849 | + |
| 3850 | +TEST_F(ServerTest, HeaderCountExceedsLimit) { |
| 3851 | + // Test with many headers to exceed the 100 limit |
| 3852 | + httplib::Headers headers; |
| 3853 | + |
| 3854 | + // Add 150 headers to definitely exceed the 100 limit |
| 3855 | + for (int i = 0; i < 150; i++) { |
| 3856 | + std::string name = "X-Test-Header-" + std::to_string(i); |
| 3857 | + std::string value = "value" + std::to_string(i); |
| 3858 | + headers.emplace(name, value); |
| 3859 | + } |
| 3860 | + |
| 3861 | + // This should fail due to exceeding header count limit |
| 3862 | + auto res = cli_.Get("/hi", headers); |
| 3863 | + |
| 3864 | + // The request should either fail or return 400 Bad Request |
| 3865 | + if (res) { |
| 3866 | + // If we get a response, it should be 400 Bad Request |
| 3867 | + EXPECT_EQ(StatusCode::BadRequest_400, res->status); |
| 3868 | + } else { |
| 3869 | + // Or the request should fail entirely |
| 3870 | + EXPECT_FALSE(res); |
| 3871 | + } |
| 3872 | +} |
| 3873 | + |
3826 | 3874 | TEST_F(ServerTest, PercentEncoding) {
|
3827 | 3875 | auto res = cli_.Get("/e%6edwith%");
|
3828 | 3876 | ASSERT_TRUE(res);
|
@@ -3860,6 +3908,32 @@ TEST_F(ServerTest, PlusSignEncoding) {
|
3860 | 3908 | EXPECT_EQ("a +b", res->body);
|
3861 | 3909 | }
|
3862 | 3910 |
|
| 3911 | +TEST_F(ServerTest, HeaderCountSecurityTest) { |
| 3912 | + // This test simulates a potential DoS attack using many headers |
| 3913 | + // to verify our security fix prevents memory exhaustion |
| 3914 | + |
| 3915 | + httplib::Headers attack_headers; |
| 3916 | + |
| 3917 | + // Attempt to add many headers like an attacker would (200 headers to far exceed limit) |
| 3918 | + for (int i = 0; i < 200; i++) { |
| 3919 | + std::string name = "X-Attack-Header-" + std::to_string(i); |
| 3920 | + std::string value = "attack_payload_" + std::to_string(i); |
| 3921 | + attack_headers.emplace(name, value); |
| 3922 | + } |
| 3923 | + |
| 3924 | + // Try to POST with excessive headers |
| 3925 | + auto res = cli_.Post("/", attack_headers, "test_data", "text/plain"); |
| 3926 | + |
| 3927 | + // Should either fail or return 400 Bad Request due to security limit |
| 3928 | + if (res) { |
| 3929 | + // If we get a response, it should be 400 Bad Request |
| 3930 | + EXPECT_EQ(StatusCode::BadRequest_400, res->status); |
| 3931 | + } else { |
| 3932 | + // Request failed, which is the expected behavior for DoS protection |
| 3933 | + EXPECT_FALSE(res); |
| 3934 | + } |
| 3935 | +} |
| 3936 | + |
3863 | 3937 | TEST_F(ServerTest, MultipartFormData) {
|
3864 | 3938 | MultipartFormDataItems items = {
|
3865 | 3939 | {"text1", "text default", "", ""},
|
|
0 commit comments