LCOV - code coverage report
Current view: top level - libs/http/src/server - fresh.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 37 0
Test Date: 2026-01-20 00:11:34 Functions: 0.0 % 4 0

            Line data    Source code
       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            0 : etag_matches(
      22              :     core::string_view if_none_match,
      23              :     core::string_view etag ) noexcept
      24              : {
      25            0 :     if( if_none_match.empty() || etag.empty() )
      26            0 :         return false;
      27              : 
      28              :     // "*" matches any ETag
      29            0 :     if( if_none_match == "*" )
      30            0 :         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            0 :     auto strip_weak = []( core::string_view s ) -> core::string_view
      38              :     {
      39            0 :         if( s.size() >= 2 &&
      40            0 :             ( s[0] == 'W' || s[0] == 'w' ) &&
      41            0 :             s[1] == '/' )
      42            0 :             return s.substr( 2 );
      43            0 :         return s;
      44              :     };
      45              : 
      46            0 :     auto const etag_val = strip_weak( etag );
      47              : 
      48              :     // Simple contains check for the ETag value
      49            0 :     auto pos = if_none_match.find( etag_val );
      50            0 :     if( pos != core::string_view::npos )
      51            0 :         return true;
      52              : 
      53              :     // Also check without weak prefix in if_none_match
      54            0 :     auto const inm_stripped = strip_weak( if_none_match );
      55            0 :     if( inm_stripped == etag_val )
      56            0 :         return true;
      57              : 
      58            0 :     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            0 : not_modified_since(
      66              :     core::string_view if_modified_since,
      67              :     core::string_view last_modified ) noexcept
      68              : {
      69            0 :     if( if_modified_since.empty() || last_modified.empty() )
      70            0 :         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            0 :     return last_modified <= if_modified_since;
      76              : }
      77              : 
      78              : } // (anon)
      79              : 
      80              : bool
      81            0 : is_fresh(
      82              :     request const& req,
      83              :     response const& res ) noexcept
      84              : {
      85              :     // Get conditional request headers
      86            0 :     auto const if_none_match = req.value_or(
      87              :         field::if_none_match, "" );
      88            0 :     auto const if_modified_since = req.value_or(
      89              :         field::if_modified_since, "" );
      90              : 
      91              :     // If no conditional headers, not fresh
      92            0 :     if( if_none_match.empty() && if_modified_since.empty() )
      93            0 :         return false;
      94              : 
      95              :     // Get response caching headers
      96            0 :     auto const etag = res.value_or( field::etag, "" );
      97            0 :     auto const last_modified = res.value_or(
      98              :         field::last_modified, "" );
      99              : 
     100              :     // Check ETag first (stronger validator)
     101            0 :     if( ! if_none_match.empty() )
     102              :     {
     103            0 :         if( ! etag.empty() && etag_matches( if_none_match, etag ) )
     104            0 :             return true;
     105              :         // If If-None-Match present but doesn't match, not fresh
     106            0 :         return false;
     107              :     }
     108              : 
     109              :     // Fall back to If-Modified-Since
     110            0 :     if( ! if_modified_since.empty() && ! last_modified.empty() )
     111              :     {
     112            0 :         return not_modified_since( if_modified_since, last_modified );
     113              :     }
     114              : 
     115            0 :     return false;
     116              : }
     117              : 
     118              : } // http
     119              : } // boost
        

Generated by: LCOV version 2.3