if (!detail::fields::is_field_value(val)) { return false; }
- if (case_ignore::equal(key, "Location") ||
- case_ignore::equal(key, "Referer")) {
- fn(key, val);
- } else {
- fn(key, decode_path_component(val));
- }
+ // RFC 9110 ยง5.5: header field values are opaque octets and MUST NOT be
+ // percent-decoded by the recipient. Applications that need to interpret a
+ // value as a URI component should call httplib::decode_uri_component()
+ // (or decode_path_component()) explicitly.
+ fn(key, val);
return true;
}
#endif
max_thread_count_ = max_n == 0 ? n : max_n;
threads_.reserve(base_thread_count_);
- for (size_t i = 0; i < base_thread_count_; i++) {
- threads_.emplace_back(std::thread([this]() { worker(false); }));
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+ try {
+#endif
+ for (size_t i = 0; i < base_thread_count_; i++) {
+ threads_.emplace_back(std::thread([this]() { worker(false); }));
+ }
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+ } catch (...) {
+ // If thread creation fails partway (e.g., pthread_create returns EAGAIN),
+ // signal the workers we already spawned to exit and join them so the
+ // vector destructor does not see joinable threads (which would call
+ // std::terminate). Then rethrow so the caller learns of the failure.
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ shutdown_ = true;
+ }
+ cond_.notify_all();
+ for (auto &t : threads_) {
+ if (t.joinable()) { t.join(); }
+ }
+ throw;
}
+#endif
}
bool ThreadPool::enqueue(std::function<void()> fn) {
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
-#define CPPHTTPLIB_VERSION "0.43.4"
-#define CPPHTTPLIB_VERSION_NUM "0x002b04"
+#define CPPHTTPLIB_VERSION "0.44.0"
+#define CPPHTTPLIB_VERSION_NUM "0x002c00"
#ifdef _WIN32
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00