Set up a unified registry servlet for Jetty (#2338)

This PR creates a unified RegistryServlet that will serve all
non-console traffic. It also creates a jetty subproject that allows one
to run Nomulus on top of a standard Jetty 12 runtime.

`./gradlew :jetty:stage` will create a jetty base folder at
`jetty/build/jetty-base` where one is able spin up a local Nomulus server
by running the following command inside the folder:

```bash
java -jar ${JETTY_HOME}/start.jar
```

`JETTY_HOME` is a folder where the [Jetty runtime](https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/12.0.6/jetty-home-12.0.6.zip) is located.

This PR also adds a Gradle task to create a Nomulus image based on the
official Jetty image:

```bash
./gradlew :jetty:buildNomulusImage
```
This commit is contained in:
Lai Jiang 2024-02-29 12:37:51 -05:00 committed by GitHub
parent 78c7d44546
commit d1f678bba7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 790 additions and 43 deletions

View file

@ -40,7 +40,6 @@ import org.joda.time.DateTime;
@Module
public class BatchModule {
public static final String PARAM_DRY_RUN = "dryRun";
public static final String PARAM_FAST = "fast";
@Provides
@ -138,10 +137,4 @@ public class BatchModule {
static boolean provideIsFast(HttpServletRequest req) {
return extractBooleanParameter(req, PARAM_FAST);
}
@Provides
@Parameter(PARAM_DRY_RUN)
static boolean provideIsDryRun(HttpServletRequest req) {
return extractBooleanParameter(req, PARAM_DRY_RUN);
}
}

View file

@ -16,9 +16,9 @@ package google.registry.batch;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.batch.BatchModule.PARAM_DRY_RUN;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.RegistryEnvironment.PRODUCTION;

View file

@ -17,12 +17,12 @@ package google.registry.batch;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.batch.BatchModule.PARAM_DRY_RUN;
import static google.registry.dns.DnsUtils.requestDomainDnsRefresh;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_DELETE;
import static google.registry.model.tld.Tlds.getTldsOfType;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
import static google.registry.request.RequestParameters.PARAM_TLDS;
import static google.registry.util.RegistryEnvironment.PRODUCTION;

View file

@ -15,10 +15,10 @@
package google.registry.batch;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.batch.BatchModule.PARAM_DRY_RUN;
import static google.registry.beam.BeamUtils.createJobName;
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;

View file

@ -14,8 +14,8 @@
package google.registry.batch;
import static google.registry.batch.BatchModule.PARAM_DRY_RUN;
import static google.registry.beam.BeamUtils.createJobName;
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;

View file

@ -84,11 +84,5 @@ public class EppToolAction implements Runnable {
static String provideClientId(HttpServletRequest req) {
return extractRequiredParameter(req, "clientId");
}
@Provides
@Parameter("dryRun")
static boolean provideIsDryRun(HttpServletRequest req) {
return extractBooleanParameter(req, "dryRun");
}
}
}

View file

@ -0,0 +1,108 @@
// Copyright 2024 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.module;
import com.google.monitoring.metrics.MetricReporter;
import dagger.Component;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
import google.registry.batch.BatchModule;
import google.registry.bigquery.BigqueryModule;
import google.registry.config.CloudTasksUtilsModule;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.export.DriveModule;
import google.registry.export.sheet.SheetsServiceModule;
import google.registry.flows.ServerTridProviderModule;
import google.registry.flows.custom.CustomLogicFactoryModule;
import google.registry.groups.DirectoryModule;
import google.registry.groups.GmailModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.RegistryComponent.RegistryModule;
import google.registry.module.RequestComponent.RequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.persistence.PersistenceModule;
import google.registry.privileges.secretmanager.SecretManagerModule;
import google.registry.rde.JSchModule;
import google.registry.request.Modules.GsonModule;
import google.registry.request.Modules.NetHttpTransportModule;
import google.registry.request.Modules.UrlConnectionServiceModule;
import google.registry.request.Modules.UserServiceModule;
import google.registry.request.RequestHandler;
import google.registry.request.auth.AuthModule;
import google.registry.request.auth.RequestAuthenticator;
import google.registry.ui.ConsoleDebug.ConsoleConfigModule;
import google.registry.util.UtilsModule;
import javax.inject.Provider;
import javax.inject.Singleton;
/** Dagger component with instance lifetime. */
@Singleton
@Component(
modules = {
AuthModule.class,
BatchModule.class,
BigqueryModule.class,
CloudTasksUtilsModule.class,
ConfigModule.class,
ConsoleConfigModule.class,
CredentialModule.class,
CustomLogicFactoryModule.class,
DirectoryModule.class,
DriveModule.class,
DummyKeyringModule.class,
GmailModule.class,
GroupsModule.class,
GroupssettingsModule.class,
GsonModule.class,
JSchModule.class,
KeyModule.class,
KeyringModule.class,
NetHttpTransportModule.class,
PersistenceModule.class,
RegistryModule.class,
RequestComponentModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
SheetsServiceModule.class,
StackdriverModule.class,
UrlConnectionServiceModule.class,
UserServiceModule.class,
UtilsModule.class,
VoidDnsWriterModule.class,
})
interface RegistryComponent {
RequestHandler<RequestComponent> requestHandler();
Lazy<MetricReporter> metricReporter();
@Module
class RegistryModule {
@Provides
static RequestHandler<RequestComponent> provideRequestHandler(
Provider<RequestComponent.Builder> componentProvider,
RequestAuthenticator requestAuthenticator) {
return RequestHandler.create(RequestComponent.class, componentProvider, requestAuthenticator);
}
}
}

View file

@ -0,0 +1,30 @@
// Copyright 2024 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.module;
import com.google.monitoring.metrics.MetricReporter;
import dagger.Lazy;
import google.registry.request.RequestHandler;
/** Servlet that handles all requests. */
public class RegistryServlet extends ServletBase {
private static final RegistryComponent component = DaggerRegistryComponent.create();
private static final RequestHandler<RequestComponent> requestHandler = component.requestHandler();
private static final Lazy<MetricReporter> metricReporter = component.metricReporter();
public RegistryServlet() {
super(requestHandler, metricReporter);
}
}

View file

@ -0,0 +1,337 @@
// Copyright 2024 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.module;
import dagger.Module;
import dagger.Subcomponent;
import google.registry.batch.BatchModule;
import google.registry.batch.CannedScriptExecutionAction;
import google.registry.batch.DeleteExpiredDomainsAction;
import google.registry.batch.DeleteLoadTestDataAction;
import google.registry.batch.DeleteProberDataAction;
import google.registry.batch.ExpandBillingRecurrencesAction;
import google.registry.batch.RelockDomainAction;
import google.registry.batch.ResaveAllEppResourcesPipelineAction;
import google.registry.batch.ResaveEntityAction;
import google.registry.batch.SendExpiringCertificateNotificationEmailAction;
import google.registry.batch.WipeOutContactHistoryPiiAction;
import google.registry.bsa.BsaDownloadAction;
import google.registry.bsa.BsaRefreshAction;
import google.registry.bsa.UploadBsaUnavailableDomainsAction;
import google.registry.cron.CronModule;
import google.registry.cron.TldFanoutAction;
import google.registry.dns.DnsModule;
import google.registry.dns.PublishDnsUpdatesAction;
import google.registry.dns.ReadDnsRefreshRequestsAction;
import google.registry.dns.RefreshDnsAction;
import google.registry.dns.RefreshDnsOnHostRenameAction;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateConfigModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.export.ExportDomainListsAction;
import google.registry.export.ExportPremiumTermsAction;
import google.registry.export.ExportReservedTermsAction;
import google.registry.export.SyncGroupMembersAction;
import google.registry.export.sheet.SheetModule;
import google.registry.export.sheet.SyncRegistrarsSheetAction;
import google.registry.flows.CheckApiAction;
import google.registry.flows.CheckApiAction.CheckApiModule;
import google.registry.flows.EppTlsAction;
import google.registry.flows.EppToolAction;
import google.registry.flows.EppToolAction.EppToolModule;
import google.registry.flows.FlowComponent;
import google.registry.flows.TlsCredentials.EppTlsModule;
import google.registry.flows.custom.CustomLogicModule;
import google.registry.loadtest.LoadTestAction;
import google.registry.loadtest.LoadTestModule;
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.RdapEntityAction;
import google.registry.rdap.RdapEntitySearchAction;
import google.registry.rdap.RdapHelpAction;
import google.registry.rdap.RdapIpAction;
import google.registry.rdap.RdapModule;
import google.registry.rdap.RdapNameserverAction;
import google.registry.rdap.RdapNameserverSearchAction;
import google.registry.rdap.UpdateRegistrarRdapBaseUrlsAction;
import google.registry.rde.BrdaCopyAction;
import google.registry.rde.RdeModule;
import google.registry.rde.RdeReportAction;
import google.registry.rde.RdeReporter;
import google.registry.rde.RdeStagingAction;
import google.registry.rde.RdeUploadAction;
import google.registry.reporting.ReportingModule;
import google.registry.reporting.billing.BillingModule;
import google.registry.reporting.billing.CopyDetailReportsAction;
import google.registry.reporting.billing.GenerateInvoicesAction;
import google.registry.reporting.billing.PublishInvoicesAction;
import google.registry.reporting.icann.DnsCountQueryCoordinatorModule;
import google.registry.reporting.icann.IcannReportingModule;
import google.registry.reporting.icann.IcannReportingStagingAction;
import google.registry.reporting.icann.IcannReportingUploadAction;
import google.registry.reporting.spec11.GenerateSpec11ReportAction;
import google.registry.reporting.spec11.PublishSpec11ReportAction;
import google.registry.reporting.spec11.Spec11Module;
import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
import google.registry.tmch.NordnUploadAction;
import google.registry.tmch.NordnVerifyAction;
import google.registry.tmch.TmchCrlAction;
import google.registry.tmch.TmchDnlAction;
import google.registry.tmch.TmchModule;
import google.registry.tmch.TmchSmdrlAction;
import google.registry.tools.server.CreateGroupsAction;
import google.registry.tools.server.GenerateZoneFilesAction;
import google.registry.tools.server.ListDomainsAction;
import google.registry.tools.server.ListHostsAction;
import google.registry.tools.server.ListPremiumListsAction;
import google.registry.tools.server.ListRegistrarsAction;
import google.registry.tools.server.ListReservedListsAction;
import google.registry.tools.server.ListTldsAction;
import google.registry.tools.server.RefreshDnsForAllDomainsAction;
import google.registry.tools.server.ToolsServerModule;
import google.registry.tools.server.VerifyOteAction;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.console.ConsoleDomainListAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
import google.registry.ui.server.console.settings.ContactAction;
import google.registry.ui.server.console.settings.SecurityAction;
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
import google.registry.ui.server.registrar.ConsoleUiAction;
import google.registry.ui.server.registrar.OteStatusAction;
import google.registry.ui.server.registrar.RegistrarConsoleModule;
import google.registry.ui.server.registrar.RegistrarSettingsAction;
import google.registry.ui.server.registrar.RegistryLockGetAction;
import google.registry.ui.server.registrar.RegistryLockPostAction;
import google.registry.ui.server.registrar.RegistryLockVerifyAction;
import google.registry.whois.WhoisAction;
import google.registry.whois.WhoisHttpAction;
import google.registry.whois.WhoisModule;
/** Dagger component with per-request lifetime. */
@RequestScope
@Subcomponent(
modules = {
BatchModule.class,
BillingModule.class,
CheckApiModule.class,
CloudDnsWriterModule.class,
CronModule.class,
CustomLogicModule.class,
DnsCountQueryCoordinatorModule.class,
DnsModule.class,
DnsUpdateConfigModule.class,
DnsUpdateWriterModule.class,
EppTlsModule.class,
EppToolModule.class,
IcannReportingModule.class,
LoadTestModule.class,
RdapModule.class,
RdeModule.class,
RegistrarConsoleModule.class,
ReportingModule.class,
RequestModule.class,
SheetModule.class,
Spec11Module.class,
TmchModule.class,
ToolsServerModule.class,
VoidDnsWriterModule.class,
WhiteboxModule.class,
WhoisModule.class,
})
interface RequestComponent {
FlowComponent.Builder flowComponentBuilder();
BrdaCopyAction brdaCopyAction();
BsaDownloadAction bsaDownloadAction();
BsaRefreshAction bsaRefreshAction();
CannedScriptExecutionAction cannedScriptExecutionAction();
CheckApiAction checkApiAction();
ConsoleDomainGetAction consoleDomainGetAction();
ConsoleDomainListAction consoleDomainListAction();
ConsoleOteSetupAction consoleOteSetupAction();
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
ConsoleUiAction consoleUiAction();
ConsoleUserDataAction consoleUserDataAction();
ContactAction contactAction();
CopyDetailReportsAction copyDetailReportAction();
CreateGroupsAction createGroupsAction();
DeleteExpiredDomainsAction deleteExpiredDomainsAction();
DeleteLoadTestDataAction deleteLoadTestDataAction();
DeleteProberDataAction deleteProberDataAction();
EppTlsAction eppTlsAction();
EppToolAction eppToolAction();
ExpandBillingRecurrencesAction expandBillingRecurrencesAction();
ExportDomainListsAction exportDomainListsAction();
ExportPremiumTermsAction exportPremiumTermsAction();
ExportReservedTermsAction exportReservedTermsAction();
GenerateInvoicesAction generateInvoicesAction();
GenerateSpec11ReportAction generateSpec11ReportAction();
GenerateZoneFilesAction generateZoneFilesAction();
IcannReportingStagingAction icannReportingStagingAction();
IcannReportingUploadAction icannReportingUploadAction();
ListDomainsAction listDomainsAction();
ListHostsAction listHostsAction();
ListPremiumListsAction listPremiumListsAction();
ListRegistrarsAction listRegistrarsAction();
ListReservedListsAction listReservedListsAction();
ListTldsAction listTldsAction();
LoadTestAction loadTestAction();
NordnUploadAction nordnUploadAction();
NordnVerifyAction nordnVerifyAction();
OteStatusAction oteStatusAction();
PublishDnsUpdatesAction publishDnsUpdatesAction();
PublishInvoicesAction uploadInvoicesAction();
PublishSpec11ReportAction publishSpec11ReportAction();
RdapAutnumAction rdapAutnumAction();
RdapDomainAction rdapDomainAction();
RdapDomainSearchAction rdapDomainSearchAction();
RdapEntityAction rdapEntityAction();
RdapEntitySearchAction rdapEntitySearchAction();
RdapHelpAction rdapHelpAction();
RdapIpAction rdapDefaultAction();
RdapNameserverAction rdapNameserverAction();
RdapNameserverSearchAction rdapNameserverSearchAction();
RdeReportAction rdeReportAction();
RdeReporter rdeReporter();
RdeStagingAction rdeStagingAction();
RdeUploadAction rdeUploadAction();
ReadDnsRefreshRequestsAction readDnsRefreshRequestsAction();
RefreshDnsAction refreshDnsAction();
RefreshDnsForAllDomainsAction refreshDnsForAllDomainsAction();
RefreshDnsOnHostRenameAction refreshDnsOnHostRenameAction();
RegistrarSettingsAction registrarSettingsAction();
RegistrarsAction registrarsAction();
RegistryLockGetAction registryLockGetAction();
RegistryLockPostAction registryLockPostAction();
RegistryLockVerifyAction registryLockVerifyAction();
RelockDomainAction relockDomainAction();
ResaveAllEppResourcesPipelineAction resaveAllEppResourcesPipelineAction();
ResaveEntityAction resaveEntityAction();
SecurityAction securityAction();
SendExpiringCertificateNotificationEmailAction sendExpiringCertificateNotificationEmailAction();
SyncGroupMembersAction syncGroupMembersAction();
SyncRegistrarsSheetAction syncRegistrarsSheetAction();
TldFanoutAction tldFanoutAction();
TmchCrlAction tmchCrlAction();
TmchDnlAction tmchDnlAction();
TmchSmdrlAction tmchSmdrlAction();
UpdateRegistrarRdapBaseUrlsAction updateRegistrarRdapBaseUrlsAction();
UploadBsaUnavailableDomainsAction uploadBsaUnavailableDomains();
VerifyOteAction verifyOteAction();
WhoisAction whoisAction();
WhoisHttpAction whoisHttpAction();
WhoisRegistrarFieldsAction whoisRegistrarFieldsAction();
WipeOutContactHistoryPiiAction wipeOutContactHistoryPiiAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<RequestComponent> {
@Override
public abstract Builder requestModule(RequestModule requestModule);
@Override
public abstract RequestComponent build();
}
@Module(subcomponents = RequestComponent.class)
static class RequestComponentModule {}
}

View file

@ -95,7 +95,7 @@ public class RequestHandler<C> {
}
/** Creates a new RequestHandler with an explicit component class for test purposes. */
public static <C> RequestHandler<C> createForTest(
public static <C> RequestHandler<C> create(
Class<C> component,
Provider<? extends RequestComponentBuilder<C>> requestComponentBuilderProvider,
RequestAuthenticator requestAuthenticator) {

View file

@ -18,6 +18,8 @@ import static com.google.common.net.MediaType.JSON_UTF_8;
import static google.registry.dns.PublishDnsUpdatesAction.CLOUD_TASKS_RETRY_HEADER;
import static google.registry.model.tld.Tlds.assertTldExists;
import static google.registry.model.tld.Tlds.assertTldsExist;
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
import static google.registry.request.RequestParameters.extractBooleanParameter;
import static google.registry.request.RequestParameters.extractRequiredHeader;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import static google.registry.request.RequestParameters.extractSetOfParameters;
@ -91,6 +93,12 @@ public final class RequestModule {
return tlds;
}
@Provides
@Parameter(RequestParameters.PARAM_DRY_RUN)
static boolean provideDryRun(HttpServletRequest req) {
return extractBooleanParameter(req, PARAM_DRY_RUN);
}
@Provides
static Response provideResponse(ResponseImpl response) {
return response;

View file

@ -34,9 +34,13 @@ public final class RequestParameters {
/** The standardized request parameter name used by any action taking a tld parameter. */
public static final String PARAM_TLD = "tld";
/** The standardized request parameter name used by any action taking multiple tld parameters. */
public static final String PARAM_TLDS = "tlds";
/** The standardized request parameter name used by any action in dry run mode. */
public static final String PARAM_DRY_RUN = "dryRun";
/**
* Returns first GET or POST parameter associated with {@code name}.
*
@ -123,10 +127,10 @@ public final class RequestParameters {
* <p>Both missing parameter and parameter with empty value result in an empty set.
*
* @param req the request that has the parameter
* @param name the name of the parameter, should be in plural form (e.g. tlds=, not tld=)
* @param name the name of the parameter (should be in plural form. e.g., tlds=, not tld=)
*/
public static ImmutableSet<String> extractSetOfParameters(HttpServletRequest req, String name) {
// First we make sure the user didn't accidentally try to pass the "set of parameters" as
// First, we make sure the user didn't accidentally try to pass the "set of parameters" as
// multiple tld=a&tld=b parameters instead of tld=a,b
String[] parameters = req.getParameterValues(name);
if (parameters != null && parameters.length > 1) {
@ -160,7 +164,7 @@ public final class RequestParameters {
*
* @param req the request that has the parameter
* @param enumClass the Class of the expected Enum type
* @param name the name of the parameter, should be in plural form (e.g. tlds=, not tld=)
* @param name the name of the parameter (should be in plural form e.g., tlds=, not tld=)
* @throws BadRequestException if any of the comma-delimited values of the request parameter named
* {@code name} aren't equal to any of the values in {@code enumClass}
*/
@ -293,7 +297,7 @@ public final class RequestParameters {
/**
* Returns first HTTP header associated with {@code name}.
*
* @param name case insensitive header name
* @param name case-insensitive header name
* @throws BadRequestException if request header is absent or empty
*/
public static String extractRequiredHeader(HttpServletRequest req, String name) {
@ -307,7 +311,7 @@ public final class RequestParameters {
/**
* Returns an {@link Optional} of the first HTTP header associated with {@code name}, or empty.
*
* @param name case insensitive header name
* @param name case-insensitive header name
*/
public static Optional<String> extractOptionalHeader(HttpServletRequest req, String name) {
return Optional.ofNullable(emptyToNull(req.getHeader(name)));

View file

@ -70,12 +70,6 @@ public class ToolsServerModule {
return extractRequiredParameter(req, "rawKeys");
}
@Provides
@Parameter("jobId")
String provideJobId(HttpServletRequest req) {
return extractRequiredParameter(req, "jobId");
}
@Provides
@Parameter("batchSize")
static Optional<Integer> provideBatchSize(HttpServletRequest req) {

View file

@ -51,7 +51,7 @@ public class ConsoleDomainGetAction implements JsonGetAction {
AuthResult authResult,
Response response,
Gson gson,
@Parameter("domain") String paramDomain) {
@Parameter("consoleDomain") String paramDomain) {
this.authResult = authResult;
this.response = response;
this.gson = gson;

View file

@ -75,7 +75,7 @@ public final class ConsoleOteSetupAction extends HtmlAction {
StringGenerator passwordGenerator;
@Inject
@Parameter("clientId")
@Parameter("consoleClientId")
Optional<String> clientId;
@Inject

View file

@ -85,8 +85,15 @@ public final class ConsoleRegistrarCreatorAction extends HtmlAction {
@Inject SendEmailUtils sendEmailUtils;
@Inject @Named("base58StringGenerator") StringGenerator passwordGenerator;
@Inject @Named("digitOnlyStringGenerator") StringGenerator passcodeGenerator;
@Inject @Parameter("clientId") Optional<String> clientId;
@Inject @Parameter("name") Optional<String> name;
@Inject
@Parameter("consoleClientId")
Optional<String> clientId;
@Inject
@Parameter("consoleName")
Optional<String> name;
@Inject @Parameter("billingAccount") Optional<String> billingAccount;
@Inject @Parameter("ianaId") Optional<Integer> ianaId;
@Inject @Parameter("referralEmail") Optional<String> referralEmail;

View file

@ -17,7 +17,6 @@ package google.registry.ui.server.registrar;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
@ -85,7 +84,7 @@ public final class ConsoleUiAction extends HtmlAction {
boolean enabled;
@Inject
@Parameter(PARAM_CLIENT_ID)
@Parameter("consoleClientId")
Optional<String> paramClientId;
@Inject

View file

@ -52,13 +52,13 @@ public final class RegistrarConsoleModule {
}
@Provides
@Parameter(PARAM_CLIENT_ID)
@Parameter("consoleClientId")
static Optional<String> provideOptionalClientId(HttpServletRequest req) {
return extractOptionalParameter(req, PARAM_CLIENT_ID);
}
@Provides
@Parameter(PARAM_CLIENT_ID)
@Parameter("consoleClientId")
static String provideClientId(HttpServletRequest req) {
return extractRequiredParameter(req, PARAM_CLIENT_ID);
}
@ -76,7 +76,7 @@ public final class RegistrarConsoleModule {
}
@Provides
@Parameter("name")
@Parameter("consoleName")
static Optional<String> provideOptionalName(HttpServletRequest req) {
return extractOptionalParameter(req, "name");
}
@ -178,7 +178,7 @@ public final class RegistrarConsoleModule {
}
@Provides
@Parameter("domain")
@Parameter("consoleDomain")
static String provideDomain(HttpServletRequest req) {
return extractRequiredParameter(req, "domain");
}

View file

@ -52,7 +52,7 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
/**
* Servlet that allows for getting locks for a particular registrar.
* Action that allows for getting locks for a particular registrar.
*
* <p>Note: at the moment we have no mechanism for JSON GET/POSTs in the same class or at the same
* URL, which is why this is distinct from the {@link RegistryLockPostAction}.
@ -90,7 +90,7 @@ public final class RegistryLockGetAction implements JsonGetAction {
Response response,
AuthenticatedRegistrarAccessor registrarAccessor,
AuthResult authResult,
@Parameter(PARAM_CLIENT_ID) Optional<String> paramClientId) {
@Parameter("consoleClientId") Optional<String> paramClientId) {
this.method = method;
this.response = response;
this.registrarAccessor = registrarAccessor;

View file

@ -199,7 +199,7 @@ public final class RequestHandlerTest {
void beforeEach() throws Exception {
// Initialize here, not inline, so that we pick up the mocked UserService.
handler =
RequestHandler.createForTest(
RequestHandler.create(
Component.class,
() ->
new Builder() {

7
jetty/Dockerfile Normal file
View file

@ -0,0 +1,7 @@
FROM jetty:12-jdk17
ADD --chown=jetty:jetty build/jetty-base /jetty-base
ENV JETTY_BASE=/jetty-base
WORKDIR "$JETTY_BASE"
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/usr/local/jetty/start.jar"]

52
jetty/build.gradle Normal file
View file

@ -0,0 +1,52 @@
// Copyright 2024 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.
apply plugin: 'war'
tasks.register('copyJettyBase', Copy) {
from(layout.projectDirectory.dir('src/main')) {
include 'jetty-base/**'
}
into layout.buildDirectory
}
war {
setArchiveBaseName("root")
setDestinationDirectory(layout.buildDirectory.dir('jetty-base/webapps'))
dependsOn(tasks.named('copyJettyBase'))
}
dependencies {
implementation project(':core')
}
tasks.register('copyConsole', Copy) {
from("${rootDir}/console-webapp/dist/console-webapp") {
include "**/*"
}
into layout.buildDirectory.dir('jetty-base/webapps/console')
dependsOn(':console-webapp:buildConsoleWebappProd')
}
tasks.register('stage') {
dependsOn(tasks.named('war'))
dependsOn(tasks.named('copyConsole'))
}
tasks.register('buildNomulusImage', Exec) {
commandLine 'docker', 'build', '-t', 'nomulus', '.'
dependsOn(tasks.named('stage'))
}
project.build.dependsOn(tasks.named('buildNomulusImage'))

View file

@ -0,0 +1,10 @@
## Set logging levels from: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
org.eclipse.jetty.LEVEL=INFO
## Configure a level for an arbitrary logger tree
#com.example.LEVEL=INFO
## Configure a level for specific logger
#com.example.MyComponent.LEVEL=INFO
## Configure JMX Context Name
# org.eclipse.jetty.logging.jmx.context=JettyServer
## Hide stacks traces in an arbitrary logger tree
#com.example.STACKS=false

View file

@ -0,0 +1,36 @@
# ---------------------------------------
# Module: ee8-deploy
# This module enables webapp deployment from the `$JETTY_BASE/webapps` directory.
# ---------------------------------------
--modules=ee8-deploy
## Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps
## Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault-ee8.xml
## Monitored directory scan period (seconds)
jetty.deploy.scanInterval=1
## Whether to extract *.war files
# jetty.deploy.extractWars=true
## Whether to give the parent classloader priority
# jetty.deploy.parentLoaderPriority=true
## Comma separated list of configuration classes to set.
# jetty.deploy.configurationClasses=
## Pattern to select jars from the container classloader to be scanned (or null to scan no jars)
# jetty.deploy.containerScanJarPattern=.*/jetty-servlet-api-[^/]*\.jar$|.*/javax.servlet.jsp.jstl-.*\.jar$
## Pattern to select jars from the container classloader to be scanned (or null to scan all jars).
# jetty.deploy.webInfScanJarPattern=
## Pattern to exclude discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerExclusionPattern=
## Order of discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerOrder=

View file

@ -0,0 +1,47 @@
# ---------------------------------------
# Module: http
# Enables a clear-text HTTP connector.
# By default clear-text HTTP/1.1 is enabled, and clear-text HTTP/2 may be added by enabling the "http2c" module.
# ---------------------------------------
--modules=http
### Clear-Text HTTP Connector Configuration
## The host/address to bind the connector to.
jetty.http.host=0.0.0.0
## The port the connector listens on.
# jetty.http.port=8080
## The connector idle timeout, in milliseconds.
# jetty.http.idleTimeout=30000
## The number of acceptors (-1 picks a default value based on number of cores).
# jetty.http.acceptors=1
## The number of selectors (-1 picks a default value based on number of cores).
# jetty.http.selectors=-1
## The ServerSocketChannel accept queue backlog (0 picks the platform default).
# jetty.http.acceptQueueSize=0
## The thread priority delta to give to acceptor threads.
# jetty.http.acceptorPriorityDelta=0
## Whether to enable the SO_REUSEADDR socket option.
# jetty.http.reuseAddress=true
## Whether to enable the SO_REUSEPORT socket option.
# jetty.http.reusePort=false
## Whether to enable the TCP_NODELAY socket option on accepted sockets.
# jetty.http.acceptedTcpNoDelay=true
## The SO_RCVBUF socket option to set on accepted sockets.
## A value of -1 indicates that the platform default is used.
# jetty.http.acceptedReceiveBufferSize=-1
## The SO_SNDBUF socket option to set on accepted sockets.
## A value of -1 indicates that the platform default is used.
# jetty.http.acceptedSendBufferSize=-1

View file

@ -0,0 +1,100 @@
# ---------------------------------------
# Module: server
# Enables and configures the Jetty server.
# This module does not enable any network protocol support.
# To enable a specific network protocol such as HTTP/1.1, you must enable the correspondent Jetty module.
# ---------------------------------------
--modules=server
### Common HTTP configuration
## Scheme to use to build URIs for secure redirects
# jetty.httpConfig.secureScheme=https
## Port to use to build URIs for secure redirects
# jetty.httpConfig.securePort=8443
## Response content buffer size (in bytes)
# jetty.httpConfig.outputBufferSize=32768
## Max response content write length that is buffered (in bytes)
# jetty.httpConfig.outputAggregationSize=8192
## If HTTP/1.x persistent connections should be enabled
# jetty.httpConfig.persistentConnectionsEnabled=true
## Max request headers size (in bytes)
# jetty.httpConfig.requestHeaderSize=8192
## Max response headers size (in bytes)
# jetty.httpConfig.responseHeaderSize=8192
## Whether to send the Server: header
# jetty.httpConfig.sendServerVersion=true
## Whether to send the Date: header
# jetty.httpConfig.sendDateHeader=false
## Max per-connection header cache size (in nodes)
# jetty.httpConfig.headerCacheSize=1024
## Whether, for requests with content, delay dispatch until some content has arrived
# jetty.httpConfig.delayDispatchUntilContent=true
## Maximum number of error dispatches to prevent looping
# jetty.httpConfig.maxErrorDispatches=10
## Relative Redirect Locations allowed
# jetty.httpConfig.relativeRedirectAllowed=true
## Whether to use direct ByteBuffers for reading or writing
# jetty.httpConfig.useInputDirectByteBuffers=true
# jetty.httpConfig.useOutputDirectByteBuffers=true
## HTTP Compliance: RFC7230, RFC7230_LEGACY, RFC2616, RFC2616_LEGACY, LEGACY
# jetty.httpConfig.compliance=RFC7230
## URI Compliance: DEFAULT, LEGACY, RFC3986, RFC3986_UNAMBIGUOUS, UNSAFE
# jetty.httpConfig.uriCompliance=DEFAULT
## Cookie compliance mode for parsing request Cookie headers: RFC6265_STRICT, RFC6265, RFC6265_LEGACY, RFC2965, RFC2965_LEGACY
# jetty.httpConfig.requestCookieCompliance=RFC6265
## Cookie compliance mode for generating response Set-Cookie: RFC2965, RFC6265
# jetty.httpConfig.responseCookieCompliance=RFC6265
### Server configuration
## Whether ctrl+c on the console gracefully stops the Jetty server
# jetty.server.stopAtShutdown=true
## Timeout in ms to apply when stopping the server gracefully
# jetty.server.stopTimeout=5000
## Dump the state of the Jetty server, components, and webapps after startup
# jetty.server.dumpAfterStart=false
## The temporary directory used by the Jetty server and as a root for its contexts
# jetty.server.tempDirectory=
## Dump the state of the Jetty server, components, and webapps before shutdown
# jetty.server.dumpBeforeStop=false
### Server Scheduler Configuration
## The scheduler thread name, defaults to "Scheduler-{hashCode()}" if blank.
# jetty.scheduler.name=
## Whether the server scheduler threads are daemon.
# jetty.scheduler.daemon=false
## The number of server scheduler threads.
# jetty.scheduler.threads=1
## Whether the handlers of the ContextHandlerCollection can be updated once the server is started
## If set to false, then eeN-deploy module jetty.deploy.scanInterval should also be set to 0.
# jetty.server.contexts.dynamic=true
## Should the DefaultHandler serve the jetty favicon.ico from the root.
# jetty.server.default.serveFavIcon=true
## Should the DefaultHandler show a list of known contexts in a root 404 response.
# jetty.server.default.showContexts=true

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Servlets -->
<!-- Servlet for injected frontend actions -->
<servlet>
<servlet-name>registry</servlet-name>
<servlet-class>google.registry.module.RegistryServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- The Nomulus registry servlet. -->
<servlet-mapping>
<servlet-name>registry</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

View file

@ -45,4 +45,5 @@ include 'services:backend'
include 'services:bsa'
include 'services:tools'
include 'services:pubapi'
include "console-webapp"
include 'console-webapp'
include 'jetty'