diff --git a/java/google/registry/tools/AppEngineConnection.java b/java/google/registry/tools/AppEngineConnection.java index 6b4adde3c..a27f0170f 100644 --- a/java/google/registry/tools/AppEngineConnection.java +++ b/java/google/registry/tools/AppEngineConnection.java @@ -15,51 +15,46 @@ package google.registry.tools; import static com.google.common.base.Suppliers.memoize; -import static com.google.common.net.HttpHeaders.CONTENT_TYPE; import static com.google.common.net.HttpHeaders.X_REQUESTED_WITH; import static com.google.common.net.MediaType.JSON_UTF_8; import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX; import static google.registry.security.XsrfTokenManager.X_CSRF_TOKEN; import static java.nio.charset.StandardCharsets.UTF_8; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.Parameters; -import com.google.common.base.Function; -import com.google.common.base.Joiner; +import com.google.api.client.http.ByteArrayContent; +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpHeaders; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpResponse; +import com.google.api.client.http.HttpUnsuccessfulResponseHandler; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; import com.google.common.io.CharStreams; import com.google.common.net.HostAndPort; import com.google.common.net.MediaType; import com.google.re2j.Matcher; import com.google.re2j.Pattern; -import google.registry.config.RegistryEnvironment; import google.registry.security.XsrfTokenManager; import google.registry.tools.ServerSideCommand.Connection; import java.io.IOException; import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; import java.util.Map; -import java.util.Map.Entry; +import javax.inject.Inject; import org.json.simple.JSONValue; /** An http connection to the appengine server. */ -@Parameters(separators = " =") class AppEngineConnection implements Connection { /** Pattern to heuristically extract title tag contents in HTML responses. */ private static final Pattern HTML_TITLE_TAG_PATTERN = Pattern.compile("
This is broken out into its own class to make it cleaner to extract these from the dagger + * module, where these values are injected. + */ +@Parameters(separators = " =") +class AppEngineConnectionFlags { + + @Parameter(names = "--server", description = "HOST[:PORT] to which remote commands are sent.") + private static HostAndPort server = RegistryEnvironment.get().config().getServer(); + + HostAndPort getServer() { + return server; + } +} + diff --git a/java/google/registry/tools/AppEngineConnectionFlagsModule.java b/java/google/registry/tools/AppEngineConnectionFlagsModule.java new file mode 100644 index 000000000..ac1eea807 --- /dev/null +++ b/java/google/registry/tools/AppEngineConnectionFlagsModule.java @@ -0,0 +1,36 @@ +// Copyright 2016 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.tools; + +import com.google.common.net.HostAndPort; +import dagger.Module; +import dagger.Provides; + +/** + * Dagger module to provide communication flags for talking to App Engine. + */ +@Module +public final class AppEngineConnectionFlagsModule { + private final AppEngineConnectionFlags flags; + + AppEngineConnectionFlagsModule(AppEngineConnectionFlags flags) { + this.flags = flags; + } + + @Provides + HostAndPort provideServer() { + return flags.getServer(); + } +} diff --git a/java/google/registry/tools/BasicHttpRequestFactoryComponent.java b/java/google/registry/tools/BasicHttpRequestFactoryComponent.java new file mode 100644 index 000000000..1b96d2182 --- /dev/null +++ b/java/google/registry/tools/BasicHttpRequestFactoryComponent.java @@ -0,0 +1,29 @@ +// Copyright 2016 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.tools; + +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; + +/** Creates a request factory for dealing with normal HTTP requests. */ +class BasicHttpRequestFactoryComponent implements HttpRequestFactoryComponent { + private final HttpTransport transport = new NetHttpTransport(); + + @Override + public HttpRequestFactory httpRequestFactory() { + return transport.createRequestFactory(); + } +} diff --git a/java/google/registry/tools/HttpRequestFactoryComponent.java b/java/google/registry/tools/HttpRequestFactoryComponent.java new file mode 100644 index 000000000..3e5b5003e --- /dev/null +++ b/java/google/registry/tools/HttpRequestFactoryComponent.java @@ -0,0 +1,28 @@ +// Copyright 2016 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.tools; + +import com.google.api.client.http.HttpRequestFactory; + +/** + * This is a Dagger component interface for providing request factories. + * + *
It is not annotated as a component because it's just an interface used as a dependency in + * other components. We provide our own concrete implementations of this for creating specific + * connection types. + */ +interface HttpRequestFactoryComponent { + public HttpRequestFactory httpRequestFactory(); +} diff --git a/java/google/registry/tools/LocalhostRequestFactoryComponent.java b/java/google/registry/tools/LocalhostRequestFactoryComponent.java new file mode 100644 index 000000000..d660b05b2 --- /dev/null +++ b/java/google/registry/tools/LocalhostRequestFactoryComponent.java @@ -0,0 +1,46 @@ +// Copyright 2016 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.tools; + +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.javanet.NetHttpTransport; + +/** + * Request factory for dealing with a "localhost" connection. + * + *
Localhost connections go to the App Engine dev server. The dev server differs from most HTTP + * connections in that they don't require OAuth2 credentials, but instead require a special cookie. + * + *
This is an immplementation of HttpRequestFactoryComponent which can be a component dependency + * in a Dagger graph used for providing a request factory. + */ +class LocalhostRequestFactoryComponent implements HttpRequestFactoryComponent { + @Override + public HttpRequestFactory httpRequestFactory() { + return new NetHttpTransport() + .createRequestFactory( + new HttpRequestInitializer() { + @Override + public void initialize(HttpRequest request) { + request + .getHeaders() + .setCookie("dev_appserver_login=test@example.com:true:1858047912411"); + } + }); + } +} + diff --git a/java/google/registry/tools/RegistryCli.java b/java/google/registry/tools/RegistryCli.java index 392a503f8..59273dbfc 100644 --- a/java/google/registry/tools/RegistryCli.java +++ b/java/google/registry/tools/RegistryCli.java @@ -49,7 +49,9 @@ final class RegistryCli { // Do not make this final - compile-time constant inlining may interfere with JCommander. @ParametersDelegate - private AppEngineConnection connection = new AppEngineConnection(); + private AppEngineConnectionFlags appEngineConnectionFlags = + new AppEngineConnectionFlags(); + // Do not make this final - compile-time constant inlining may interfere with JCommander. @ParametersDelegate @@ -115,13 +117,29 @@ final class RegistryCli { return; } loggingParams.configureLogging(); // Must be called after parameters are parsed. - injectReflectively(RegistryToolComponent.class, DaggerRegistryToolComponent.create(), command); + + // Decide which HTTP connection to use for App Engine + HttpRequestFactoryComponent requestFactoryComponent; + if (appEngineConnectionFlags.getServer().getHostText().equals("localhost")) { + requestFactoryComponent = new LocalhostRequestFactoryComponent(); + } else { + requestFactoryComponent = new BasicHttpRequestFactoryComponent(); + } + + // Create the main component and use it to inject the command class. + RegistryToolComponent component = DaggerRegistryToolComponent.builder() + .httpRequestFactoryComponent(requestFactoryComponent) + .appEngineConnectionFlagsModule( + new AppEngineConnectionFlagsModule(appEngineConnectionFlags)) + .build(); + injectReflectively(RegistryToolComponent.class, component, command); if (!(command instanceof RemoteApiCommand)) { command.run(); return; } + AppEngineConnection connection = component.appEngineConnection(); if (command instanceof ServerSideCommand) { ((ServerSideCommand) command).setConnection(connection); } diff --git a/java/google/registry/tools/RegistryToolComponent.java b/java/google/registry/tools/RegistryToolComponent.java index 13d62a4da..f82c6761c 100644 --- a/java/google/registry/tools/RegistryToolComponent.java +++ b/java/google/registry/tools/RegistryToolComponent.java @@ -26,6 +26,7 @@ import google.registry.request.Modules.Jackson2Module; import google.registry.request.Modules.URLFetchServiceModule; import google.registry.util.SystemClock.SystemClockModule; import google.registry.util.SystemSleeper.SystemSleeperModule; +import javax.inject.Singleton; /** * Dagger component for Registry Tool. @@ -33,8 +34,10 @@ import google.registry.util.SystemSleeper.SystemSleeperModule; *
Any command class with {@code @Inject} fields must be listed as a method here. * Otherwise {@link RegistryCli} will not be able to populate those fields after its instantiation. */ +@Singleton @Component( modules = { + AppEngineConnectionFlagsModule.class, ConfigModule.class, DatastoreServiceModule.class, CloudDnsWriterModule.class, @@ -47,6 +50,9 @@ import google.registry.util.SystemSleeper.SystemSleeperModule; SystemSleeperModule.class, URLFetchServiceModule.class, VoidDnsWriterModule.class, + }, + dependencies = { + HttpRequestFactoryComponent.class, } ) interface RegistryToolComponent { @@ -68,4 +74,6 @@ interface RegistryToolComponent { void inject(UpdateTldCommand command); void inject(ValidateEscrowDepositCommand command); void inject(WhoisQueryCommand command); + + AppEngineConnection appEngineConnection(); }