CCF
Loading...
Searching...
No Matches
http_accept.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/nonstd.h"
6#include "ccf/http_status.h"
7#include "ccf/odata_error.h"
8#include "ccf/rpc_exception.h"
9
10#include <string_view>
11
12namespace ccf::http
13{
15 {
16 std::string mime_type;
17 std::string mime_subtype;
18 float q_factor;
19
20 static bool is_wildcard(const std::string_view& s)
21 {
22 return s == "*";
23 }
24
25 bool matches(const std::string& mime) const
26 {
27 const auto [t, st] = ccf::nonstd::split_1(mime, "/");
28
29 if (is_wildcard(mime_type) || mime_type == t)
30 {
32 {
33 return true;
34 }
35 }
36
37 return false;
38 }
39
40 bool operator==(const AcceptHeaderField& other) const
41 {
42 return mime_type == other.mime_type &&
43 mime_subtype == other.mime_subtype && q_factor == other.q_factor;
44 }
45
46 bool operator<(const AcceptHeaderField& other) const
47 {
48 static constexpr auto float_comp_epsilon = 0.0000001f;
49 if (std::abs(q_factor - other.q_factor) > float_comp_epsilon)
50 {
51 return q_factor < other.q_factor;
52 }
53
55 {
56 return true;
57 }
58
60 {
61 return true;
62 }
63
64 // Spec says these mime types are now equivalent. For stability, we
65 // order them lexicographically
66 if (mime_type != other.mime_type)
67 {
68 return mime_type < other.mime_type;
69 }
70 return mime_subtype < other.mime_subtype;
71 }
72 };
73
74 inline std::vector<AcceptHeaderField> parse_accept_header(std::string s)
75 {
76 // Strip out all spaces
77 s.erase(
78 std::remove_if(s.begin(), s.end(), [](char c) { return c == ' '; }),
79 s.end());
80
81 if (s.empty())
82 {
83 return {};
84 }
85
86 std::vector<AcceptHeaderField> fields;
87
88 const auto elements = ccf::nonstd::split(s, ",");
89 for (const auto& element : elements)
90 {
91 const auto [types, q_string] = ccf::nonstd::split_1(element, ";q=");
92 const auto [type, subtype] = ccf::nonstd::split_1(types, "/");
93 if (type.empty() || subtype.empty())
94 {
96 HTTP_STATUS_BAD_REQUEST,
97 ccf::errors::InvalidHeaderValue,
98 fmt::format(
99 "Entry in Accept header is not a valid MIME type: {}", element));
100 }
101
102 float q_factor = 1.0f;
103 if (!q_string.empty())
104 {
105 try
106 {
107 q_factor = std::stof(std::string(q_string));
108 }
109 catch (const std::exception& e)
110 {
111 throw ccf::RpcException(
112 HTTP_STATUS_BAD_REQUEST,
113 ccf::errors::InvalidHeaderValue,
114 fmt::format(
115 "Could not parse q-factor from MIME type in Accept header: "
116 "{}",
117 element));
118 }
119 }
120
121 fields.push_back(
122 AcceptHeaderField{std::string(type), std::string(subtype), q_factor});
123 }
124
125 // Sort in _reverse_, so the 'largest' (highest quality-value) entry is
126 // first
127 std::sort(fields.begin(), fields.end(), [](const auto& a, const auto& b) {
128 return b < a;
129 });
130 return fields;
131 }
132}
Definition http_accept.h:13
std::vector< AcceptHeaderField > parse_accept_header(std::string s)
Definition http_accept.h:74
Definition rpc_exception.h:13
Definition http_accept.h:15
bool operator<(const AcceptHeaderField &other) const
Definition http_accept.h:46
float q_factor
Definition http_accept.h:18
static bool is_wildcard(const std::string_view &s)
Definition http_accept.h:20
std::string mime_subtype
Definition http_accept.h:17
std::string mime_type
Definition http_accept.h:16
bool matches(const std::string &mime) const
Definition http_accept.h:25
bool operator==(const AcceptHeaderField &other) const
Definition http_accept.h:40