| 4095 | |
| 4096 | template <typename T> |
| 4097 | inline bool parse_header(const char *beg, const char *end, T fn) { |
| 4098 | // Skip trailing spaces and tabs. |
| 4099 | while (beg < end && is_space_or_tab(end[-1])) { |
| 4100 | end--; |
| 4101 | } |
| 4102 | |
| 4103 | auto p = beg; |
| 4104 | while (p < end && *p != ':') { |
| 4105 | p++; |
| 4106 | } |
| 4107 | |
| 4108 | if (p == end) { return false; } |
| 4109 | |
| 4110 | auto key_end = p; |
| 4111 | |
| 4112 | if (*p++ != ':') { return false; } |
| 4113 | |
| 4114 | while (p < end && is_space_or_tab(*p)) { |
| 4115 | p++; |
| 4116 | } |
| 4117 | |
| 4118 | if (p < end) { |
| 4119 | auto key_len = key_end - beg; |
| 4120 | if (!key_len) { return false; } |
| 4121 | |
| 4122 | auto key = std::string(beg, key_end); |
| 4123 | auto val = case_ignore::equal(key, "Location") |
| 4124 | ? std::string(p, end) |
| 4125 | : decode_url(std::string(p, end), false); |
| 4126 | |
| 4127 | // NOTE: From RFC 9110: |
| 4128 | // Field values containing CR, LF, or NUL characters are |
| 4129 | // invalid and dangerous, due to the varying ways that |
| 4130 | // implementations might parse and interpret those |
| 4131 | // characters; a recipient of CR, LF, or NUL within a field |
| 4132 | // value MUST either reject the message or replace each of |
| 4133 | // those characters with SP before further processing or |
| 4134 | // forwarding of that message. |
| 4135 | static const std::string CR_LF_NUL("\r\n\0", 3); |
| 4136 | if (val.find_first_of(CR_LF_NUL) != std::string::npos) { return false; } |
| 4137 | |
| 4138 | fn(key, val); |
| 4139 | return true; |
| 4140 | } |
| 4141 | |
| 4142 | return false; |
| 4143 | } |
| 4144 | |
| 4145 | inline bool read_headers(Stream &strm, Headers &headers) { |
| 4146 | const auto bufsiz = 2048; |
no test coverage detected