diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 25df9cf44b..46dd332117 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -209,6 +209,26 @@ void HTTPRequest::cancel_request() { requesting = false; } +bool HTTPRequest::_is_content_header(const String &p_header) const { + return (p_header.begins_with("content-type:") || p_header.begins_with("content-length:") || p_header.begins_with("content-location:") || p_header.begins_with("content-encoding:") || + p_header.begins_with("transfer-encoding:") || p_header.begins_with("connection:") || p_header.begins_with("authorization:")); +} + +bool HTTPRequest::_is_method_safe() const { + return (method == HTTPClient::METHOD_GET || method == HTTPClient::METHOD_HEAD || method == HTTPClient::METHOD_OPTIONS || method == HTTPClient::METHOD_TRACE); +} + +Error HTTPRequest::_get_redirect_headers(Vector *r_headers) { + for (const String &E : headers) { + const String h = E.to_lower(); + // We strip content headers when changing a redirect to GET. + if (!_is_content_header(h)) { + r_headers->push_back(E); + } + } + return OK; +} + bool HTTPRequest::_handle_response(bool *ret_value) { if (!client->has_response()) { _defer_done(RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray()); @@ -268,6 +288,16 @@ bool HTTPRequest::_handle_response(bool *ret_value) { final_body_size.set(0); redirections = new_redirs; *ret_value = false; + if (!_is_method_safe()) { + // 301, 302, and 303 are changed to GET for unsafe methods. + // See: https://www.rfc-editor.org/rfc/rfc9110#section-15.4-3.1 + method = HTTPClient::METHOD_GET; + // Content headers should be dropped if changing method. + // See: https://www.rfc-editor.org/rfc/rfc9110#section-15.4-6.2.1 + Vector req_headers; + _get_redirect_headers(&req_headers); + headers = req_headers; + } return true; } } diff --git a/scene/main/http_request.h b/scene/main/http_request.h index a2b56b063e..ccac9809fe 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -102,6 +102,10 @@ private: void _redirect_request(const String &p_new_url); + bool _is_content_header(const String &p_header) const; + bool _is_method_safe() const; + Error _get_redirect_headers(Vector *r_headers); + bool _handle_response(bool *ret_value); Error _parse_url(const String &p_url);