blob: 5b8996c2f26a1866202fba2f2c4f09706c1107b7 [file] [log] [blame]
Ed Tanous9bd21fc2018-04-26 16:08:56 -07001#pragma once
Tanousf00032d2018-11-05 01:18:10 -03002
Ed Tanous463b2932024-07-16 17:02:42 -07003#include <boost/spirit/home/x3.hpp>
4
Ed Tanous18f8f602023-07-18 10:07:23 -07005#include <algorithm>
Nan Zhoud5c80ad2022-07-11 01:16:31 +00006#include <cctype>
7#include <iomanip>
8#include <ostream>
Ed Tanous3544d2a2023-08-06 18:12:20 -07009#include <ranges>
Ed Tanous99351cd2022-08-07 16:42:51 -070010#include <span>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000011#include <string>
12#include <string_view>
13#include <vector>
14
Ed Tanous1abe55e2018-09-05 08:30:59 -070015namespace http_helpers
16{
George Liu647b3cd2021-07-05 12:43:56 +080017
Ed Tanous99351cd2022-08-07 16:42:51 -070018enum class ContentType
George Liu647b3cd2021-07-05 12:43:56 +080019{
Ed Tanous99351cd2022-08-07 16:42:51 -070020 NoMatch,
Ed Tanous4a0e1a02022-09-21 15:28:04 -070021 ANY, // Accepts: */*
Ed Tanous99351cd2022-08-07 16:42:51 -070022 CBOR,
23 HTML,
24 JSON,
25 OctetStream,
Ed Tanous6fde95f2023-06-01 07:33:34 -070026 EventStream,
Ed Tanous99351cd2022-08-07 16:42:51 -070027};
28
Patrick Williamsbd79bce2024-08-16 15:22:20 -040029inline ContentType getPreferredContentType(
30 std::string_view header, std::span<const ContentType> preferedOrder)
Ed Tanous99351cd2022-08-07 16:42:51 -070031{
Ed Tanous463b2932024-07-16 17:02:42 -070032 using boost::spirit::x3::char_;
33 using boost::spirit::x3::lit;
34 using boost::spirit::x3::omit;
35 using boost::spirit::x3::parse;
36 using boost::spirit::x3::space;
37 using boost::spirit::x3::symbols;
38 using boost::spirit::x3::uint_;
39
40 const symbols<ContentType> knownMimeType{
41 {"application/cbor", ContentType::CBOR},
42 {"application/json", ContentType::JSON},
43 {"application/octet-stream", ContentType::OctetStream},
44 {"text/html", ContentType::HTML},
45 {"text/event-stream", ContentType::EventStream},
46 {"*/*", ContentType::ANY}};
47
48 std::vector<ContentType> ct;
49
50 auto parameters = *(lit(';') >> lit("q=") >> uint_ >> -(lit('.') >> uint_));
51 auto typeCharset = char_("a-zA-Z.+-");
52 auto mimeType = knownMimeType |
53 omit[+typeCharset >> lit('/') >> +typeCharset];
54 auto parser = +(mimeType >> omit[parameters >> -char_(',') >> *space]);
55 if (!parse(header.begin(), header.end(), parser, ct))
Ed Tanous1abe55e2018-09-05 08:30:59 -070056 {
Ed Tanous463b2932024-07-16 17:02:42 -070057 return ContentType::NoMatch;
George Liu647b3cd2021-07-05 12:43:56 +080058 }
Ed Tanous463b2932024-07-16 17:02:42 -070059
60 for (const ContentType parsedType : ct)
61 {
62 if (parsedType == ContentType::ANY)
63 {
64 return parsedType;
65 }
66 auto it = std::ranges::find(preferedOrder, parsedType);
67 if (it != preferedOrder.end())
68 {
69 return *it;
70 }
71 }
72
Ed Tanous99351cd2022-08-07 16:42:51 -070073 return ContentType::NoMatch;
74}
75
Ed Tanous4a0e1a02022-09-21 15:28:04 -070076inline bool isContentTypeAllowed(std::string_view header, ContentType type,
77 bool allowWildcard)
Ed Tanous99351cd2022-08-07 16:42:51 -070078{
79 auto types = std::to_array({type});
Ed Tanous8ece0e42024-01-02 13:16:50 -080080 ContentType allowed = getPreferredContentType(header, types);
Ed Tanous4a0e1a02022-09-21 15:28:04 -070081 if (allowed == ContentType::ANY)
82 {
83 return allowWildcard;
84 }
85
86 return type == allowed;
George Liu647b3cd2021-07-05 12:43:56 +080087}
88
Ed Tanous23a21a12020-07-25 04:45:05 +000089} // namespace http_helpers