LCOV - code coverage report
Current view: top level - libs/http/src/server - mime_types.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 67 0
Test Date: 2026-01-20 00:11:34 Functions: 0.0 % 7 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/mime_types.hpp>
      11              : #include <boost/http/server/mime_db.hpp>
      12              : #include <algorithm>
      13              : #include <cctype>
      14              : 
      15              : namespace boost {
      16              : namespace http {
      17              : namespace mime_types {
      18              : 
      19              : namespace {
      20              : 
      21              : struct ext_entry
      22              : {
      23              :     core::string_view ext;
      24              :     core::string_view type;
      25              : };
      26              : 
      27              : // Sorted by extension for binary search
      28              : constexpr ext_entry ext_db[] = {
      29              :     { "aac", "audio/aac" },
      30              :     { "avif", "image/avif" },
      31              :     { "bmp", "image/bmp" },
      32              :     { "bz", "application/x-bzip" },
      33              :     { "bz2", "application/x-bzip2" },
      34              :     { "cjs", "application/javascript" },
      35              :     { "css", "text/css" },
      36              :     { "csv", "text/csv" },
      37              :     { "flac", "audio/flac" },
      38              :     { "gif", "image/gif" },
      39              :     { "gz", "application/gzip" },
      40              :     { "htm", "text/html" },
      41              :     { "html", "text/html" },
      42              :     { "ico", "image/x-icon" },
      43              :     { "ics", "text/calendar" },
      44              :     { "jpeg", "image/jpeg" },
      45              :     { "jpg", "image/jpeg" },
      46              :     { "js", "text/javascript" },
      47              :     { "json", "application/json" },
      48              :     { "m4a", "audio/mp4" },
      49              :     { "m4v", "video/mp4" },
      50              :     { "manifest", "text/cache-manifest" },
      51              :     { "md", "text/markdown" },
      52              :     { "mjs", "text/javascript" },
      53              :     { "mp3", "audio/mpeg" },
      54              :     { "mp4", "video/mp4" },
      55              :     { "mpeg", "video/mpeg" },
      56              :     { "mpg", "video/mpeg" },
      57              :     { "oga", "audio/ogg" },
      58              :     { "ogg", "audio/ogg" },
      59              :     { "ogv", "video/ogg" },
      60              :     { "otf", "font/otf" },
      61              :     { "pdf", "application/pdf" },
      62              :     { "png", "image/png" },
      63              :     { "rtf", "application/rtf" },
      64              :     { "svg", "image/svg+xml" },
      65              :     { "tar", "application/x-tar" },
      66              :     { "tif", "image/tiff" },
      67              :     { "tiff", "image/tiff" },
      68              :     { "ttf", "font/ttf" },
      69              :     { "txt", "text/plain" },
      70              :     { "wasm", "application/wasm" },
      71              :     { "wav", "audio/wav" },
      72              :     { "weba", "audio/webm" },
      73              :     { "webm", "video/webm" },
      74              :     { "webp", "image/webp" },
      75              :     { "woff", "font/woff" },
      76              :     { "woff2", "font/woff2" },
      77              :     { "xhtml", "application/xhtml+xml" },
      78              :     { "xml", "application/xml" },
      79              :     { "zip", "application/zip" },
      80              :     { "7z", "application/x-7z-compressed" },
      81              : };
      82              : 
      83              : constexpr std::size_t ext_db_size = sizeof( ext_db ) / sizeof( ext_db[0] );
      84              : 
      85              : // Case-insensitive comparison
      86              : int
      87            0 : compare_icase( core::string_view a, core::string_view b ) noexcept
      88              : {
      89            0 :     auto const n = ( std::min )( a.size(), b.size() );
      90            0 :     for( std::size_t i = 0; i < n; ++i )
      91              :     {
      92              :         auto const ca = static_cast<unsigned char>(
      93            0 :             std::tolower( static_cast<unsigned char>( a[i] ) ) );
      94              :         auto const cb = static_cast<unsigned char>(
      95            0 :             std::tolower( static_cast<unsigned char>( b[i] ) ) );
      96            0 :         if( ca < cb )
      97            0 :             return -1;
      98            0 :         if( ca > cb )
      99            0 :             return 1;
     100              :     }
     101            0 :     if( a.size() < b.size() )
     102            0 :         return -1;
     103            0 :     if( a.size() > b.size() )
     104            0 :         return 1;
     105            0 :     return 0;
     106              : }
     107              : 
     108              : // Extract extension from path
     109              : core::string_view
     110            0 : get_extension( core::string_view path ) noexcept
     111              : {
     112              :     // Find last dot
     113            0 :     auto const pos = path.rfind( '.' );
     114            0 :     if( pos == core::string_view::npos )
     115            0 :         return path; // Assume it's just an extension
     116            0 :     return path.substr( pos + 1 );
     117              : }
     118              : 
     119              : // Binary search for extension
     120              : core::string_view
     121            0 : lookup_ext( core::string_view ext ) noexcept
     122              : {
     123            0 :     std::size_t lo = 0;
     124            0 :     std::size_t hi = ext_db_size;
     125            0 :     while( lo < hi )
     126              :     {
     127            0 :         auto const mid = lo + ( hi - lo ) / 2;
     128            0 :         auto const cmp = compare_icase( ext_db[mid].ext, ext );
     129            0 :         if( cmp < 0 )
     130            0 :             lo = mid + 1;
     131            0 :         else if( cmp > 0 )
     132            0 :             hi = mid;
     133              :         else
     134            0 :             return ext_db[mid].type;
     135              :     }
     136            0 :     return {};
     137              : }
     138              : 
     139              : } // (anon)
     140              : 
     141              : core::string_view
     142            0 : lookup( core::string_view path_or_ext ) noexcept
     143              : {
     144            0 :     if( path_or_ext.empty() )
     145            0 :         return {};
     146              : 
     147              :     // Skip leading dot if present
     148            0 :     if( path_or_ext[0] == '.' )
     149            0 :         path_or_ext.remove_prefix( 1 );
     150              : 
     151            0 :     auto const ext = get_extension( path_or_ext );
     152            0 :     return lookup_ext( ext );
     153              : }
     154              : 
     155              : core::string_view
     156            0 : extension( core::string_view type ) noexcept
     157              : {
     158              :     // Linear search for type -> extension
     159              :     // Could optimize with reverse map if needed
     160            0 :     for( std::size_t i = 0; i < ext_db_size; ++i )
     161              :     {
     162            0 :         if( compare_icase( ext_db[i].type, type ) == 0 )
     163            0 :             return ext_db[i].ext;
     164              :     }
     165            0 :     return {};
     166              : }
     167              : 
     168              : core::string_view
     169            0 : charset( core::string_view type ) noexcept
     170              : {
     171            0 :     auto const* entry = mime_db::lookup( type );
     172            0 :     if( entry )
     173            0 :         return entry->charset;
     174            0 :     return {};
     175              : }
     176              : 
     177              : std::string
     178            0 : content_type( core::string_view type_or_ext )
     179              : {
     180            0 :     core::string_view type;
     181              : 
     182              :     // Check if it looks like an extension
     183            0 :     if( ! type_or_ext.empty() &&
     184            0 :         ( type_or_ext[0] == '.' ||
     185            0 :           type_or_ext.find( '/' ) == core::string_view::npos ) )
     186              :     {
     187            0 :         type = lookup( type_or_ext );
     188            0 :         if( type.empty() )
     189            0 :             return {};
     190              :     }
     191              :     else
     192              :     {
     193            0 :         type = type_or_ext;
     194              :     }
     195              : 
     196            0 :     auto const cs = charset( type );
     197            0 :     if( cs.empty() )
     198            0 :         return std::string( type );
     199              : 
     200            0 :     std::string result;
     201            0 :     result.reserve( type.size() + 10 + cs.size() );
     202            0 :     result.append( type.data(), type.size() );
     203            0 :     result.append( "; charset=" );
     204            0 :     result.append( cs.data(), cs.size() );
     205            0 :     return result;
     206            0 : }
     207              : 
     208              : } // mime_types
     209              : } // http
     210              : } // boost
        

Generated by: LCOV version 2.3