From 3ba4a408fd9613ec849aebb3b7a1aff0bcb866d9 Mon Sep 17 00:00:00 2001 From: gulnaz Date: Thu, 28 Nov 2024 12:42:58 +0300 Subject: [PATCH] SUPPORT-8662: use synchronous request-reply; fix file manager --- micord.env | 3 + .../ervu/av/response/AvFileSendResponse.java | 11 --- .../micord/ervu/av/service/FileManager.java | 32 ++++++- .../service/ReceiveScanReportRetryable.java | 91 +++---------------- src/main/resources/application.properties | 2 + 5 files changed, 48 insertions(+), 91 deletions(-) delete mode 100644 src/main/java/ru/micord/ervu/av/response/AvFileSendResponse.java diff --git a/micord.env b/micord.env index 25b4ae4..a0d39b4 100644 --- a/micord.env +++ b/micord.env @@ -30,3 +30,6 @@ S3_ACCESS_KEY=rlTdTvkmSXu9FsLhfecw S3_SECRET_KEY=NUmY0wwRIEyAd98GCKd1cOgJWvLQYAcMMul5Ulu0 S3_BUCKET_NAME=default-out-bucket S3_PATH_STYLE_ACCESS_ENABLED=true + +WEBDAV_USERNAME=test +WEBDAV_PASSWORD=test diff --git a/src/main/java/ru/micord/ervu/av/response/AvFileSendResponse.java b/src/main/java/ru/micord/ervu/av/response/AvFileSendResponse.java deleted file mode 100644 index ea8dd00..0000000 --- a/src/main/java/ru/micord/ervu/av/response/AvFileSendResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.micord.ervu.av.response; - -/** - * @author r.latypov - */ -public record AvFileSendResponse(String id, String location, Error error, String status) { - public static final String STATUS_ERROR = "error"; - - public record Error(String code, String message) { - } -} diff --git a/src/main/java/ru/micord/ervu/av/service/FileManager.java b/src/main/java/ru/micord/ervu/av/service/FileManager.java index 4b52afe..044cd58 100644 --- a/src/main/java/ru/micord/ervu/av/service/FileManager.java +++ b/src/main/java/ru/micord/ervu/av/service/FileManager.java @@ -6,12 +6,17 @@ import java.io.IOException; import java.nio.file.Path; import org.apache.http.HttpEntity; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.HttpHostConnectException; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.HttpClientBuilder; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; @@ -20,12 +25,19 @@ import ru.micord.ervu.av.exception.FileUploadException; import ru.micord.ervu.av.exception.InvalidHttpFileUrlException; import ru.micord.ervu.av.exception.RetryableException; +import static org.springframework.util.StringUtils.hasText; + /** * @author gulnaz */ @Component public class FileManager { + @Value("${webdav.username}") + private String username; + @Value("${webdav.password}") + private String password; + @Retryable(retryFor = {InvalidHttpFileUrlException.class}, maxAttemptsExpression = "${av.retry.max.attempts.count}", backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}")) @@ -34,7 +46,7 @@ public class FileManager { File file = filePath.toFile(); HttpGet request = new HttpGet(fileUrl); - try (CloseableHttpClient client = HttpClients.createDefault(); + try (CloseableHttpClient client = getClientBuilder().build(); CloseableHttpResponse response = client.execute(request)) { int statusCode = response.getStatusLine().getStatusCode(); @@ -67,7 +79,7 @@ public class FileManager { maxAttemptsExpression = "${av.retry.max.attempts.count}", backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}")) public void deleteFile(String fileUrl) throws FileUploadException { - try (CloseableHttpClient client = HttpClients.createDefault()) { + try (CloseableHttpClient client = getClientBuilder().build()) { HttpDelete delete = new HttpDelete(fileUrl); try (CloseableHttpResponse response = client.execute(delete)) { @@ -83,4 +95,18 @@ public class FileManager { throw new FileUploadException(e); } } + + private HttpClientBuilder getClientBuilder() { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + + if (hasText(username) && hasText(password)) { + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(username, password) + ); + httpClientBuilder.setDefaultCredentialsProvider(provider); + } + return httpClientBuilder; + } } diff --git a/src/main/java/ru/micord/ervu/av/service/ReceiveScanReportRetryable.java b/src/main/java/ru/micord/ervu/av/service/ReceiveScanReportRetryable.java index 1b4fbc4..679b05a 100644 --- a/src/main/java/ru/micord/ervu/av/service/ReceiveScanReportRetryable.java +++ b/src/main/java/ru/micord/ervu/av/service/ReceiveScanReportRetryable.java @@ -2,16 +2,16 @@ package ru.micord.ervu.av.service; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.file.Path; -import java.util.concurrent.TimeUnit; import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.CloseableHttpClient; @@ -24,7 +24,6 @@ import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import ru.micord.ervu.av.exception.FileUploadException; import ru.micord.ervu.av.exception.RetryableException; -import ru.micord.ervu.av.response.AvFileSendResponse; import ru.micord.ervu.av.response.AvResponse; /** @@ -35,8 +34,6 @@ public class ReceiveScanReportRetryable { @Value("${av.rest.address}") private String avRestAddress; - @Value("${av.first.timeout.milliseconds:1000}") - private Long avFirstTimeoutMilliseconds; @Retryable(retryFor = {RetryableException.class}, maxAttemptsExpression = "${av.retry.max.attempts.count}", @@ -45,7 +42,10 @@ public class ReceiveScanReportRetryable { File file = filePath.toFile(); try (CloseableHttpClient client = HttpClients.createDefault()) { - HttpPost post = new HttpPost(avRestAddress); + URI uri = new URIBuilder(avRestAddress) + .addParameter("wait", "1") + .build(); + HttpPost post = new HttpPost(uri); HttpEntity entity = MultipartEntityBuilder.create() .addPart("file", new FileBody(file)) .build(); @@ -54,84 +54,21 @@ public class ReceiveScanReportRetryable { try (CloseableHttpResponse postResponse = client.execute(post)) { int postStatusCode = postResponse.getStatusLine().getStatusCode(); String postResponseJson = EntityUtils.toString(postResponse.getEntity()); - AvFileSendResponse avFileSendResponse; - try { - avFileSendResponse = new Gson().fromJson(postResponseJson, AvFileSendResponse.class); + if (postStatusCode == HttpStatus.OK.value()) { + return new Gson().fromJson(postResponseJson, AvResponse.class); } - catch (JsonSyntaxException e) { - throw new FileUploadException("error json: " + postResponseJson, e); + else { + throw new FileUploadException( + "http status code " + postStatusCode + " for " + post.getURI() + + " get request."); } - - if (postStatusCode != HttpStatus.CREATED.value()) { - StringBuilder stringBuilder = new StringBuilder( - "http status code " + postStatusCode + " for " + avRestAddress + " post request."); - String status = avFileSendResponse.status(); - - if (status != null) { - stringBuilder.append(" Status: ").append(status).append("."); - } - - if (avFileSendResponse.error() != null) { - stringBuilder.append(" Error code: ") - .append(avFileSendResponse.error().code()) - .append(". Error message: ") - .append(avFileSendResponse.error().message()) - .append(". "); - } - throw new FileUploadException(stringBuilder.toString()); - } - - String id = avFileSendResponse.id(); - String reportRequestUri = avRestAddress + "/" + id; - HttpGet get = new HttpGet(reportRequestUri); - - // waiting for timeout time before first request - try { - TimeUnit.MILLISECONDS.sleep(avFirstTimeoutMilliseconds); - } - catch (InterruptedException e) { - throw new FileUploadException(e); - } - - return receiveScanReport(client, get); } } catch (ClientProtocolException e) { throw new RetryableException("Failed to check file"); } - catch (IOException e) { - // непредусмотренная ошибка доступа через http-клиент - throw new FileUploadException(e); - } - } - - private AvResponse receiveScanReport(CloseableHttpClient client, HttpGet get) - throws RetryableException, FileUploadException { - - try (CloseableHttpResponse getResponse = client.execute(get)) { - int getStatusCode = getResponse.getStatusLine().getStatusCode(); - - if (getStatusCode == HttpStatus.OK.value()) { - String getResponseJson = EntityUtils.toString(getResponse.getEntity()); - AvResponse avResponse = new Gson().fromJson(getResponseJson, AvResponse.class); - - if (avResponse.completed() == null) { - throw new RetryableException("Failed to complete file scan"); - } - return avResponse; - } - else { - throw new FileUploadException("http status code " + getStatusCode + " for " + get.getURI() - + " get request."); - } - } - catch (ClientProtocolException e) { - // непредусмотренная ошибка доступа через http-клиент - throw new RetryableException("Failed to receive scan report"); - } - catch (IOException e) { - // непредусмотренная ошибка доступа через http-клиент + catch (IOException | URISyntaxException e) { throw new FileUploadException(e); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index fa9859a..ddf45e4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -63,6 +63,8 @@ s3.out.secret_key=${S3_SECRET_KEY} s3.out.bucket_name=${S3_OUT_BUCKET_NAME} s3.out.path.style.access.enabled=${S3_OUT_PATH_STYLE_ACCESS_ENABLED} # +webdav.username=${WEBDAV_USERNAME} +webdav.password=${WEBDAV_PASSWORD} # endpoints management management.endpoints.web.exposure.include = health, info, metrics