blob: 4f430aeb8ec2c57b070a4dbc17f25c1dd3fbeabd [file] [log] [blame]
Ed Tanous9bd21fc2018-04-26 16:08:56 -07001#pragma once
Tanousf00032d2018-11-05 01:18:10 -03002
Ed Tanous11ba3972022-07-11 09:50:41 -07003#include <boost/algorithm/string/classification.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +00004#include <boost/algorithm/string/constants.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +00005#include <boost/iterator/iterator_facade.hpp>
6#include <boost/type_index/type_index_facade.hpp>
7
8#include <cctype>
9#include <iomanip>
10#include <ostream>
Ed Tanous3544d2a2023-08-06 18:12:20 -070011#include <ranges>
Ed Tanous99351cd2022-08-07 16:42:51 -070012#include <span>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000013#include <string>
14#include <string_view>
15#include <vector>
16
17// IWYU pragma: no_include <ctype.h>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050018
Ed Tanous1abe55e2018-09-05 08:30:59 -070019namespace http_helpers
20{
George Liu647b3cd2021-07-05 12:43:56 +080021
Ed Tanous99351cd2022-08-07 16:42:51 -070022enum class ContentType
George Liu647b3cd2021-07-05 12:43:56 +080023{
Ed Tanous99351cd2022-08-07 16:42:51 -070024 NoMatch,
Ed Tanous4a0e1a02022-09-21 15:28:04 -070025 ANY, // Accepts: */*
Ed Tanous99351cd2022-08-07 16:42:51 -070026 CBOR,
27 HTML,
28 JSON,
29 OctetStream,
Ed Tanous6fde95f2023-06-01 07:33:34 -070030 EventStream,
Ed Tanous99351cd2022-08-07 16:42:51 -070031};
32
33struct ContentTypePair
34{
35 std::string_view contentTypeString;
36 ContentType contentTypeEnum;
37};
38
Ed Tanous6fde95f2023-06-01 07:33:34 -070039constexpr std::array<ContentTypePair, 5> contentTypes{{
Ed Tanous99351cd2022-08-07 16:42:51 -070040 {"application/cbor", ContentType::CBOR},
41 {"application/json", ContentType::JSON},
42 {"application/octet-stream", ContentType::OctetStream},
43 {"text/html", ContentType::HTML},
Ed Tanous6fde95f2023-06-01 07:33:34 -070044 {"text/event-stream", ContentType::EventStream},
Ed Tanous99351cd2022-08-07 16:42:51 -070045}};
46
Ed Tanoused194be2022-08-07 16:50:11 -070047inline ContentType
48 getPreferedContentType(std::string_view header,
49 std::span<const ContentType> preferedOrder)
Ed Tanous99351cd2022-08-07 16:42:51 -070050{
Ed Tanous99351cd2022-08-07 16:42:51 -070051 size_t lastIndex = 0;
52 while (lastIndex < header.size() + 1)
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 {
Ed Tanousf8fe53e2022-06-30 15:55:45 -070054 size_t index = header.find(',', lastIndex);
Ed Tanous99351cd2022-08-07 16:42:51 -070055 if (index == std::string_view::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -070056 {
Ed Tanous99351cd2022-08-07 16:42:51 -070057 index = header.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 }
Ed Tanous99351cd2022-08-07 16:42:51 -070059 std::string_view encoding = header.substr(lastIndex, index);
Ed Tanous6b5e77d2018-11-16 14:52:56 -080060
Ed Tanous99351cd2022-08-07 16:42:51 -070061 if (!header.empty())
62 {
63 header.remove_prefix(1);
64 }
65 lastIndex = index + 1;
Gunnar Millsa3526fe2022-02-02 21:56:44 +000066 // ignore any q-factor weighting (;q=)
67 std::size_t separator = encoding.find(";q=");
68
69 if (separator != std::string_view::npos)
70 {
71 encoding = encoding.substr(0, separator);
72 }
Ed Tanous99351cd2022-08-07 16:42:51 -070073 // If the client allows any encoding, given them the first one on the
74 // servers list
75 if (encoding == "*/*")
George Liu647b3cd2021-07-05 12:43:56 +080076 {
Ed Tanous4a0e1a02022-09-21 15:28:04 -070077 return ContentType::ANY;
George Liu647b3cd2021-07-05 12:43:56 +080078 }
Ed Tanous3544d2a2023-08-06 18:12:20 -070079 const auto* knownContentType = std::ranges::find_if(
80 contentTypes, [encoding](const ContentTypePair& pair) {
Patrick Williams5a39f772023-10-20 11:20:21 -050081 return pair.contentTypeString == encoding;
82 });
Ed Tanous99351cd2022-08-07 16:42:51 -070083
84 if (knownContentType == contentTypes.end())
85 {
86 // not able to find content type in list
87 continue;
88 }
89
90 // Not one of the types requested
Ed Tanous3544d2a2023-08-06 18:12:20 -070091 if (std::ranges::find(preferedOrder,
92 knownContentType->contentTypeEnum) ==
93 preferedOrder.end())
Ed Tanous99351cd2022-08-07 16:42:51 -070094 {
95 continue;
96 }
97 return knownContentType->contentTypeEnum;
George Liu647b3cd2021-07-05 12:43:56 +080098 }
Ed Tanous99351cd2022-08-07 16:42:51 -070099 return ContentType::NoMatch;
100}
101
Ed Tanous4a0e1a02022-09-21 15:28:04 -0700102inline bool isContentTypeAllowed(std::string_view header, ContentType type,
103 bool allowWildcard)
Ed Tanous99351cd2022-08-07 16:42:51 -0700104{
105 auto types = std::to_array({type});
Ed Tanous4a0e1a02022-09-21 15:28:04 -0700106 ContentType allowed = getPreferedContentType(header, types);
107 if (allowed == ContentType::ANY)
108 {
109 return allowWildcard;
110 }
111
112 return type == allowed;
George Liu647b3cd2021-07-05 12:43:56 +0800113}
114
Ed Tanous23a21a12020-07-25 04:45:05 +0000115} // namespace http_helpers