blob: b7844bacb859dd50d75bddfe1a0ed8b6c67400de [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>
Ed Tanous11ba3972022-07-11 09:50:41 -07005#include <boost/algorithm/string/split.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +00006#include <boost/iterator/iterator_facade.hpp>
7#include <boost/type_index/type_index_facade.hpp>
8
9#include <cctype>
10#include <iomanip>
11#include <ostream>
12#include <string>
13#include <string_view>
14#include <vector>
15
16// IWYU pragma: no_include <ctype.h>
17// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
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 +080021inline std::vector<std::string> parseAccept(std::string_view header)
Ed Tanous1abe55e2018-09-05 08:30:59 -070022{
Ed Tanous753d0342021-07-01 07:57:30 -070023 std::vector<std::string> encodings;
24 // chrome currently sends 6 accepts headers, firefox sends 4.
25 encodings.reserve(6);
26 boost::split(encodings, header, boost::is_any_of(", "),
27 boost::token_compress_on);
George Liu647b3cd2021-07-05 12:43:56 +080028
29 return encodings;
30}
31
32inline bool requestPrefersHtml(std::string_view header)
33{
34 for (const std::string& encoding : parseAccept(header))
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 {
Ed Tanous753d0342021-07-01 07:57:30 -070036 if (encoding == "text/html")
Ed Tanous1abe55e2018-09-05 08:30:59 -070037 {
38 return true;
39 }
Ed Tanous753d0342021-07-01 07:57:30 -070040 if (encoding == "application/json")
Ed Tanous1abe55e2018-09-05 08:30:59 -070041 {
42 return false;
43 }
Ed Tanous9bd21fc2018-04-26 16:08:56 -070044 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 return false;
Ed Tanous9bd21fc2018-04-26 16:08:56 -070046}
Ed Tanous6b5e77d2018-11-16 14:52:56 -080047
George Liu647b3cd2021-07-05 12:43:56 +080048inline bool isOctetAccepted(std::string_view header)
49{
Gunnar Millsa3526fe2022-02-02 21:56:44 +000050 for (std::string_view encoding : parseAccept(header))
George Liu647b3cd2021-07-05 12:43:56 +080051 {
Gunnar Millsa3526fe2022-02-02 21:56:44 +000052 // ignore any q-factor weighting (;q=)
53 std::size_t separator = encoding.find(";q=");
54
55 if (separator != std::string_view::npos)
56 {
57 encoding = encoding.substr(0, separator);
58 }
George Liu647b3cd2021-07-05 12:43:56 +080059 if (encoding == "*/*" || encoding == "application/octet-stream")
60 {
61 return true;
62 }
63 }
64 return false;
65}
66
Ed Tanous39e77502019-03-04 17:35:53 -080067inline std::string urlEncode(const std::string_view value)
Ed Tanous6b5e77d2018-11-16 14:52:56 -080068{
69 std::ostringstream escaped;
70 escaped.fill('0');
71 escaped << std::hex;
72
73 for (const char c : value)
74 {
75 // Keep alphanumeric and other accepted characters intact
Ed Tanouse662eae2022-01-25 10:39:19 -080076 if ((isalnum(c) != 0) || c == '-' || c == '_' || c == '.' || c == '~')
Ed Tanous6b5e77d2018-11-16 14:52:56 -080077 {
78 escaped << c;
79 continue;
80 }
81
82 // Any other characters are percent-encoded
83 escaped << std::uppercase;
84 escaped << '%' << std::setw(2)
85 << static_cast<int>(static_cast<unsigned char>(c));
86 escaped << std::nouppercase;
87 }
88
89 return escaped.str();
90}
Ed Tanous23a21a12020-07-25 04:45:05 +000091} // namespace http_helpers