@Override public void deleteItem(final ProxyRepository repository, final ResourceStoreRequest request) throws ItemNotFoundException, UnsupportedStorageOperationException, RemoteStorageException { final URL remoteUrl = appendQueryString(repository, request, getAbsoluteUrlFromBase(repository, request)); final HttpDelete method = new HttpDelete(remoteUrl.toExternalForm()); final HttpResponse httpResponse = executeRequestAndRelease(repository, request, method, repository.getRemoteUrl()); final int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT && statusCode != HttpStatus.SC_ACCEPTED) { throw new RemoteStorageException( "The response to HTTP " + method.getMethod() + " was unexpected HTTP Code " + statusCode + " : " + httpResponse.getStatusLine().getReasonPhrase() + " [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteUrl.toString() + "\"]"); } }
@Override public void storeItem(final ProxyRepository repository, final StorageItem item) throws UnsupportedStorageOperationException, RemoteStorageException { if (!(item instanceof StorageFileItem)) { throw new UnsupportedStorageOperationException( "Storing of non-files remotely is not supported!"); } final StorageFileItem fileItem = (StorageFileItem) item; final ResourceStoreRequest request = new ResourceStoreRequest(item); final URL remoteUrl = appendQueryString(getAbsoluteUrlFromBase(repository, request), repository); final HttpPut method = new HttpPut(remoteUrl.toExternalForm()); final InputStreamEntity entity; try { entity = new InputStreamEntity(fileItem.getInputStream(), fileItem.getLength()); } catch (IOException e) { throw new RemoteStorageException( e.getMessage() + " [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteUrl.toString() + "\"]", e); } entity.setContentType(fileItem.getMimeType()); method.setEntity(entity); final HttpResponse httpResponse = executeRequestAndRelease(repository, request, method); final int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED && statusCode != HttpStatus.SC_NO_CONTENT && statusCode != HttpStatus.SC_ACCEPTED) { throw new RemoteStorageException( "Unexpected response code while executing " + method.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteUrl.toString() + "\"]. Expected: \"any success (2xx)\". Received: " + statusCode + " : " + httpResponse.getStatusLine().getReasonPhrase()); } }
@Override public void doApplyConfiguration( Repository repository, ApplicationConfiguration configuration, CRepositoryCoreConfiguration coreConfiguration) throws ConfigurationException { super.doApplyConfiguration(repository, configuration, coreConfiguration); if (repository.getRepositoryKind().isFacetAvailable(ProxyRepository.class)) { ProxyRepository proxy = repository.adaptToFacet(ProxyRepository.class); proxy.getItemContentValidators().put("checksum", checksumValidator); proxy.getItemContentValidators().put("filetypevalidator", fileTypeItemContentValidator); } }
@Override protected void updateContext(final ProxyRepository repository, final RemoteStorageContext ctx) { getLogger() .info( "Remote storage settings change detected for ProxyRepository ID=\"" + repository.getId() + "\" (\"" + repository.getName() + "\"), updating HttpClient..."); // reset current http client, if exists HttpClientUtil.release(CTX_KEY, ctx); // and create a new one HttpClientUtil.configure(CTX_KEY, ctx, getLogger()); }
/** * Executes the HTTP request. * * <p>In case of any exception thrown by HttpClient, it will release the connection. In other * cases it is the duty of caller to do it, or process the input stream. * * @param repository to execute the HTTP method for * @param request resource store request that triggered the HTTP request * @param httpRequest HTTP request to be executed * @param baseUrl The BaseURL used to construct final httpRequest * @return response of making the request * @throws RemoteStorageException If an error occurred during execution of HTTP request */ @VisibleForTesting HttpResponse executeRequest( final ProxyRepository repository, final ResourceStoreRequest request, final HttpUriRequest httpRequest, final String baseUrl, final boolean contentRequest) throws RemoteStorageException { final Timer timer = timer(repository, httpRequest, baseUrl); final TimerContext timerContext = timer.time(); Stopwatch stopwatch = null; if (outboundRequestLog.isDebugEnabled()) { stopwatch = new Stopwatch().start(); } try { return doExecuteRequest(repository, request, httpRequest, contentRequest); } finally { timerContext.stop(); if (stopwatch != null) { outboundRequestLog.debug( "[{}] {} {} - {}", repository.getId(), httpRequest.getMethod(), httpRequest.getURI(), stopwatch); } } }
protected void validateResponse( final ProxyRepository repository, final ResourceStoreRequest request, final String method, final String remoteUrl, final Response response, int... expectedCodes) throws ItemNotFoundException, RemoteStorageException { // maintain the S3 flag checkForRemotePeerAmazonS3Storage(repository, response.getHeader("server")); if (response.isRedirected()) { getLogger() .info( String.format( "Proxy repository %s (id=%s) got redirected from %s, please verify your remoteUrl is up-to-date!", repository.getName(), repository.getId(), remoteUrl)); } if (AHCUtils.isAnyOfTheseStatusCodes(response, expectedCodes)) { // good, an expected one return; } // 404 NotFound if (404 == response.getStatusCode()) { throw new ItemNotFoundException(request, repository); } // 401 Unauthorized if (401 == response.getStatusCode()) { throw new RemoteAuthenticationNeededException( repository, remoteUrl, response.getStatusText()); } // 403 Forbidden if (403 == response.getStatusCode()) { throw new RemoteAccessDeniedException(repository, remoteUrl, response.getStatusText()); } // anything else "unexpected"? throw new RemoteStorageException( String.format( "Coult not perform %s against Url %s, unexpected response is %s", method, remoteUrl, response.getStatusText())); }
protected AsyncHttpClient getHttpClient(final ProxyRepository proxyRepository) { final AsyncHttpClientConfig.Builder clientConfigBuilder = ahcProvider.getAsyncHttpClientConfigBuilder( proxyRepository, proxyRepository.getRemoteStorageContext()); clientConfigBuilder.setFollowRedirects(true); clientConfigBuilder.setMaximumNumberOfRedirects(3); clientConfigBuilder.setMaxRequestRetry(2); final AsyncHttpClient client = new AsyncHttpClient(clientConfigBuilder.build()); return client; }
@Before public void setup() { this.underTest = new DefaultUserAgentBuilder(statusSource, contributors); when(statusSource.getSystemStatus()).thenReturn(status); when(status.getVersion()).thenReturn("2.1-FAKE"); when(status.getEditionShort()).thenReturn("FAKENEXUS"); when(ctx.getRemoteConnectionSettings()).thenReturn(settings); when(settings.getUserAgentCustomizationString()).thenReturn("SETTINGS_CUSTOMIZATION"); when(repository.getRemoteStorage()).thenReturn(storage); when(storage.getProviderId()).thenReturn("RRS_PROVIDER"); when(storage.getVersion()).thenReturn("RRS_VERSION"); when(contributor.getUserAgent(ctx, repository)).thenReturn("PLUGIN_CONTRIBUTED"); }
// CLEAN public String getRestRepoRemoteStatus( ProxyRepository repository, Request request, Response response) throws ResourceException { Form form = request.getResourceRef().getQueryAsForm(); boolean forceCheck = form.getFirst("forceCheck") != null; RemoteStatus rs = repository.getRemoteStatus( new ResourceStoreRequest(RepositoryItemUid.PATH_ROOT), forceCheck); if (RemoteStatus.UNKNOWN.equals(rs)) { // set status to ACCEPTED, since we have incomplete info response.setStatus(Status.SUCCESS_ACCEPTED); } return rs == null ? null : rs.toString(); }
@Override protected boolean checkRemoteAvailability( long newerThen, ProxyRepository repository, ResourceStoreRequest request, boolean isStrict) throws RemoteStorageException { final URL remoteURL = getAbsoluteUrlFromBase(repository, request); final String itemUrl = remoteURL.toString(); final AsyncHttpClient client = getClient(repository); if (getLogger().isDebugEnabled()) { getLogger() .debug( String.format( "Checking remote availability of proxy repository \"%s\" (id=%s) on URL %s", repository.getName(), repository.getId(), itemUrl)); } // artifactory hack, it pukes on HEAD so we will try with GET if HEAD fails boolean doGet = false; Response responseObject = null; int response = 400; try { responseObject = client.prepareHead(itemUrl).execute().get(); response = responseObject.getStatusCode(); validateResponse(repository, request, "HEAD", itemUrl, responseObject, 200); } catch (ItemNotFoundException e) { return false; } catch (RemoteStorageException e) { // If HEAD failed, attempt a GET. Some repos may not support HEAD method doGet = true; getLogger().debug("HEAD method failed, will attempt GET. Exception: " + e.getMessage(), e); } catch (Exception e) { throw new RemoteStorageException(e); } finally { // HEAD returned error, but not exception, try GET before failing if (!doGet && response != 200) { // try with GET unless some known to fail responses are in doGet = (response != 401) && (response != 403); getLogger().debug("HEAD method failed, will attempt GET. Status: " + response); } } if (doGet) { try { responseObject = client.prepareGet(itemUrl).execute().get(); response = responseObject.getStatusCode(); validateResponse(repository, request, "GET", itemUrl, responseObject, 200); } catch (ItemNotFoundException e) { return false; } catch (Exception e) { throw new RemoteStorageException(e); } } // if we are not strict and remote is S3 if (!isStrict && isRemotePeerAmazonS3Storage(repository)) { // if we are relaxed, we will accept any HTTP response code below 500. This means anyway the // HTTP // transaction succeeded. This method was never really detecting that the remoteUrl really // denotes a root of // repository (how could we do that?) // this "relaxed" check will help us to "pass" S3 remote storage. return response >= 200 && response < 500; } else { // non relaxed check is strict, and will select only the OK response if (response == 200) { // we have it // we have newer if this below is true return AHCUtils.getLastModified(responseObject, System.currentTimeMillis()) > newerThen; } else if ((response >= 300 && response < 400) || response == 404) { return false; } else { throw new RemoteStorageException( "Unexpected response code while executing GET" + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + itemUrl + "\"]. Expected: \"SUCCESS (200)\". Received: " + response + " : " + responseObject.getStatusText()); } } }
/** * Executes the HTTP request. * * <p>In case of any exception thrown by HttpClient, it will release the connection. In other * cases it is the duty of caller to do it, or process the input stream. * * @param repository to execute the HTTP method fpr * @param request resource store request that triggered the HTTP request * @param httpRequest HTTP request to be executed * @return response of making the request * @throws RemoteStorageException If an error occurred during execution of HTTP request */ private HttpResponse executeRequest( final ProxyRepository repository, final ResourceStoreRequest request, final HttpUriRequest httpRequest) throws RemoteStorageException { final URI methodUri = httpRequest.getURI(); if (getLogger().isDebugEnabled()) { getLogger() .debug( "Invoking HTTP " + httpRequest.getMethod() + " method against remote location " + methodUri); } final RemoteStorageContext ctx = getRemoteStorageContext(repository); final HttpClient httpClient = HttpClientUtil.getHttpClient(CTX_KEY, ctx); httpRequest.setHeader("user-agent", formatUserAgentString(ctx, repository)); httpRequest.setHeader("accept", "*/*"); httpRequest.setHeader("accept-language", "en-us"); httpRequest.setHeader("accept-encoding", "gzip,deflate,identity"); httpRequest.setHeader("cache-control", "no-cache"); // HTTP keep alive should not be used, except when NTLM is used final Boolean isNtlmUsed = HttpClientUtil.isNTLMAuthenticationUsed(CTX_KEY, ctx); if (isNtlmUsed == null || !isNtlmUsed) { httpRequest.setHeader("Connection", "close"); httpRequest.setHeader("Proxy-Connection", "close"); } HttpResponse httpResponse = null; try { httpResponse = httpClient.execute(httpRequest); final int statusCode = httpResponse.getStatusLine().getStatusCode(); final Header httpServerHeader = httpResponse.getFirstHeader("server"); checkForRemotePeerAmazonS3Storage( repository, httpServerHeader == null ? null : httpServerHeader.getValue()); Header proxyReturnedErrorHeader = httpResponse.getFirstHeader(NEXUS_MISSING_ARTIFACT_HEADER); boolean proxyReturnedError = proxyReturnedErrorHeader != null && Boolean.valueOf(proxyReturnedErrorHeader.getValue()); if (statusCode == HttpStatus.SC_FORBIDDEN) { throw new RemoteAccessDeniedException( repository, methodUri.toASCIIString(), httpResponse.getStatusLine().getReasonPhrase()); } else if (statusCode == HttpStatus.SC_UNAUTHORIZED) { throw new RemoteAuthenticationNeededException( repository, httpResponse.getStatusLine().getReasonPhrase()); } else if (statusCode == HttpStatus.SC_OK && proxyReturnedError) { throw new RemoteStorageException( "Invalid artifact found, most likely a proxy redirected to an HTML error page."); } return httpResponse; } catch (RemoteStorageException ex) { release(httpResponse); throw ex; } catch (ClientProtocolException ex) { release(httpResponse); throw new RemoteStorageException( "Protocol error while executing " + httpRequest.getMethod() + " method. [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + methodUri.toASCIIString() + "\"]", ex); } catch (IOException ex) { release(httpResponse); throw new RemoteStorageException( "Transport error while executing " + httpRequest.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + methodUri.toASCIIString() + "\"]", ex); } }
/** @since 2.3 */ public String getQueryString(final ProxyRepository repository) { checkNotNull(repository); return getQueryString(repository.getRemoteStorageContext(), repository); }
@Override protected boolean checkRemoteAvailability( final long newerThen, final ProxyRepository repository, final ResourceStoreRequest request, final boolean isStrict) throws RemoteStorageException { final URL remoteUrl = appendQueryString(getAbsoluteUrlFromBase(repository, request), repository); HttpRequestBase method; HttpResponse httpResponse = null; int statusCode = HttpStatus.SC_BAD_REQUEST; // artifactory hack, it pukes on HEAD so we will try with GET if HEAD fails boolean doGet = false; { method = new HttpHead(remoteUrl.toExternalForm()); try { httpResponse = executeRequestAndRelease(repository, request, method); statusCode = httpResponse.getStatusLine().getStatusCode(); } catch (RemoteStorageException e) { // If HEAD failed, attempt a GET. Some repos may not support HEAD method doGet = true; getLogger().debug("HEAD method failed, will attempt GET. Exception: " + e.getMessage(), e); } finally { // HEAD returned error, but not exception, try GET before failing if (!doGet && statusCode != HttpStatus.SC_OK) { doGet = true; getLogger().debug("HEAD method failed, will attempt GET. Status: " + statusCode); } } } { if (doGet) { // create a GET method = new HttpGet(remoteUrl.toExternalForm()); // execute it httpResponse = executeRequestAndRelease(repository, request, method); statusCode = httpResponse.getStatusLine().getStatusCode(); } } // if we are not strict and remote is S3 if (!isStrict && isRemotePeerAmazonS3Storage(repository)) { // if we are relaxed, we will accept any HTTP response code below 500. This means anyway the // HTTP // transaction succeeded. This method was never really detecting that the remoteUrl really // denotes a root of // repository (how could we do that?) // this "relaxed" check will help us to "pass" S3 remote storage. return statusCode >= HttpStatus.SC_OK && statusCode <= HttpStatus.SC_INTERNAL_SERVER_ERROR; } else { // non relaxed check is strict, and will select only the OK response if (statusCode == HttpStatus.SC_OK) { // we have it // we have newer if this below is true return makeDateFromHeader(httpResponse.getFirstHeader("last-modified")) > newerThen; } else if ((statusCode >= HttpStatus.SC_MULTIPLE_CHOICES && statusCode < HttpStatus.SC_BAD_REQUEST) || statusCode == HttpStatus.SC_NOT_FOUND) { return false; } else { throw new RemoteStorageException( "Unexpected response code while executing " + method.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteUrl.toString() + "\"]. Expected: \"SUCCESS (200)\". Received: " + statusCode + " : " + httpResponse.getStatusLine().getReasonPhrase()); } } }
@Override public AbstractStorageItem retrieveItem( final ProxyRepository repository, final ResourceStoreRequest request, final String baseUrl) throws ItemNotFoundException, RemoteStorageException { final URL remoteURL = appendQueryString(getAbsoluteUrlFromBase(baseUrl, request.getRequestPath()), repository); final HttpGet method = new HttpGet(remoteURL.toExternalForm()); final HttpResponse httpResponse = executeRequest(repository, request, method); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { if (method.getURI().getPath().endsWith("/")) { // this is a collection and not a file! // httpClient will follow redirections, and the getPath() // _should_ // give us URL with ending "/" release(httpResponse); throw new ItemNotFoundException( "The remoteURL we got to looks like is a collection, and Nexus cannot fetch collections over plain HTTP (remoteUrl=\"" + remoteURL.toString() + "\")", request, repository); } InputStream is; try { is = httpResponse.getEntity().getContent(); String mimeType = EntityUtils.getContentMimeType(httpResponse.getEntity()); if (mimeType == null) { mimeType = getMimeSupport() .guessMimeTypeFromPath(repository.getMimeRulesSource(), request.getRequestPath()); } final DefaultStorageFileItem httpItem = new DefaultStorageFileItem( repository, request, CAN_READ, CAN_WRITE, new PreparedContentLocator(is, mimeType)); if (httpResponse.getEntity().getContentLength() != -1) { httpItem.setLength(httpResponse.getEntity().getContentLength()); } httpItem.setRemoteUrl(remoteURL.toString()); httpItem.setModified(makeDateFromHeader(httpResponse.getFirstHeader("last-modified"))); httpItem.setCreated(httpItem.getModified()); httpItem.getItemContext().putAll(request.getRequestContext()); return httpItem; } catch (IOException ex) { release(httpResponse); throw new RemoteStorageException( "IO Error during response stream handling [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteURL.toString() + "\"]!", ex); } catch (RuntimeException ex) { release(httpResponse); throw ex; } } else { release(httpResponse); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { throw new ItemNotFoundException( "The remoteURL we requested does not exists on remote server (remoteUrl=\"" + remoteURL.toString() + "\")", request, repository); } else { throw new RemoteStorageException( "The method execution returned result code " + httpResponse.getStatusLine().getStatusCode() + ". [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteURL.toString() + "\"]"); } } }
private HttpResponse doExecuteRequest( final ProxyRepository repository, final ResourceStoreRequest request, final HttpUriRequest httpRequest, final boolean contentRequest) throws RemoteStorageException { final URI methodUri = httpRequest.getURI(); if (log.isDebugEnabled()) { log.debug( "Invoking HTTP {} method against remote location {}", httpRequest.getMethod(), methodUri); } final RemoteStorageContext ctx = getRemoteStorageContext(repository); final HttpClient httpClient = (HttpClient) ctx.getContextObject(CTX_KEY_CLIENT); httpRequest.setHeader("Accept", "*/*"); httpRequest.setHeader("Accept-Language", "en-us"); httpRequest.setHeader("Accept-Encoding", "gzip,deflate,identity"); httpRequest.setHeader("Cache-Control", "no-cache"); HttpResponse httpResponse = null; try { final BasicHttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(Hc4Provider.HTTP_CTX_KEY_REPOSITORY, repository); if (contentRequest) { httpContext.setAttribute(CONTENT_RETRIEVAL_MARKER_KEY, Boolean.TRUE); } httpResponse = httpClient.execute(httpRequest, httpContext); final int statusCode = httpResponse.getStatusLine().getStatusCode(); final Header httpServerHeader = httpResponse.getFirstHeader("server"); checkForRemotePeerAmazonS3Storage( repository, httpServerHeader == null ? null : httpServerHeader.getValue()); Header proxyReturnedErrorHeader = httpResponse.getFirstHeader(NEXUS_MISSING_ARTIFACT_HEADER); boolean proxyReturnedError = proxyReturnedErrorHeader != null && Boolean.valueOf(proxyReturnedErrorHeader.getValue()); if (statusCode == HttpStatus.SC_FORBIDDEN) { throw new RemoteAccessDeniedException( repository, methodUri.toASCIIString(), httpResponse.getStatusLine().getReasonPhrase()); } else if (statusCode == HttpStatus.SC_UNAUTHORIZED) { throw new RemoteAuthenticationNeededException( repository, httpResponse.getStatusLine().getReasonPhrase()); } else if (statusCode == HttpStatus.SC_OK && proxyReturnedError) { throw new RemoteStorageException( "Invalid artifact found, most likely a proxy redirected to an HTML error page."); } return httpResponse; } catch (RemoteStorageException ex) { release(httpResponse); throw ex; } catch (ClientProtocolException ex) { release(httpResponse); throw new RemoteStorageException( "Protocol error while executing " + httpRequest.getMethod() + " method. [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + methodUri.toASCIIString() + "\"]", ex); } catch (ConnectionPoolTimeoutException ex) { release(httpResponse); throw new RemoteStorageTransportOverloadedException( repository, "Connection pool timeout error while executing " + httpRequest.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + methodUri.toASCIIString() + "\"]", ex); } catch (IOException ex) { release(httpResponse); throw new RemoteStorageException( "Transport error while executing " + httpRequest.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + methodUri.toASCIIString() + "\"]", ex); } }
/** Converting App model to REST DTO. */ public RepositoryProxyResource getRepositoryProxyRestModel(ProxyRepository repository) { RepositoryProxyResource resource = new RepositoryProxyResource(); resource.setRemoteStorage(new RepositoryResourceRemoteStorage()); resource.getRemoteStorage().setRemoteStorageUrl(repository.getRemoteUrl()); resource .getRemoteStorage() .setAuthentication( AbstractGlobalConfigurationPlexusResource.convert( NexusCompat.getRepositoryRawConfiguration(repository) .getRemoteStorage() .getAuthentication())); resource .getRemoteStorage() .setConnectionSettings( AbstractGlobalConfigurationPlexusResource.convert( NexusCompat.getRepositoryRawConfiguration(repository) .getRemoteStorage() .getConnectionSettings())); resource .getRemoteStorage() .setHttpProxySettings( AbstractGlobalConfigurationPlexusResource.convert( NexusCompat.getRepositoryRawConfiguration(repository) .getRemoteStorage() .getHttpProxySettings())); // set auto block resource.setAutoBlockActive(repository.isAutoBlockActive()); // set content validation resource.setFileTypeValidation(repository.isFileTypeValidation()); if (repository.getRepositoryKind().isFacetAvailable(MavenProxyRepository.class)) { resource.setArtifactMaxAge( repository.adaptToFacet(MavenProxyRepository.class).getArtifactMaxAge()); resource.setMetadataMaxAge( repository.adaptToFacet(MavenProxyRepository.class).getMetadataMaxAge()); resource.setItemMaxAge(repository.adaptToFacet(MavenProxyRepository.class).getItemMaxAge()); } else { // This is a total hack to be able to retrieve this data from a non core repo if available try { Method artifactMethod = repository.getClass().getMethod("getArtifactMaxAge", new Class<?>[0]); Method metadataMethod = repository.getClass().getMethod("getMetadataMaxAge", new Class<?>[0]); Method itemMethod = repository.getClass().getMethod("getItemMaxAge", new Class<?>[0]); if (artifactMethod != null) { resource.setArtifactMaxAge((Integer) artifactMethod.invoke(repository, new Object[0])); } if (metadataMethod != null) { resource.setMetadataMaxAge((Integer) metadataMethod.invoke(repository, new Object[0])); } if (itemMethod != null) { resource.setItemMaxAge((Integer) itemMethod.invoke(repository, new Object[0])); } } catch (Exception e) { // nothing to do here, doesn't support artifactmax age } } return resource; }
@Override protected boolean checkRemoteAvailability( final long newerThen, final ProxyRepository repository, final ResourceStoreRequest request, final boolean isStrict) throws RemoteStorageException { final URL remoteUrl = appendQueryString(repository, request, getAbsoluteUrlFromBase(repository, request)); HttpRequestBase method; HttpResponse httpResponse = null; int statusCode = HttpStatus.SC_BAD_REQUEST; // artifactory hack, it pukes on HEAD so we will try with GET if HEAD fails boolean doGet = false; { method = new HttpHead(remoteUrl.toExternalForm()); try { httpResponse = executeRequestAndRelease(repository, request, method, repository.getRemoteUrl()); statusCode = httpResponse.getStatusLine().getStatusCode(); } catch (RemoteStorageException e) { // If HEAD failed, attempt a GET. Some repos may not support HEAD method doGet = true; log.debug("HEAD method failed, will attempt GET. Exception: " + e.getMessage(), e); } finally { // HEAD returned error, but not exception, try GET before failing if (!doGet && statusCode != HttpStatus.SC_OK) { doGet = true; log.debug("HEAD method failed, will attempt GET. Status: " + statusCode); } } } { if (doGet) { // create a GET method = new HttpGet(remoteUrl.toExternalForm()); // execute it httpResponse = executeRequestAndRelease(repository, request, method, repository.getRemoteUrl()); statusCode = httpResponse.getStatusLine().getStatusCode(); } } // if we are not strict and remote is S3 if (!isStrict && isRemotePeerAmazonS3Storage(repository)) { // if we are relaxed, we will accept any HTTP response code below 500. This means anyway the // HTTP // transaction succeeded. This method was never really detecting that the remoteUrl really // denotes a root of // repository (how could we do that?) // this "relaxed" check will help us to "pass" S3 remote storage. return statusCode >= HttpStatus.SC_OK && statusCode <= HttpStatus.SC_INTERNAL_SERVER_ERROR; } else { // non relaxed check is strict, and will select only the OK response if (statusCode == HttpStatus.SC_OK) { // we have it // we have newer if this below is true return makeDateFromHeader(httpResponse.getFirstHeader("last-modified")) > newerThen; } else if ((statusCode >= HttpStatus.SC_MULTIPLE_CHOICES && statusCode < HttpStatus.SC_BAD_REQUEST) || statusCode == HttpStatus.SC_NOT_FOUND) { if (RepositoryItemUid.PATH_ROOT.equals(request.getRequestPath()) && statusCode == HttpStatus.SC_NOT_FOUND) { // NEXUS-5944: Give it a chance: it might be remote Nexus with browsing disabled? // to check that, we will check is remote is Nexus by pinging "well know" location // if we got it, we will know it's only browsing forbidden on remote final RemoteStorageContext ctx = getRemoteStorageContext(repository); final HttpClient httpClient = (HttpClient) ctx.getContextObject(CTX_KEY_CLIENT); final PageContext pageContext = new RepositoryPageContext(httpClient, repository); final ResourceStoreRequest rmRequest = new ResourceStoreRequest("/.meta/repository-metadata.xml"); final URL nxRepoMetadataUrl = appendQueryString( repository, rmRequest, getAbsoluteUrlFromBase(repository, rmRequest)); try { final Page page = Page.getPageFor(pageContext, nxRepoMetadataUrl.toExternalForm()); if (page.getStatusCode() == 200) { // this is a Nexus with browsing disabled. say OK log.debug( "Original GET request for URL {} failed with 404, but GET request for URL {} succeeded, we assume remote is a Nexus repository having browsing disabled.", remoteUrl, nxRepoMetadataUrl); return true; } } catch (IOException e) { // just fall trough } } return false; } else { throw new RemoteStorageException( "Unexpected response code while executing " + method.getMethod() + " method [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteUrl.toString() + "\"]. Expected: \"SUCCESS (200)\". Received: " + statusCode + " : " + httpResponse.getStatusLine().getReasonPhrase()); } } }
@Override public AbstractStorageItem retrieveItem( final ProxyRepository repository, final ResourceStoreRequest request, final String baseUrl) throws ItemNotFoundException, RemoteStorageException { final URL remoteURL = appendQueryString( repository, request, getAbsoluteUrlFromBase(baseUrl, request.getRequestPath())); final String url = remoteURL.toExternalForm(); if (remoteURL.getPath().endsWith("/")) { // NEXUS-5125 we do not want to fetch any collection // Even though it is unlikely that we actually see a request for a collection here, // requests for paths like this over the REST layer will be localOnly not trigger a remote // request. // // The usual case is that there is a request for a directory that is redirected to '/', see // below behavior // for SC_MOVED_* throw new RemoteItemNotFoundException( request, repository, "remoteIsCollection", remoteURL.toString()); } final HttpGet method = new HttpGet(url); final HttpResponse httpResponse = executeRequest(repository, request, method, baseUrl, true); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { InputStream is; try { is = new Hc4InputStream( repository, new InterruptableInputStream(method, httpResponse.getEntity().getContent())); String mimeType = ContentType.getOrDefault(httpResponse.getEntity()).getMimeType(); if (mimeType == null) { mimeType = getMimeSupport() .guessMimeTypeFromPath(repository.getMimeRulesSource(), request.getRequestPath()); } final long entityLength = httpResponse.getEntity().getContentLength(); final DefaultStorageFileItem httpItem = new DefaultStorageFileItem( repository, request, CAN_READ, CAN_WRITE, new PreparedContentLocator( is, mimeType, entityLength != -1 ? entityLength : ContentLocator.UNKNOWN_LENGTH)); httpItem.setRemoteUrl(remoteURL.toString()); httpItem.setModified(makeDateFromHeader(httpResponse.getFirstHeader("last-modified"))); httpItem.setCreated(httpItem.getModified()); return httpItem; } catch (IOException ex) { release(httpResponse); throw new RemoteStorageException( "IO Error during response stream handling [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteURL.toString() + "\"]!", ex); } catch (RuntimeException ex) { release(httpResponse); throw ex; } } else { release(httpResponse); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { throw new RemoteItemNotFoundException( request, repository, "NotFound", remoteURL.toString()); } else if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY || httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY) { // NEXUS-5125 unfollowed redirect means collection (path.endsWith("/")) // see also HttpClientUtil#configure throw new RemoteItemNotFoundException( request, repository, "redirected", remoteURL.toString()); } else { throw new RemoteStorageException( "The method execution returned result code " + httpResponse.getStatusLine().getStatusCode() + " (expected 200). [repositoryId=\"" + repository.getId() + "\", requestPath=\"" + request.getRequestPath() + "\", remoteUrl=\"" + remoteURL.toString() + "\"]"); } } }