88#include < string>
99#include < vector>
1010#include < boost/beast/http.hpp>
11- #include < boost/regex.hpp>
1211
1312using namespace icinga ;
1413
@@ -80,24 +79,6 @@ void HttpUtility::SendJsonError(HttpResponse& response,
8079 HttpUtility::SendJsonBody (response, params, result);
8180}
8281
83- /* *
84- * Regular expression for matching valid HTTP header names.
85- *
86- * Derived from the following syntax definition in RFC9110:
87- *
88- * field-name = token
89- * token = 1*tchar
90- * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
91- * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
92- * DIGIT = %x30-39 ; 0-9
93- *
94- * References:
95- * - https://datatracker.ietf.org/doc/html/rfc9110#section-5.1
96- * - https://datatracker.ietf.org/doc/html/rfc9110#appendix-A
97- * - https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
98- */
99- static const boost::regex l_HttpFieldNameRegex (" [0-9A-Za-z!#$%&'*+\\ -.^_`|~]+" );
100-
10182/* *
10283 * Check if the given string is suitable to be used as an HTTP header name.
10384 *
@@ -106,27 +87,33 @@ static const boost::regex l_HttpFieldNameRegex("[0-9A-Za-z!#$%&'*+\\-.^_`|~]+");
10687 */
10788bool HttpUtility::IsValidHeaderName (std::string_view name)
10889{
109- return boost::regex_match (name.begin (), name.end (), l_HttpFieldNameRegex);
90+ /*
91+ * Derived from the following syntax definition in RFC9110:
92+ *
93+ * field-name = token
94+ * token = 1*tchar
95+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
96+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
97+ * DIGIT = %x30-39 ; 0-9
98+ *
99+ * References:
100+ * - https://datatracker.ietf.org/doc/html/rfc9110#section-5.1
101+ * - https://datatracker.ietf.org/doc/html/rfc9110#appendix-A
102+ * - https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
103+ */
104+
105+ return !name.empty () && std::all_of (name.begin (), name.end (), [](char c) {
106+ switch (c) {
107+ case ' !' : case ' #' : case ' $' : case ' %' : case ' &' : case ' \' ' : case ' *' : case ' +' :
108+ case ' -' : case ' .' : case ' ^' : case ' _' : case ' `' : case ' |' : case ' ~' :
109+ return true ;
110+ default :
111+ return (' 0' <= c && c <= ' 9' ) || (' A' <= c && c <= ' Z' ) || (' a' <= c && c <= ' z' );
112+ }
113+
114+ });
110115}
111116
112- /* *
113- * Regular expression for matching valid HTTP header values.
114- *
115- * Derived from the following syntax definition in RFC9110:
116- *
117- * field-value = *field-content
118- * field-content = field-vchar [ 1*( SP / HTAB / field-vchar ) field-vchar ]
119- * field-vchar = VCHAR / obs-text
120- * obs-text = %x80-FF
121- * VCHAR = %x21-7E ; visible (printing) characters
122- *
123- * References:
124- * - https://datatracker.ietf.org/doc/html/rfc9110#section-5.5
125- * - https://datatracker.ietf.org/doc/html/rfc9110#appendix-A
126- * - https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
127- */
128- static const boost::regex l_HttpFieldValueRegex (R"( ([\x21-\x7e\x80-\xff](([ \t\x21-\x7e\x80-\xff]*)[\x21-\x7e\x80-\xff])?)*)" );
129-
130117/* *
131118 * Check if the given string is suitable to be used as an HTTP header value.
132119 *
@@ -135,5 +122,31 @@ static const boost::regex l_HttpFieldValueRegex(R"(([\x21-\x7e\x80-\xff](([ \t\x
135122 */
136123bool HttpUtility::IsValidHeaderValue (std::string_view value)
137124{
138- return boost::regex_match (value.begin (), value.end (), l_HttpFieldValueRegex);
125+ /*
126+ * Derived from the following syntax definition in RFC9110:
127+ *
128+ * field-value = *field-content
129+ * field-content = field-vchar [ 1*( SP / HTAB / field-vchar ) field-vchar ]
130+ * field-vchar = VCHAR / obs-text
131+ * obs-text = %x80-FF
132+ * VCHAR = %x21-7E ; visible (printing) characters
133+ *
134+ * References:
135+ * - https://datatracker.ietf.org/doc/html/rfc9110#section-5.5
136+ * - https://datatracker.ietf.org/doc/html/rfc9110#appendix-A
137+ * - https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
138+ */
139+
140+ if (!value.empty ()) {
141+ // Must not start with space or tab.
142+ for (char c : {*value.begin (), *value.rbegin ()}) {
143+ if (c == ' ' || c == ' \t ' ) {
144+ return false ;
145+ }
146+ }
147+ }
148+
149+ return std::all_of (value.begin (), value.end (), [](char c) {
150+ return c == ' ' || c == ' \t ' || (' \x21 ' <= c && c <= ' \x7e ' ) || (' \x80 ' <= c && c <= ' \xff ' );
151+ });
139152}
0 commit comments