| 1243 | } |
| 1244 | |
| 1245 | ParseResult |
| 1246 | validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh) |
| 1247 | { |
| 1248 | MIMEField *content_length_field = mime_hdr_field_find(hh->m_fields_impl, MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH); |
| 1249 | |
| 1250 | if (content_length_field) { |
| 1251 | // RFC 7230 section 3.3.3: |
| 1252 | // If a message is received with both a Transfer-Encoding and a |
| 1253 | // Content-Length header field, the Transfer-Encoding overrides |
| 1254 | // the Content-Length |
| 1255 | if (mime_hdr_field_find(hh->m_fields_impl, MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING) != nullptr) { |
| 1256 | // Delete all Content-Length headers |
| 1257 | Dbg(dbg_ctl_http, "Transfer-Encoding header and Content-Length headers the request, removing all Content-Length headers"); |
| 1258 | mime_hdr_field_delete(heap, hh->m_fields_impl, content_length_field, true); |
| 1259 | return PARSE_RESULT_DONE; |
| 1260 | } |
| 1261 | |
| 1262 | // RFC 7230 section 3.3.3: |
| 1263 | // If a message is received without Transfer-Encoding and with |
| 1264 | // either multiple Content-Length header fields having differing |
| 1265 | // field-values or a single Content-Length header field having an |
| 1266 | // invalid value, then the message framing is invalid and the |
| 1267 | // recipient MUST treat it as an unrecoverable error. If this is a |
| 1268 | // request message, the server MUST respond with a 400 (Bad Request) |
| 1269 | // status code and then close the connection |
| 1270 | std::string_view value = content_length_field->value_get(); |
| 1271 | |
| 1272 | // RFC 9110 section 8.6. |
| 1273 | // Content-Length = 1*DIGIT |
| 1274 | // |
| 1275 | if (value.empty()) { |
| 1276 | Dbg(dbg_ctl_http, "Content-Length headers don't match the ABNF, returning parse error"); |
| 1277 | return PARSE_RESULT_ERROR; |
| 1278 | } |
| 1279 | |
| 1280 | // If the content-length value contains a non-numeric value, the header is invalid |
| 1281 | if (std::find_if(value.cbegin(), value.cend(), [](std::string_view::value_type c) { return !std::isdigit(c); }) != |
| 1282 | value.cend()) { |
| 1283 | Dbg(dbg_ctl_http, "Content-Length value contains non-digit, returning parse error"); |
| 1284 | return PARSE_RESULT_ERROR; |
| 1285 | } |
| 1286 | |
| 1287 | while (content_length_field->has_dups()) { |
| 1288 | std::string_view value_dup = content_length_field->m_next_dup->value_get(); |
| 1289 | |
| 1290 | if ((value.length() != value_dup.length()) || value.compare(value_dup) != 0) { |
| 1291 | // Values are different, parse error |
| 1292 | Dbg(dbg_ctl_http, "Content-Length headers don't match, returning parse error"); |
| 1293 | return PARSE_RESULT_ERROR; |
| 1294 | } else { |
| 1295 | // Delete the duplicate since it has the same value |
| 1296 | Dbg(dbg_ctl_http, "Deleting duplicate Content-Length header"); |
| 1297 | mime_hdr_field_delete(heap, hh->m_fields_impl, content_length_field->m_next_dup, false); |
| 1298 | } |
| 1299 | } |
| 1300 | } |
| 1301 | |
| 1302 | return PARSE_RESULT_DONE; |
no test coverage detected