src/server/etag.cpp

77.8% Lines (21/27) 75.0% Functions (3/4)
src/server/etag.cpp
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
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/etag.hpp>
11 #include <cstdio>
12
13 namespace boost {
14 namespace http {
15
16 namespace {
17
18 // Simple FNV-1a hash for content
19 std::uint64_t
20 1 fnv1a_hash( core::string_view data ) noexcept
21 {
22 1 constexpr std::uint64_t basis = 14695981039346656037ULL;
23 1 constexpr std::uint64_t prime = 1099511628211ULL;
24
25 1 std::uint64_t hash = basis;
26 3 for( unsigned char c : data )
27 {
28 2 hash ^= c;
29 2 hash *= prime;
30 }
31 1 return hash;
32 }
33
34 // Convert to null-terminated hex string
35 void
36 1 to_hex( std::uint64_t value, char* out ) noexcept
37 {
38 1 constexpr char hex[] = "0123456789abcdef";
39 17 for( int i = 15; i >= 0; --i )
40 {
41 16 out[i] = hex[value & 0xF];
42 16 value >>= 4;
43 }
44 1 out[16] = '\0';
45 1 }
46
47 } // (anon)
48
49 std::string
50 1 etag( core::string_view body, etag_options opts )
51 {
52 1 auto const hash = fnv1a_hash( body );
53
54 char hex[17];
55 1 to_hex( hash, hex );
56
57 char buf[64];
58 int n;
59 1 if( opts.weak )
60 n = std::snprintf( buf, sizeof(buf),
61 "W/\"%zx-%s\"", body.size(), hex );
62 else
63 1 n = std::snprintf( buf, sizeof(buf),
64 "\"%zx-%s\"", body.size(), hex );
65
66 2 return std::string( buf, static_cast<std::size_t>(n) );
67 }
68
69 std::string
70 etag(
71 std::uint64_t size,
72 std::uint64_t mtime,
73 etag_options opts )
74 {
75 char buf[64];
76 int n;
77 if( opts.weak )
78 n = std::snprintf( buf, sizeof(buf),
79 "W/\"%llx-%llx\"",
80 static_cast<unsigned long long>( size ),
81 static_cast<unsigned long long>( mtime ) );
82 else
83 n = std::snprintf( buf, sizeof(buf),
84 "\"%llx-%llx\"",
85 static_cast<unsigned long long>( size ),
86 static_cast<unsigned long long>( mtime ) );
87
88 return std::string( buf, static_cast<std::size_t>(n) );
89 }
90
91 } // http
92 } // boost
93