@@ -3037,13 +3037,13 @@ inline time_t parse_http_date(const std::string &date_str) {
30373037#endif
30383038}
30393039
3040- // Check if the string is a weak ETag (starts with 'W/"')
30413040inline bool is_weak_etag (const std::string &s) {
3041+ // Check if the string is a weak ETag (starts with 'W/"')
30423042 return s.size () > 3 && s[0 ] == ' W' && s[1 ] == ' /' && s[2 ] == ' "' ;
30433043}
30443044
3045- // Check if the string is a strong ETag (starts with '"' but not 'W/"')
30463045inline bool is_strong_etag (const std::string &s) {
3046+ // Check if the string is a strong ETag (starts with '"' but not 'W/"')
30473047 return !s.empty () && s[0 ] == ' "' ;
30483048}
30493049
@@ -3429,6 +3429,42 @@ inline void split(const char *b, const char *e, char d, size_t m,
34293429 }
34303430}
34313431
3432+ inline bool split_find (const char *b, const char *e, char d, size_t m,
3433+ std::function<bool (const char *, const char *)> fn) {
3434+ size_t i = 0 ;
3435+ size_t beg = 0 ;
3436+ size_t count = 1 ;
3437+
3438+ while (e ? (b + i < e) : (b[i] != ' \0 ' )) {
3439+ if (b[i] == d && count < m) {
3440+ auto r = trim (b, e, beg, i);
3441+ if (r.first < r.second ) {
3442+ auto found = fn (&b[r.first ], &b[r.second ]);
3443+ if (found) { return true ; }
3444+ }
3445+ beg = i + 1 ;
3446+ count++;
3447+ }
3448+ i++;
3449+ }
3450+
3451+ if (i) {
3452+ auto r = trim (b, e, beg, i);
3453+ if (r.first < r.second ) {
3454+ auto found = fn (&b[r.first ], &b[r.second ]);
3455+ if (found) { return true ; }
3456+ }
3457+ }
3458+
3459+ return false ;
3460+ }
3461+
3462+ inline bool split_find (const char *b, const char *e, char d,
3463+ std::function<bool (const char *, const char *)> fn) {
3464+ return split_find (b, e, d, (std::numeric_limits<size_t >::max)(),
3465+ std::move (fn));
3466+ }
3467+
34323468inline stream_line_reader::stream_line_reader (Stream &strm, char *fixed_buffer,
34333469 size_t fixed_buffer_size)
34343470 : strm_(strm), fixed_buffer_(fixed_buffer),
@@ -8413,23 +8449,20 @@ inline bool Server::check_if_not_modified(const Request &req, Response &res,
84138449 if (req.has_header (" If-None-Match" )) {
84148450 if (!etag.empty ()) {
84158451 auto val = req.get_header_value (" If-None-Match" );
8416- auto matched = false ;
84178452
84188453 // NOTE: We use exact string matching here. This works correctly
84198454 // because our server always generates weak ETags (W/"..."), and
84208455 // clients typically send back the same ETag they received.
84218456 // RFC 9110 Section 8.8.3.2 allows weak comparison for
84228457 // If-None-Match, where W/"x" and "x" would match, but this
84238458 // simplified implementation requires exact matches.
8424- detail::split (val.data (), val.data () + val.size (), ' ,' ,
8425- [&](const char *b, const char *e) {
8426- if (!matched) {
8427- auto tag = std::string (b, e);
8428- matched = tag == " *" || tag == etag;
8429- }
8430- });
8431-
8432- if (matched) {
8459+ auto ret = detail::split_find (val.data (), val.data () + val.size (), ' ,' ,
8460+ [&](const char *b, const char *e) {
8461+ auto tag = std::string (b, e);
8462+ return tag == " *" || tag == etag;
8463+ });
8464+
8465+ if (ret) {
84338466 res.status = StatusCode::NotModified_304;
84348467 return true ;
84358468 }
@@ -8454,28 +8487,29 @@ inline bool Server::check_if_range(Request &req, const std::string &etag,
84548487 // serve full content.
84558488 if (!req.ranges .empty () && req.has_header (" If-Range" )) {
84568489 auto val = req.get_header_value (" If-Range" );
8457- auto valid = false ;
8458-
8459- if (detail::is_strong_etag (val)) {
8460- // RFC 9110 Section 13.1.5: If-Range requires strong ETag
8461- // comparison.
8462- valid = (!etag.empty () && val == etag);
8463- } else if (detail::is_weak_etag (val)) {
8464- // Weak ETags are not valid for If-Range (RFC 9110 Section 13.1.5)
8465- valid = false ;
8466- } else {
8467- // HTTP-date comparison
8468- auto if_range_time = detail::parse_http_date (val);
8469- valid =
8470- (if_range_time != static_cast <time_t >(-1 ) && mtime <= if_range_time);
8471- }
84728490
8473- if (!valid) {
8491+ auto is_valid_range = [&]() {
8492+ if (detail::is_strong_etag (val)) {
8493+ // RFC 9110 Section 13.1.5: If-Range requires strong ETag
8494+ // comparison.
8495+ return (!etag.empty () && val == etag);
8496+ } else if (detail::is_weak_etag (val)) {
8497+ // Weak ETags are not valid for If-Range (RFC 9110 Section 13.1.5)
8498+ return false ;
8499+ } else {
8500+ // HTTP-date comparison
8501+ auto t = detail::parse_http_date (val);
8502+ return (t != static_cast <time_t >(-1 ) && mtime <= t);
8503+ }
8504+ };
8505+
8506+ if (!is_valid_range ()) {
84748507 // Validator doesn't match: ignore Range and serve full content
84758508 req.ranges .clear ();
84768509 return false ;
84778510 }
84788511 }
8512+
84798513 return true ;
84808514}
84818515
0 commit comments