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"
9
10#include <string_view>
11
12namespace 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 if (q_factor != other.q_factor)
49 {
50 return q_factor < other.q_factor;
51 }
52
54 {
55 return true;
56 }
57 else if (is_wildcard(other.mime_type))
58 {
59 return false;
60 }
61
63 {
64 return true;
65 }
66 else if (is_wildcard(other.mime_subtype))
67 {
68 return false;
69 }
70
71 // Spec says these mime types are now equivalent. For stability, we
72 // order them lexicographically
73 return mime_type < other.mime_type && mime_subtype < other.mime_subtype;
74 }
75 };
76
77 inline std::vector<AcceptHeaderField> parse_accept_header(std::string s)
78 {
79 // Strip out all spaces
80 s.erase(
81 std::remove_if(s.begin(), s.end(), [](char c) { return c == ' '; }),
82 s.end());
83
84 if (s.empty())
85 {
86 return {};
87 }
88
89 std::vector<AcceptHeaderField> fields;
90
91 const auto elements = ccf::nonstd::split(s, ",");
92 for (const auto& element : elements)
93 {
94 const auto [types, q_string] = ccf::nonstd::split_1(element, ";q=");
95 const auto [type, subtype] = ccf::nonstd::split_1(types, "/");
96 if (type.empty() || subtype.empty())
97 {
99 HTTP_STATUS_BAD_REQUEST,
100 ccf::errors::InvalidHeaderValue,
101 fmt::format(
102 "Entry in Accept header is not a valid MIME type: {}", element));
103 }
104
105 float q_factor = 1.0f;
106 if (!q_string.empty())
107 {
108 try
109 {
110 q_factor = std::stof(std::string(q_string));
111 }
112 catch (const std::exception& e)
113 {
114 throw ccf::RpcException(
115 HTTP_STATUS_BAD_REQUEST,
116 ccf::errors::InvalidHeaderValue,
117 fmt::format(
118 "Could not parse q-factor from MIME type in Accept header: "
119 "{}",
120 element));
121 }
122 }
123
124 fields.push_back(
125 AcceptHeaderField{std::string(type), std::string(subtype), q_factor});
126 }
127
128 // Sort in _reverse_, so the 'largest' (highest quality-value) entry is
129 // first
130 std::sort(fields.begin(), fields.end(), [](const auto& a, const auto& b) {
131 return b < a;
132 });
133 return fields;
134 }
135}
Definition error_reporter.h:6
std::vector< AcceptHeaderField > parse_accept_header(std::string s)
Definition http_accept.h:77
Definition rpc_exception.h:13
Definition http_accept.h:15
float q_factor
Definition http_accept.h:18
bool matches(const std::string &mime) const
Definition http_accept.h:25
std::string mime_subtype
Definition http_accept.h:17
static bool is_wildcard(const std::string_view &s)
Definition http_accept.h:20
std::string mime_type
Definition http_accept.h:16
bool operator<(const AcceptHeaderField &other) const
Definition http_accept.h:46
bool operator==(const AcceptHeaderField &other) const
Definition http_accept.h:40