Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package au.net.causal.maven.plugins.boxdb.db;
import au.net.causal.maven.plugins.boxdb.db.DockerRegistry.ReadManifestResult.Type;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
public class DockerRegistry
{
private final URI registryUri;
private final CloseableHttpClient http;
private final JsonParser jsonParser = new JsonParser();
public DockerRegistry(URI registryUri)
{
this(registryUri, HttpClientBuilder.create().build());
}
public DockerRegistry(URI registryUri, CloseableHttpClient http)
{
Objects.requireNonNull(registryUri, "registryUri == null");
Objects.requireNonNull(http, "http == null");
this.registryUri = registryUri;
this.http = http;
}
/**
* Finds an image in the Docker registry and returns manifest information.
*
* @param imageName the name of the image in the repository.
* @param imageTagOrDigest the tag or digest of the image to find.
*
* @return the result, which may indicate the image was not found or details about the image if it was found.
*
* @throws IOException if an error occurs reading the manifest.
*/
public ReadManifestResult readManifest(String imageName, String imageTagOrDigest)
throws IOException
{
return readManifest(imageName, imageTagOrDigest, null);
}
private ReadManifestResult readManifest(String imageName, String imageTagOrDigest, String authToken)
throws IOException
{
Objects.requireNonNull(imageName, "repositoryName == null");
Objects.requireNonNull(imageTagOrDigest, "imageTagOrDigest == null");
HttpGet get = new HttpGet(registryUri.resolve(imageName + "/manifests/" + imageTagOrDigest));
get.setHeader(HttpHeaders.ACCEPT, "application/vnd.docker.distribution.manifest.v2+json");
if (authToken != null)
get.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + authToken);
try (CloseableHttpResponse response = http.execute(get))
{
if (authToken == null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED)
{
try
{
//Make a new request now with auth
authToken = attemptAuthorization(response, http);
return readManifest(imageName, imageTagOrDigest, authToken);
}
catch (URISyntaxException e)
{
throw new IOException("Error getting auth token for Docker registry readManifest: " + e, e);
}
}
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND)
return new ReadManifestResult(Type.NOT_FOUND);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine()
.getStatusCode() >= 300) //Non-200 response
throw new IOException("Bad response reading Docker manifest: " + response.getStatusLine());
//System.err.println(Arrays.toString(response.getAllHeaders()));
String imageId = parseImageIdFromManifestResponse(EntityUtils.toString(response.getEntity()));
Header dockerContentDigestHeader = response.getFirstHeader("Docker-Content-Digest");
String digest = (dockerContentDigestHeader == null ? null : dockerContentDigestHeader.getValue());
if (imageId == null)
return new ReadManifestResult(Type.OLD_MANIFEST, digest);
else
return new ReadManifestResult(Type.FOUND, digest, imageId);
}
}
public List readTags(String repositoryName)
throws IOException
{
return readTags(repositoryName, null);
}
private List readTags(String repositoryName, String authToken)
throws IOException
{
Objects.requireNonNull(repositoryName, "repositoryName == null");
HttpGet get = new HttpGet(registryUri.resolve(repositoryName + "/tags/list"));
if (authToken != null)
get.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + authToken);
try (CloseableHttpResponse response = http.execute(get))
{
if (authToken == null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED)
{
try
{
//Make a new request now with auth
authToken = attemptAuthorization(response, http);
return readTags(repositoryName, authToken);
}
catch (URISyntaxException e)
{
throw new IOException("Error getting auth token for Docker registry readTags: " + e, e);
}
}
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine()
.getStatusCode() >= 300) //Non-200 response
throw new IOException("Bad response reading Docker tags: " + response.getStatusLine());
return parseTagsFromResponse(EntityUtils.toString(response.getEntity()));
}
}
protected List parseTagsFromResponse(String responseString)
{
JsonElement responseJson = jsonParser.parse(responseString);
JsonArray tagsArray = responseJson.getAsJsonObject().getAsJsonArray("tags");
ImmutableList.Builder tagsBuilder = ImmutableList.builder();
for (JsonElement tagsElement : tagsArray)
{
tagsBuilder.add(tagsElement.getAsString());
}
return tagsBuilder.build();
}
protected String parseImageIdFromManifestResponse(String responseString)
throws IOException
{
JsonElement responseJson = jsonParser.parse(responseString);
JsonObject config = responseJson.getAsJsonObject().getAsJsonObject("config");
if (config == null)
return null;
JsonPrimitive digestPrim = config.getAsJsonPrimitive("digest");
if (digestPrim == null)
return null;
return digestPrim.getAsString();
}
private String attemptAuthorization(HttpResponse response, CloseableHttpClient http)
throws IOException, URISyntaxException
{
for (Header authHeader : response.getHeaders(HttpHeaders.WWW_AUTHENTICATE))
{
//Look for something like this:
//Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="registry:catalog:*"
String authHeaderValue = authHeader.getValue();
if (authHeaderValue.startsWith("Bearer "))
{
URI realmUri = null;
List authParams = new ArrayList<>();
for (HeaderElement bearerParam : authHeader.getElements())
{
String paramName = bearerParam.getName();
if (paramName.startsWith("Bearer ")) //The first value has this prefixed so get rid of it
paramName = paramName.substring("Bearer ".length());
String paramValue = bearerParam.getValue();
if ("realm".equals(paramName))
realmUri = new URI(paramValue);
else
authParams.add(new BasicNameValuePair(bearerParam.getName(), bearerParam.getValue()));
}
if (realmUri == null)
throw new IOException("Failed to parse realm from bearer: " + authHeader);
URIBuilder authUriBuilder = new URIBuilder(realmUri);
authUriBuilder.addParameters(authParams);
HttpGet authRequest = new HttpGet();
authRequest.setURI(authUriBuilder.build());
try (CloseableHttpResponse authResponse = http.execute(authRequest))
{
if (authResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
throw new IOException(
"HTTP error " + authResponse.getStatusLine() + " getting auth for Docker registry");
//Parse the JSON response
JsonElement responseJson = jsonParser.parse(EntityUtils.toString(authResponse.getEntity()));
return responseJson.getAsJsonObject().getAsJsonPrimitive("token").getAsString();
}
}
}
//If we get here we couldn't understand the auth request so bail out
throw new IOException("Found no understandable auth requests for Docker registry");
}
public static class ReadManifestResult
{
private final Type type;
private final String digest;
private final String imageId;
public ReadManifestResult(Type type, String digest, String imageId)
{
Objects.requireNonNull(type, "type == null");
this.type = type;
this.digest = digest;
this.imageId = imageId;
}
public ReadManifestResult(Type type, String digest)
{
this(type, digest, null);
}
public ReadManifestResult(Type type)
{
this(type, null, null);
}
/**
* @return type of response, indicating whether the manifest was found and what type of manifest it is. The
* manifest type indicates whether an image ID is available for comparison with the local registry.
*/
public Type getType()
{
return type;
}
/**
* @return the digest of the manifest. Not the same as the image hash but may be used for comparison with the
* local repository. Digest should be available both for old and new manifests. Prefixed by the algorithm,
* e.g. 'sha256:'.
*/
public String getDigest()
{
return digest;
}
/**
* @return the image hash, or null if none exists. This may be compared to the image ID of the image in the
* local repository. Prefixed by the algorithm, e.g. 'sha256:'.
*/
public String getImageId()
{
return imageId;
}
@Override
public String toString()
{
return new StringJoiner(", ", ReadManifestResult.class.getSimpleName() + "[", "]")
.add("type=" + type)
.add("digest=" + digest)
.add("imageId=" + imageId)
.toString();
}
public static enum Type
{
/**
* Manifest was found and was of an appropriate version, image hash will be available.
*/
FOUND,
/**
* Manifest not found, indicating no image with the specified name exists remotely.
*/
NOT_FOUND,
/**
* Manifest was found but was an old version so the image hash is unavailable. Old manifests are typically
* served for very old Docker images.
*/
OLD_MANIFEST;
}
}
}