From 9dc32156244d86fe2ee57f15ac52937084e05f0c Mon Sep 17 00:00:00 2001 From: gbrodman Date: Thu, 3 Apr 2025 11:37:23 -0400 Subject: [PATCH] Redirect an empty RDAP path to the /help response (#2722) The behavior when someone hits the plain RDAP base URL isn't specified by the spec. Currently we just return a plain 404 which isn't particularly nice or helpful -- so it would probably be nicer to just redirect to the /help response instead. tested on alpha, https://pubapi-dot-domain-registry-alpha.appspot.com/rdap redirects to https://pubapi-dot-domain-registry-alpha.appspot.com/rdap/help --- .../registry/module/RequestComponent.java | 3 ++ .../module/pubapi/PubApiRequestComponent.java | 4 ++ .../google/registry/rdap/RdapEmptyAction.java | 54 +++++++++++++++++++ .../google/registry/rdap/RdapHelpAction.java | 4 +- .../registry/rdap/RdapEmptyActionTest.java | 42 +++++++++++++++ .../registry/module/pubapi/pubapi_routing.txt | 1 + .../google/registry/module/routing.txt | 1 + 7 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/google/registry/rdap/RdapEmptyAction.java create mode 100644 core/src/test/java/google/registry/rdap/RdapEmptyActionTest.java diff --git a/core/src/main/java/google/registry/module/RequestComponent.java b/core/src/main/java/google/registry/module/RequestComponent.java index bef4e282c..2ccd703e1 100644 --- a/core/src/main/java/google/registry/module/RequestComponent.java +++ b/core/src/main/java/google/registry/module/RequestComponent.java @@ -62,6 +62,7 @@ import google.registry.monitoring.whitebox.WhiteboxModule; import google.registry.rdap.RdapAutnumAction; import google.registry.rdap.RdapDomainAction; import google.registry.rdap.RdapDomainSearchAction; +import google.registry.rdap.RdapEmptyAction; import google.registry.rdap.RdapEntityAction; import google.registry.rdap.RdapEntitySearchAction; import google.registry.rdap.RdapHelpAction; @@ -261,6 +262,8 @@ interface RequestComponent { RdapDomainSearchAction rdapDomainSearchAction(); + RdapEmptyAction rdapEmptyAction(); + RdapEntityAction rdapEntityAction(); RdapEntitySearchAction rdapEntitySearchAction(); diff --git a/core/src/main/java/google/registry/module/pubapi/PubApiRequestComponent.java b/core/src/main/java/google/registry/module/pubapi/PubApiRequestComponent.java index 30d1ab205..0a6eef6d6 100644 --- a/core/src/main/java/google/registry/module/pubapi/PubApiRequestComponent.java +++ b/core/src/main/java/google/registry/module/pubapi/PubApiRequestComponent.java @@ -24,6 +24,7 @@ import google.registry.monitoring.whitebox.WhiteboxModule; import google.registry.rdap.RdapAutnumAction; import google.registry.rdap.RdapDomainAction; import google.registry.rdap.RdapDomainSearchAction; +import google.registry.rdap.RdapEmptyAction; import google.registry.rdap.RdapEntityAction; import google.registry.rdap.RdapEntitySearchAction; import google.registry.rdap.RdapHelpAction; @@ -55,6 +56,9 @@ public interface PubApiRequestComponent { RdapAutnumAction rdapAutnumAction(); RdapDomainAction rdapDomainAction(); RdapDomainSearchAction rdapDomainSearchAction(); + + RdapEmptyAction rdapEmptyAction(); + RdapEntityAction rdapEntityAction(); RdapEntitySearchAction rdapEntitySearchAction(); RdapHelpAction rdapHelpAction(); diff --git a/core/src/main/java/google/registry/rdap/RdapEmptyAction.java b/core/src/main/java/google/registry/rdap/RdapEmptyAction.java new file mode 100644 index 000000000..59384e2c2 --- /dev/null +++ b/core/src/main/java/google/registry/rdap/RdapEmptyAction.java @@ -0,0 +1,54 @@ +// Copyright 2025 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.rdap; + +import static google.registry.request.Action.Method.GET; +import static google.registry.request.Action.Method.HEAD; + +import google.registry.request.Action; +import google.registry.request.Response; +import google.registry.request.auth.Auth; +import jakarta.inject.Inject; +import java.io.IOException; + +/** + * RDAP action that serves the empty string, redirecting to the help page. + * + *

This isn't technically required, but if someone requests the base url it seems nice to give + * them the help response. + */ +@Action( + service = Action.GaeService.PUBAPI, + path = "/rdap/", + method = {GET, HEAD}, + auth = Auth.AUTH_PUBLIC) +public class RdapEmptyAction implements Runnable { + + private final Response response; + + @Inject + public RdapEmptyAction(Response response) { + this.response = response; + } + + @Override + public void run() { + try { + response.sendRedirect(RdapHelpAction.PATH); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/src/main/java/google/registry/rdap/RdapHelpAction.java b/core/src/main/java/google/registry/rdap/RdapHelpAction.java index b66d4216f..1d7849fe2 100644 --- a/core/src/main/java/google/registry/rdap/RdapHelpAction.java +++ b/core/src/main/java/google/registry/rdap/RdapHelpAction.java @@ -31,12 +31,14 @@ import java.util.Optional; /** RDAP (new WHOIS) action for help requests. */ @Action( service = GaeService.PUBAPI, - path = "/rdap/help", + path = RdapHelpAction.PATH, method = {GET, HEAD}, isPrefix = true, auth = Auth.AUTH_PUBLIC) public class RdapHelpAction extends RdapActionBase { + public static final String PATH = "/rdap/help"; + /** The help path for the RDAP terms of service. */ public static final String TOS_PATH = "/tos"; diff --git a/core/src/test/java/google/registry/rdap/RdapEmptyActionTest.java b/core/src/test/java/google/registry/rdap/RdapEmptyActionTest.java new file mode 100644 index 000000000..0e0116f58 --- /dev/null +++ b/core/src/test/java/google/registry/rdap/RdapEmptyActionTest.java @@ -0,0 +1,42 @@ +// Copyright 2025 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.rdap; + +import static com.google.common.truth.Truth.assertThat; + +import google.registry.testing.FakeResponse; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Tests for {@link RdapEmptyAction}. */ +public class RdapEmptyActionTest { + + private FakeResponse fakeResponse; + private RdapEmptyAction action; + + @BeforeEach + void beforeEach() { + fakeResponse = new FakeResponse(); + action = new RdapEmptyAction(fakeResponse); + } + + @Test + void testRedirect() { + action.run(); + assertThat(fakeResponse.getStatus()).isEqualTo(HttpServletResponse.SC_FOUND); + assertThat(fakeResponse.getPayload()).isEqualTo("Redirected to /rdap/help"); + } +} diff --git a/core/src/test/resources/google/registry/module/pubapi/pubapi_routing.txt b/core/src/test/resources/google/registry/module/pubapi/pubapi_routing.txt index 3a9ac8d1c..aa0b8f86d 100644 --- a/core/src/test/resources/google/registry/module/pubapi/pubapi_routing.txt +++ b/core/src/test/resources/google/registry/module/pubapi/pubapi_routing.txt @@ -1,6 +1,7 @@ SERVICE PATH CLASS METHODS OK MIN USER_POLICY PUBAPI /_dr/whois WhoisAction POST n APP ADMIN PUBAPI /check CheckApiAction GET n NONE PUBLIC +PUBAPI /rdap/ RdapEmptyAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC diff --git a/core/src/test/resources/google/registry/module/routing.txt b/core/src/test/resources/google/registry/module/routing.txt index 4b8a6a77c..53c8ab5a7 100644 --- a/core/src/test/resources/google/registry/module/routing.txt +++ b/core/src/test/resources/google/registry/module/routing.txt @@ -56,6 +56,7 @@ BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailable BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN PUBAPI /_dr/whois WhoisAction POST n APP ADMIN PUBAPI /check CheckApiAction GET n NONE PUBLIC +PUBAPI /rdap/ RdapEmptyAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC