Skip to content

Commit ac7a8db

Browse files
committed
Don't use regex for HTTP header validation
1 parent 38bf4bd commit ac7a8db

File tree

1 file changed

+52
-39
lines changed

1 file changed

+52
-39
lines changed

lib/remote/httputility.cpp

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <string>
99
#include <vector>
1010
#include <boost/beast/http.hpp>
11-
#include <boost/regex.hpp>
1211

1312
using 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
*/
10788
bool 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
*/
136123
bool 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 or end 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

Comments
 (0)