Skip to content

Commit

Permalink
Implement a function to calculate IANA MIME types
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Jul 29, 2024
1 parent 06f05fe commit dd326f0
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/http/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
noa_library(NAMESPACE sourcemeta PROJECT hydra NAME http
FOLDER "Hydra/HTTP"
PRIVATE_HEADERS method.h status.h error.h header.h time.h
SOURCES method.cc status.cc error.cc header.cc time.cc)
PRIVATE_HEADERS method.h status.h error.h header.h time.h mime.h
SOURCES method.cc status.cc error.cc header.cc time.cc mime.cc)

if(HYDRA_INSTALL)
noa_library_install(NAMESPACE sourcemeta PROJECT hydra NAME http)
Expand Down
1 change: 1 addition & 0 deletions src/http/include/sourcemeta/hydra/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <sourcemeta/hydra/http_error.h>
#include <sourcemeta/hydra/http_header.h>
#include <sourcemeta/hydra/http_method.h>
#include <sourcemeta/hydra/http_mime.h>
#include <sourcemeta/hydra/http_status.h>
#include <sourcemeta/hydra/http_time.h>

Expand Down
30 changes: 30 additions & 0 deletions src/http/include/sourcemeta/hydra/http_mime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef SOURCEMETA_HYDRA_HTTP_MIME_H
#define SOURCEMETA_HYDRA_HTTP_MIME_H

#if defined(__Unikraft__)
#define SOURCEMETA_HYDRA_HTTP_EXPORT
#else
#include "http_export.h"
#endif

#include <filesystem> // std::filesystem
#include <string> // std::string

namespace sourcemeta::hydra::http {

/// @ingroup http
/// Find a IANA MIME type for the given file. For example:
///
/// ```cpp
/// #include <sourcemeta/hydra/http.h>
/// #include <cassert>
///
/// const auto result{sourcemeta::hydra::http::mime_type("image.png")};
/// assert(result == "image/png");
/// ```
auto SOURCEMETA_HYDRA_HTTP_EXPORT
mime_type(const std::filesystem::path &file_path) -> std::string;

} // namespace sourcemeta::hydra::http

#endif
32 changes: 32 additions & 0 deletions src/http/mime.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <sourcemeta/hydra/http_mime.h>

#include <algorithm> // std::transform
#include <cctype> // std::tolower
#include <map> // std::map

namespace sourcemeta::hydra::http {

// See https://www.iana.org/assignments/media-types/media-types.xhtml
auto mime_type(const std::filesystem::path &file_path) -> std::string {
// TODO: More exhaustively define all known types
static const std::map<std::string, std::string> MIME_TYPES{
{".css", "text/css"},
{".png", "image/png"},
{".webp", "image/webp"},
{".ico", "image/vnd.microsoft.icon"},
{".svg", "image/svg+xml"},
{".webmanifest", "application/manifest+json"},
{".json", "application/json"},
{".woff", "font/woff"},
{".woff2", "font/woff2"},
};

std::string extension{file_path.extension().string()};
std::transform(extension.begin(), extension.end(), extension.begin(),
[](const auto character) { return std::tolower(character); });
const auto result{MIME_TYPES.find(extension)};
return result == MIME_TYPES.cend() ? "application/octet-stream"
: result->second;
}

} // namespace sourcemeta::hydra::http
3 changes: 2 additions & 1 deletion test/unit/http/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_executable(sourcemeta_hydra_http_unit
time_test.cc status_test.cc method_test.cc header_test.cc)
time_test.cc status_test.cc method_test.cc
header_test.cc mime_test.cc)
noa_add_default_options(PRIVATE sourcemeta_hydra_http_unit)
target_link_libraries(sourcemeta_hydra_http_unit
PRIVATE GTest::gtest GTest::gtest_main)
Expand Down
72 changes: 72 additions & 0 deletions test/unit/http/mime_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <gtest/gtest.h>

#include <sourcemeta/hydra/http.h>

TEST(HTTP_MIME, css_lower) {
const std::filesystem::path file_path{"path/to/example.css"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "text/css");
}

TEST(HTTP_MIME, css_upper) {
const std::filesystem::path file_path{"path/to/example.CSS"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "text/css");
}

TEST(HTTP_MIME, css_mixed) {
const std::filesystem::path file_path{"path/to/example.cSs"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "text/css");
}

TEST(HTTP_MIME, png_lower) {
const std::filesystem::path file_path{"path/to/example.png"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "image/png");
}

TEST(HTTP_MIME, webp_lower) {
const std::filesystem::path file_path{"path/to/example.webp"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "image/webp");
}

TEST(HTTP_MIME, ico_lower) {
const std::filesystem::path file_path{"path/to/example.ico"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path),
"image/vnd.microsoft.icon");
}

TEST(HTTP_MIME, svg_lower) {
const std::filesystem::path file_path{"path/to/example.svg"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "image/svg+xml");
}

TEST(HTTP_MIME, webmanifest_lower) {
const std::filesystem::path file_path{"path/to/example.webmanifest"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path),
"application/manifest+json");
}

TEST(HTTP_MIME, json_lower) {
const std::filesystem::path file_path{"path/to/example.json"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "application/json");
}

TEST(HTTP_MIME, woff_lower) {
const std::filesystem::path file_path{"path/to/example.woff"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "font/woff");
}

TEST(HTTP_MIME, woff2_lower) {
const std::filesystem::path file_path{"path/to/example.woff2"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path), "font/woff2");
}

TEST(HTTP_MIME, unknown) {
const std::filesystem::path file_path{"path/to/example.foobar"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path),
"application/octet-stream");
}

TEST(HTTP_MIME, none) {
const std::filesystem::path file_path{"path/to/example"};
EXPECT_EQ(sourcemeta::hydra::http::mime_type(file_path),
"application/octet-stream");
}

0 comments on commit dd326f0

Please sign in to comment.