Skip to content

Commit 1f1071c

Browse files
committed
Fix Windows test failure and add hex utility coverage
- Fix file_upload tests to use subdirectory instead of /tmp for cross-platform compatibility - Extract hex validation functions (is_valid_hex, hex_char_to_val) from webserver.cpp to string_utilities for testability - Add unit tests for hex utility functions to improve coverage
1 parent a4e514b commit 1f1071c

File tree

5 files changed

+74
-25
lines changed

5 files changed

+74
-25
lines changed

src/httpserver/string_utilities.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ const std::string to_upper_copy(const std::string& str);
4242
const std::string to_lower_copy(const std::string& str);
4343
const std::vector<std::string> string_split(const std::string& s, char sep = ' ', bool collapse = true);
4444

45+
/**
46+
* Validate that a string contains only valid hexadecimal characters (0-9, a-f, A-F)
47+
* @param s The string to validate
48+
* @return true if string contains only valid hex characters, false otherwise
49+
*/
50+
bool is_valid_hex(const std::string& s);
51+
52+
/**
53+
* Convert a hex character to its numeric value (0-15)
54+
* @param c The hex character to convert
55+
* @return numeric value (0-15), or 0 for invalid characters
56+
*/
57+
unsigned char hex_char_to_val(char c);
58+
4559
} // namespace string_utilities
4660

4761
} // namespace httpserver

src/string_utilities.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,22 @@ const std::vector<std::string> string_split(const std::string& s, char sep, bool
5555
return result;
5656
}
5757

58+
bool is_valid_hex(const std::string& s) {
59+
for (char c : s) {
60+
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
61+
(c >= 'A' && c <= 'F'))) {
62+
return false;
63+
}
64+
}
65+
return true;
66+
}
67+
68+
unsigned char hex_char_to_val(char c) {
69+
if (c >= '0' && c <= '9') return static_cast<unsigned char>(c - '0');
70+
if (c >= 'a' && c <= 'f') return static_cast<unsigned char>(c - 'a' + 10);
71+
if (c >= 'A' && c <= 'F') return static_cast<unsigned char>(c - 'A' + 10);
72+
return 0;
73+
}
74+
5875
} // namespace string_utilities
5976
} // namespace httpserver

src/webserver.cpp

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "httpserver/http_resource.hpp"
5959
#include "httpserver/http_response.hpp"
6060
#include "httpserver/http_utils.hpp"
61+
#include "httpserver/string_utilities.hpp"
6162
#include "httpserver/string_response.hpp"
6263

6364
struct MHD_Connection;
@@ -429,25 +430,6 @@ void webserver::disallow_ip(const string& ip) {
429430
}
430431

431432
#ifdef HAVE_GNUTLS
432-
// Validate that a string contains only valid hexadecimal characters
433-
static bool is_valid_hex(const std::string& s) {
434-
for (char c : s) {
435-
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
436-
(c >= 'A' && c <= 'F'))) {
437-
return false;
438-
}
439-
}
440-
return true;
441-
}
442-
443-
// Convert a hex character to its numeric value
444-
static unsigned char hex_char_to_val(char c) {
445-
if (c >= '0' && c <= '9') return static_cast<unsigned char>(c - '0');
446-
if (c >= 'a' && c <= 'f') return static_cast<unsigned char>(c - 'a' + 10);
447-
if (c >= 'A' && c <= 'F') return static_cast<unsigned char>(c - 'A' + 10);
448-
return 0;
449-
}
450-
451433
// MHD_PskServerCredentialsCallback signature:
452434
// The 'cls' parameter is our webserver pointer (passed via MHD_OPTION)
453435
// Returns 0 on success, -1 on error
@@ -476,7 +458,8 @@ int webserver::psk_cred_handler_func(void* cls,
476458

477459
// Validate hex string before allocating memory
478460
size_t psk_len = psk_hex.size() / 2;
479-
if (psk_len == 0 || (psk_hex.size() % 2 != 0) || !is_valid_hex(psk_hex)) {
461+
if (psk_len == 0 || (psk_hex.size() % 2 != 0) ||
462+
!string_utilities::is_valid_hex(psk_hex)) {
480463
return -1;
481464
}
482465

@@ -489,8 +472,8 @@ int webserver::psk_cred_handler_func(void* cls,
489472
// Convert hex string to binary
490473
for (size_t i = 0; i < psk_len; i++) {
491474
psk_data[i] = static_cast<unsigned char>(
492-
(hex_char_to_val(psk_hex[i * 2]) << 4) |
493-
hex_char_to_val(psk_hex[i * 2 + 1]));
475+
(string_utilities::hex_char_to_val(psk_hex[i * 2]) << 4) |
476+
string_utilities::hex_char_to_val(psk_hex[i * 2 + 1]));
494477
}
495478

496479
*psk = psk_data;

test/integ/file_upload.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,9 @@ LT_END_AUTO_TEST(file_cleanup_no_callback_deletes)
889889

890890
// Test file upload keeping original filename (without random generation)
891891
LT_BEGIN_AUTO_TEST(file_upload_suite, file_upload_original_filename)
892-
string upload_directory = "/tmp"; // Use temp directory to avoid conflicts
892+
// Use a subdirectory to avoid overwriting the test input file
893+
string upload_directory = "upload_test_dir";
894+
mkdir(upload_directory.c_str(), 0755);
893895

894896
auto ws = std::make_unique<webserver>(create_webserver(PORT)
895897
.file_upload_target(httpserver::FILE_UPLOAD_DISK_ONLY)
@@ -915,15 +917,16 @@ LT_BEGIN_AUTO_TEST(file_upload_suite, file_upload_original_filename)
915917

916918
ws->stop();
917919

918-
// Clean up the file
920+
// Clean up the file and directory
919921
unlink(expected_path.c_str());
922+
rmdir(upload_directory.c_str());
920923
LT_END_AUTO_TEST(file_upload_original_filename)
921924

922925
// Test file upload with explicit content-type header
923926
// This exercises the content_type != nullptr branch in webserver.cpp post_iterator
924927
LT_BEGIN_AUTO_TEST(file_upload_suite, file_upload_with_content_type)
925928
int port = PORT + 1;
926-
string upload_directory = "/tmp";
929+
string upload_directory = ".";
927930

928931
auto ws = std::make_unique<webserver>(create_webserver(port)
929932
.file_upload_target(httpserver::FILE_UPLOAD_DISK_ONLY)

test/unit/string_utilities_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,38 @@ LT_BEGIN_AUTO_TEST(string_utilities_suite, split_string_single_element)
173173
LT_CHECK_EQ(actual[0], "hello");
174174
LT_END_AUTO_TEST(split_string_single_element)
175175

176+
// Test is_valid_hex with valid strings
177+
LT_BEGIN_AUTO_TEST(string_utilities_suite, is_valid_hex_valid)
178+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("0123456789"), true);
179+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("abcdef"), true);
180+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("ABCDEF"), true);
181+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("0123456789abcdefABCDEF"), true);
182+
LT_END_AUTO_TEST(is_valid_hex_valid)
183+
184+
// Test is_valid_hex with invalid strings
185+
LT_BEGIN_AUTO_TEST(string_utilities_suite, is_valid_hex_invalid)
186+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("ZZZZ"), false);
187+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("hello"), false);
188+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("12g4"), false);
189+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex("12 34"), false);
190+
LT_END_AUTO_TEST(is_valid_hex_invalid)
191+
192+
// Test is_valid_hex with empty string
193+
LT_BEGIN_AUTO_TEST(string_utilities_suite, is_valid_hex_empty)
194+
LT_CHECK_EQ(httpserver::string_utilities::is_valid_hex(""), true);
195+
LT_END_AUTO_TEST(is_valid_hex_empty)
196+
197+
// Test hex_char_to_val with digits
198+
LT_BEGIN_AUTO_TEST(string_utilities_suite, hex_char_to_val_digits)
199+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('0'), 0);
200+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('9'), 9);
201+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('a'), 10);
202+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('f'), 15);
203+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('A'), 10);
204+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('F'), 15);
205+
LT_CHECK_EQ(httpserver::string_utilities::hex_char_to_val('z'), 0);
206+
LT_END_AUTO_TEST(hex_char_to_val_digits)
207+
176208
LT_BEGIN_AUTO_TEST_ENV()
177209
AUTORUN_TESTS()
178210
LT_END_AUTO_TEST_ENV()

0 commit comments

Comments
 (0)