You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by ad...@apache.org on 2022/08/19 11:38:11 UTC
[ozone] branch master updated: HDDS-7113. Support overriding response header values (#3680)
This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 3efb039091 HDDS-7113. Support overriding response header values (#3680)
3efb039091 is described below
commit 3efb03909111f5a018660713fa0a591a94b4289f
Author: XiChen <32...@users.noreply.github.com>
AuthorDate: Fri Aug 19 19:38:05 2022 +0800
HDDS-7113. Support overriding response header values (#3680)
---
.../hadoop/ozone/s3/endpoint/ObjectEndpoint.java | 55 +++++++---
.../hadoop/ozone/s3/endpoint/TestObjectGet.java | 115 +++++++++++++++++++--
.../ozone/s3/metrics/TestS3GatewayMetrics.java | 10 ++
3 files changed, 161 insertions(+), 19 deletions(-)
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
index 90aae3b388..940df2f858 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
@@ -31,9 +31,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
@@ -46,7 +48,6 @@ import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -84,6 +85,7 @@ import org.apache.hadoop.ozone.s3.util.S3Utils;
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
import org.apache.hadoop.util.Time;
+import com.google.common.collect.ImmutableMap;
import com.google.common.annotations.VisibleForTesting;
import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
import static javax.ws.rs.core.HttpHeaders.LAST_MODIFIED;
@@ -128,19 +130,25 @@ public class ObjectEndpoint extends EndpointBase {
LoggerFactory.getLogger(ObjectEndpoint.class);
@Context
- private HttpHeaders headers;
+ private ContainerRequestContext context;
+ @Context
+ private HttpHeaders headers;
- private List<String> customizableGetHeaders = new ArrayList<>();
+ /*FOR the feature Overriding Response Header
+ https://docs.aws.amazon.com/de_de/AmazonS3/latest/API/API_GetObject.html */
+ private Map<String, String> overrideQueryParameter;
private int bufferSize;
public ObjectEndpoint() {
- customizableGetHeaders.add("Content-Type");
- customizableGetHeaders.add("Content-Language");
- customizableGetHeaders.add("Expires");
- customizableGetHeaders.add("Cache-Control");
- customizableGetHeaders.add("Content-Disposition");
- customizableGetHeaders.add("Content-Encoding");
+ overrideQueryParameter = ImmutableMap.<String, String>builder()
+ .put("Content-Type", "response-content-type")
+ .put("Content-Language", "response-content-language")
+ .put("Expires", "response-expires")
+ .put("Cache-Control", "response-cache-control")
+ .put("Content-Disposition", "response-content-disposition")
+ .put("Content-Encoding", "response-content-encoding")
+ .build();
}
@Inject
@@ -346,10 +354,28 @@ public class ObjectEndpoint extends EndpointBase {
}
responseBuilder.header(ACCEPT_RANGE_HEADER,
RANGE_HEADER_SUPPORTED_UNIT);
- for (String responseHeader : customizableGetHeaders) {
- String headerValue = headers.getHeaderString(responseHeader);
+
+ // if multiple query parameters having same name,
+ // Only the first parameters will be recognized
+ // eg:
+ // http://localhost:9878/bucket/key?response-expires=1&response-expires=2
+ // only response-expires=1 is valid
+ MultivaluedMap<String, String> queryParams = context
+ .getUriInfo().getQueryParameters();
+
+ for (Map.Entry<String, String> entry :
+ overrideQueryParameter.entrySet()) {
+ String headerValue = headers.getHeaderString(entry.getKey());
+
+ /* "Overriding Response Header" by query parameter, See:
+ https://docs.aws.amazon.com/de_de/AmazonS3/latest/API/API_GetObject.html
+ */
+ String queryValue = queryParams.getFirst(entry.getValue());
+ if (queryValue != null) {
+ headerValue = queryValue;
+ }
if (headerValue != null) {
- responseBuilder.header(responseHeader, headerValue);
+ responseBuilder.header(entry.getKey(), headerValue);
}
}
addLastModifiedDate(responseBuilder, keyDetails);
@@ -849,6 +875,11 @@ public class ObjectEndpoint extends EndpointBase {
this.headers = headers;
}
+ @VisibleForTesting
+ public void setContext(ContainerRequestContext context) {
+ this.context = context;
+ }
+
void copy(OzoneVolume volume, InputStream src, long srcKeyLen,
String destKey, String destBucket,
ReplicationConfig replication) throws IOException {
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGet.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGet.java
index a5e8dd039f..d9de8b0f9e 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGet.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGet.java
@@ -20,8 +20,11 @@
package org.apache.hadoop.ozone.s3.endpoint;
+import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
@@ -36,10 +39,12 @@ import org.apache.hadoop.ozone.s3.exception.OS3Exception;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.mockito.Mockito.doReturn;
/**
* Test get object.
@@ -47,11 +52,30 @@ import static java.nio.charset.StandardCharsets.UTF_8;
public class TestObjectGet {
public static final String CONTENT = "0123456789";
+ public static final String CONTENT_TYPE1 = "video/mp4";
+ public static final String CONTENT_TYPE2 = "text/html; charset=UTF-8";
+ public static final String CONTENT_LANGUAGE1 = "en-CA";
+ public static final String CONTENT_LANGUAGE2 = "de-DE, en-CA";
+ public static final String EXPIRES1 = "Wed, 21 Oct 2015 07:29:00 GMT";
+ public static final String EXPIRES2 = "Wed, 21 Oct 2015 07:28:00 GMT";
+ public static final String CACHE_CONTROL1 = "no-cache";
+ public static final String CACHE_CONTROL2 = "max-age=604800";
+ public static final String CONTENT_DISPOSITION1 = "inline";
+ public static final String CONTENT_DISPOSITION2 = "attachment; "
+ + "filename=\"filename.jpg\"";
+ public static final String CONTENT_ENCODING1 = "gzip";
+ public static final String CONTENT_ENCODING2 = "compress";
- @Test
- public void get() throws IOException, OS3Exception {
+ private HttpHeaders headers;
+ private ObjectEndpoint rest;
+ private OzoneClient client;
+ private ByteArrayInputStream body;
+ private ContainerRequestContext context;
+
+ @Before
+ public void init() throws IOException {
//GIVEN
- OzoneClient client = new OzoneClientStub();
+ client = new OzoneClientStub();
client.getObjectStore().createS3Bucket("b1");
OzoneBucket bucket = client.getObjectStore().getS3Bucket("b1");
OzoneOutputStream keyStream =
@@ -59,14 +83,22 @@ public class TestObjectGet {
keyStream.write(CONTENT.getBytes(UTF_8));
keyStream.close();
- ObjectEndpoint rest = new ObjectEndpoint();
+ rest = new ObjectEndpoint();
rest.setClient(client);
rest.setOzoneConfiguration(new OzoneConfiguration());
- HttpHeaders headers = Mockito.mock(HttpHeaders.class);
+ headers = Mockito.mock(HttpHeaders.class);
rest.setHeaders(headers);
- ByteArrayInputStream body =
- new ByteArrayInputStream(CONTENT.getBytes(UTF_8));
+ body = new ByteArrayInputStream(CONTENT.getBytes(UTF_8));
+ context = Mockito.mock(ContainerRequestContext.class);
+ Mockito.when(context.getUriInfo()).thenReturn(Mockito.mock(UriInfo.class));
+ Mockito.when(context.getUriInfo().getQueryParameters())
+ .thenReturn(new MultivaluedHashMap<>());
+ rest.setContext(context);
+ }
+
+ @Test
+ public void get() throws IOException, OS3Exception {
//WHEN
Response response = rest.get("b1", "key1", null, 0, null, body);
@@ -85,4 +117,73 @@ public class TestObjectGet {
.parse(response.getHeaderString("Last-Modified"));
}
+
+ @Test
+ public void inheritRequestHeader() throws IOException, OS3Exception {
+ setDefaultHeader();
+
+ Response response = rest.get("b1", "key1", null, 0, null, body);
+
+ Assert.assertEquals(CONTENT_TYPE1,
+ response.getHeaderString("Content-Type"));
+ Assert.assertEquals(CONTENT_LANGUAGE1,
+ response.getHeaderString("Content-Language"));
+ Assert.assertEquals(EXPIRES1,
+ response.getHeaderString("Expires"));
+ Assert.assertEquals(CACHE_CONTROL1,
+ response.getHeaderString("Cache-Control"));
+ Assert.assertEquals(CONTENT_DISPOSITION1,
+ response.getHeaderString("Content-Disposition"));
+ Assert.assertEquals(CONTENT_ENCODING1,
+ response.getHeaderString("Content-Encoding"));
+ }
+
+ @Test
+ public void overrideResponseHeader() throws IOException, OS3Exception {
+ setDefaultHeader();
+
+ MultivaluedHashMap<String, String> queryParameter =
+ new MultivaluedHashMap<>();
+ // overrider request header
+ queryParameter.putSingle("response-content-type", CONTENT_TYPE2);
+ queryParameter.putSingle("response-content-language", CONTENT_LANGUAGE2);
+ queryParameter.putSingle("response-expires", EXPIRES2);
+ queryParameter.putSingle("response-cache-control", CACHE_CONTROL2);
+ queryParameter.putSingle("response-content-disposition",
+ CONTENT_DISPOSITION2);
+ queryParameter.putSingle("response-content-encoding", CONTENT_ENCODING2);
+
+ Mockito.when(context.getUriInfo().getQueryParameters())
+ .thenReturn(queryParameter);
+ body = new ByteArrayInputStream(CONTENT.getBytes(UTF_8));
+ Response response = rest.get("b1", "key1", null, 0, null, body);
+
+ Assert.assertEquals(CONTENT_TYPE2,
+ response.getHeaderString("Content-Type"));
+ Assert.assertEquals(CONTENT_LANGUAGE2,
+ response.getHeaderString("Content-Language"));
+ Assert.assertEquals(EXPIRES2,
+ response.getHeaderString("Expires"));
+ Assert.assertEquals(CACHE_CONTROL2,
+ response.getHeaderString("Cache-Control"));
+ Assert.assertEquals(CONTENT_DISPOSITION2,
+ response.getHeaderString("Content-Disposition"));
+ Assert.assertEquals(CONTENT_ENCODING2,
+ response.getHeaderString("Content-Encoding"));
+ }
+
+ private void setDefaultHeader() {
+ doReturn(CONTENT_TYPE1)
+ .when(headers).getHeaderString("Content-Type");
+ doReturn(CONTENT_LANGUAGE1)
+ .when(headers).getHeaderString("Content-Language");
+ doReturn(EXPIRES1)
+ .when(headers).getHeaderString("Expires");
+ doReturn(CACHE_CONTROL1)
+ .when(headers).getHeaderString("Cache-Control");
+ doReturn(CONTENT_DISPOSITION1)
+ .when(headers).getHeaderString("Content-Disposition");
+ doReturn(CONTENT_ENCODING1)
+ .when(headers).getHeaderString("Content-Encoding");
+ }
}
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
index 9ce6a95001..daae572df9 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
@@ -39,8 +39,11 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -70,6 +73,7 @@ public class TestS3GatewayMetrics {
private static final String ACL_MARKER = "acl";
private static final String CONTENT = "0123456789";
private S3GatewayMetrics metrics;
+ private ContainerRequestContext context;
@Before
@@ -93,6 +97,12 @@ public class TestS3GatewayMetrics {
"STANDARD");
keyEndpoint.setHeaders(headers);
metrics = bucketEndpoint.getMetrics();
+
+ context = Mockito.mock(ContainerRequestContext.class);
+ Mockito.when(context.getUriInfo()).thenReturn(Mockito.mock(UriInfo.class));
+ Mockito.when(context.getUriInfo().getQueryParameters())
+ .thenReturn(new MultivaluedHashMap<>());
+ keyEndpoint.setContext(context);
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org