diff --git a/engine/engine.cpp b/engine/engine.cpp index 3b526fa4..461ee626 100644 --- a/engine/engine.cpp +++ b/engine/engine.cpp @@ -133,12 +133,16 @@ void Engine::on_navigation_success() { } Engine::LoadResult Engine::load(uri::Uri uri) { + static constexpr int kMaxRedirects = 10; + auto is_redirect = [](int status_code) { return status_code == 301 || status_code == 302 || status_code == 307 || status_code == 308; }; + int redirect_count = 0; protocol::Response response = protocol_handler_->handle(uri); while (response.err == protocol::Error::Ok && is_redirect(response.status_line.status_code)) { + ++redirect_count; auto location = response.headers.get("Location"); if (!location) { response.err = protocol::Error::InvalidResponse; @@ -148,6 +152,10 @@ Engine::LoadResult Engine::load(uri::Uri uri) { spdlog::info("Following {} redirect from {} to {}", response.status_line.status_code, uri.uri, *location); uri = uri::Uri::parse(std::string(*location), uri); response = protocol_handler_->handle(uri); + if (redirect_count > kMaxRedirects) { + response.err = protocol::Error::RedirectLimit; + return {std::move(response), std::move(uri)}; + } } return {std::move(response), std::move(uri)}; diff --git a/engine/engine_test.cpp b/engine/engine_test.cpp index a1f49768..7dfe5690 100644 --- a/engine/engine_test.cpp +++ b/engine/engine_test.cpp @@ -418,5 +418,16 @@ int main() { expect(contains(e.stylesheet().rules, {.selectors{"p"}, .declarations{{css::PropertyId::Color, "green"}}})); }); + etest::test("redirect loop", [] { + std::map responses; + responses["hax://example.com"s] = Response{ + .err = Error::Ok, + .status_line = {.status_code = 301}, + .headers = {{"Location", "hax://example.com"}}, + }; + engine::Engine e{std::make_unique(std::move(responses))}; + expect_eq(e.navigate(uri::Uri::parse("hax://example.com")), protocol::Error::RedirectLimit); + }); + return etest::run_all_tests(); }