GCC Code Coverage Report


Directory: ./
File: libs/http/src/server/fresh.cpp
Date: 2026-01-20 00:11:35
Exec Total Coverage
Lines: 0 37 0.0%
Functions: 0 4 0.0%
Branches: 0 48 0.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/http
8 //
9
10 #include <boost/http/server/fresh.hpp>
11 #include <boost/http/field.hpp>
12
13 namespace boost {
14 namespace http {
15
16 namespace {
17
18 // Check if ETag matches If-None-Match
19 // Returns true if they match (response is fresh)
20 bool
21 etag_matches(
22 core::string_view if_none_match,
23 core::string_view etag ) noexcept
24 {
25 if( if_none_match.empty() || etag.empty() )
26 return false;
27
28 // "*" matches any ETag
29 if( if_none_match == "*" )
30 return true;
31
32 // Simple comparison - check if ETag appears in the list
33 // In full implementation, would need to handle weak vs strong
34 // and parse comma-separated list properly
35
36 // Remove W/ prefix for comparison if present
37 auto strip_weak = []( core::string_view s ) -> core::string_view
38 {
39 if( s.size() >= 2 &&
40 ( s[0] == 'W' || s[0] == 'w' ) &&
41 s[1] == '/' )
42 return s.substr( 2 );
43 return s;
44 };
45
46 auto const etag_val = strip_weak( etag );
47
48 // Simple contains check for the ETag value
49 auto pos = if_none_match.find( etag_val );
50 if( pos != core::string_view::npos )
51 return true;
52
53 // Also check without weak prefix in if_none_match
54 auto const inm_stripped = strip_weak( if_none_match );
55 if( inm_stripped == etag_val )
56 return true;
57
58 return false;
59 }
60
61 // Parse HTTP date and compare
62 // Returns true if response's Last-Modified <= request's If-Modified-Since
63 // For simplicity, doing string comparison (works for RFC 7231 dates)
64 bool
65 not_modified_since(
66 core::string_view if_modified_since,
67 core::string_view last_modified ) noexcept
68 {
69 if( if_modified_since.empty() || last_modified.empty() )
70 return false;
71
72 // HTTP dates in RFC 7231 format are lexicographically comparable
73 // when in the same format (preferred format)
74 // For a robust implementation, would parse dates properly
75 return last_modified <= if_modified_since;
76 }
77
78 } // (anon)
79
80 bool
81 is_fresh(
82 request const& req,
83 response const& res ) noexcept
84 {
85 // Get conditional request headers
86 auto const if_none_match = req.value_or(
87 field::if_none_match, "" );
88 auto const if_modified_since = req.value_or(
89 field::if_modified_since, "" );
90
91 // If no conditional headers, not fresh
92 if( if_none_match.empty() && if_modified_since.empty() )
93 return false;
94
95 // Get response caching headers
96 auto const etag = res.value_or( field::etag, "" );
97 auto const last_modified = res.value_or(
98 field::last_modified, "" );
99
100 // Check ETag first (stronger validator)
101 if( ! if_none_match.empty() )
102 {
103 if( ! etag.empty() && etag_matches( if_none_match, etag ) )
104 return true;
105 // If If-None-Match present but doesn't match, not fresh
106 return false;
107 }
108
109 // Fall back to If-Modified-Since
110 if( ! if_modified_since.empty() && ! last_modified.empty() )
111 {
112 return not_modified_since( if_modified_since, last_modified );
113 }
114
115 return false;
116 }
117
118 } // http
119 } // boost
120