Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retries registry call with HTTP if HTTPS fails. #407

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
import com.google.cloud.tools.jib.json.JsonTemplateMapper;
import com.google.cloud.tools.jib.registry.json.ErrorEntryTemplate;
import com.google.cloud.tools.jib.registry.json.ErrorResponseTemplate;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.function.Function;
import javax.annotation.Nullable;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.apache.http.NoHttpResponseException;
import org.apache.http.conn.HttpHostConnectException;

/**
* Makes requests to a registry endpoint.
Expand All @@ -50,15 +53,29 @@ private static class RequestState {

/**
* @param authorization authentication credentials
* @param url the endpoint URL to call, or {@code null} to use default from {@code
* registryEndpointProvider}
* @param url the endpoint URL to call
*/
private RequestState(@Nullable Authorization authorization, URL url) {
this.authorization = authorization;
this.url = url;
}
}

/**
* Converts the {@link URL}'s protocol to HTTP.
*
* @param url the URL to conver to HTTP
* @return the URL with protocol set to HTTP
*/
private static URL urlWithHttp(URL url) {
GenericUrl httpUrl = new GenericUrl(url);
httpUrl.setScheme("http");
return httpUrl.toURL();
}

/** Makes a {@link Connection} to the specified {@link URL}. */
private final Function<URL, Connection> connectionFactory;

private final RequestState initialRequestState;
private final String userAgent;
private final RegistryEndpointProvider<T> registryEndpointProvider;
Expand All @@ -81,13 +98,32 @@ private RequestState(@Nullable Authorization authorization, URL url) {
@Nullable Authorization authorization,
RegistryEndpointProperties registryEndpointProperties)
throws MalformedURLException {
this(
userAgent,
apiRouteBase,
registryEndpointProvider,
authorization,
registryEndpointProperties,
Connection::new);
}

@VisibleForTesting
RegistryEndpointCaller(
String userAgent,
String apiRouteBase,
RegistryEndpointProvider<T> registryEndpointProvider,
@Nullable Authorization authorization,
RegistryEndpointProperties registryEndpointProperties,
Function<URL, Connection> connectionFactory)
throws MalformedURLException {
this.initialRequestState =
new RequestState(
authorization,
registryEndpointProvider.getApiRoute(DEFAULT_PROTOCOL + "://" + apiRouteBase));
this.userAgent = userAgent;
this.registryEndpointProvider = registryEndpointProvider;
this.registryEndpointProperties = registryEndpointProperties;
this.connectionFactory = connectionFactory;
}

/**
Expand All @@ -102,10 +138,18 @@ T call() throws IOException, RegistryException {
return call(initialRequestState);
}

/** Calls the registry endpoint with a certain {@link RequestState}. */
/**
* Calls the registry endpoint with a certain {@link RequestState}.
*
* @param requestState the state of the request - determines how to make the request and how to
* process the response
* @return an object representing the response, or {@code null}
* @throws IOException for most I/O exceptions when making the request
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be @link?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean like @throws IOException for most {@link IOException}s when making the request?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope. Please ignore. I shouldn't make review comments so early in the morning.

* @throws RegistryException for known exceptions when interacting with the registry
*/
@Nullable
private T call(RequestState requestState) throws IOException, RegistryException {
try (Connection connection = new Connection(requestState.url)) {
try (Connection connection = connectionFactory.apply(requestState.url)) {
Request request =
Request.builder()
.setAuthorization(requestState.authorization)
Expand Down Expand Up @@ -161,14 +205,16 @@ private T call(RequestState requestState) throws IOException, RegistryException
}
}

} catch (HttpHostConnectException | SSLPeerUnverifiedException ex) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this, but is it possible users might not want this insecure fallback mechanism? What if they always want to use https or fail?

Copy link
Contributor Author

@coollog coollog Jun 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yea it seems that we might want to have the user enable the fallback to HTTP with a configuration option, since Docker only seems to allow insecure registries with a flag.

https://docs.docker.com/registry/insecure/

// Tries to call with HTTP protocol if HTTPS failed to connect.
if ("https".equals(requestState.url.getProtocol())) {
return call(new RequestState(requestState.authorization, urlWithHttp(requestState.url)));
}

throw ex;

} catch (NoHttpResponseException ex) {
throw new RegistryNoResponseException(ex);

} catch (SSLPeerUnverifiedException ex) {
// Fall-back to HTTP
GenericUrl httpUrl = new GenericUrl(requestState.url);
httpUrl.setScheme("http");
return call(new RequestState(requestState.authorization, httpUrl.toURL()));
}
}
}
Loading