HDDS-4856. Ruby S3 SDK never get authenticated by Ozone (#2013)
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/EmptyContentTypeFilter.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/EmptyContentTypeFilter.java
new file mode 100644
index 0000000..d9518e6
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/EmptyContentTypeFilter.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.ozone.s3;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * Filter to accept queries with empty string content-type (ruby sdk).
+ */
+public class EmptyContentTypeFilter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+
+ }
+
+ @Override
+ public void doFilter(
+ ServletRequest request, ServletResponse response, FilterChain chain
+ ) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ if ("".equals(httpRequest.getContentType())) {
+ chain.doFilter(new HttpServletRequestWrapper(httpRequest) {
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ if (name.equalsIgnoreCase("Content-Type")) {
+ return null;
+ }
+ return super.getHeader(name);
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String name) {
+ if ("Content-Type".equalsIgnoreCase(name)) {
+ return null;
+ }
+ return super.getHeaders(name);
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return new EnumerationWrapper(super.getHeaderNames());
+ }
+ }, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+ /**
+ * Enumeration Wrapper which removes Content-Type from the original
+ * enumeration.
+ */
+ public static class EnumerationWrapper implements Enumeration<String> {
+
+ private final Enumeration<String> original;
+
+ private String nextElement;
+
+ public EnumerationWrapper(Enumeration<String> original) {
+ this.original = original;
+ step();
+ }
+
+ private void step() {
+ if (original.hasMoreElements()) {
+ nextElement = original.nextElement();
+ } else {
+ nextElement = null;
+ }
+ if ("Content-Type".equalsIgnoreCase(nextElement)) {
+ if (original.hasMoreElements()) {
+ nextElement = original.nextElement();
+ } else {
+ nextElement = null;
+ }
+ }
+ }
+
+ @Override
+ public boolean hasMoreElements() {
+ return nextElement != null;
+ }
+
+ @Override
+ public String nextElement() {
+ if (nextElement == null) {
+ throw new NoSuchElementException();
+ }
+ String returnValue = nextElement;
+ step();
+ return returnValue;
+ }
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/main/resources/webapps/s3gateway/WEB-INF/web.xml b/hadoop-ozone/s3gateway/src/main/resources/webapps/s3gateway/WEB-INF/web.xml
index d4e8d02..79bf7b9 100644
--- a/hadoop-ozone/s3gateway/src/main/resources/webapps/s3gateway/WEB-INF/web.xml
+++ b/hadoop-ozone/s3gateway/src/main/resources/webapps/s3gateway/WEB-INF/web.xml
@@ -28,11 +28,20 @@
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
+ <filter-name>optional-content-type</filter-name>
+ <filter-class>org.apache.hadoop.ozone.s3.EmptyContentTypeFilter
+ </filter-class>
+ </filter>
+ <filter>
<filter-name>info-page-redirect</filter-name>
<filter-class>org.apache.hadoop.ozone.s3.RootPageDisplayFilter
</filter-class>
</filter>
<filter-mapping>
+ <filter-name>optional-content-type</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <filter-mapping>
<filter-name>info-page-redirect</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/TestEmptyContentTypeFilter.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/TestEmptyContentTypeFilter.java
new file mode 100644
index 0000000..7bac23c
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/TestEmptyContentTypeFilter.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.ozone.s3;
+
+import java.util.Vector;
+
+import org.apache.hadoop.ozone.s3.EmptyContentTypeFilter.EnumerationWrapper;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestEmptyContentTypeFilter {
+
+ @Test
+ public void enumerationWithContentType() {
+ Vector<String> values = new Vector<>();
+ values.add("Content-Type");
+ values.add("1");
+ values.add("2");
+ values.add("Content-Type");
+
+ final EnumerationWrapper enumerationWrapper =
+ new EnumerationWrapper(values.elements());
+
+ Assert.assertTrue(enumerationWrapper.hasMoreElements());
+ Assert.assertEquals("1", enumerationWrapper.nextElement());
+ Assert.assertTrue(enumerationWrapper.hasMoreElements());
+ Assert.assertEquals("2", enumerationWrapper.nextElement());
+ Assert.assertFalse(enumerationWrapper.hasMoreElements());
+ }
+
+ @Test
+ public void enumerationWithOneContentType() {
+ Vector<String> values = new Vector<>();
+ values.add("Content-Type");
+
+ final EnumerationWrapper enumerationWrapper =
+ new EnumerationWrapper(values.elements());
+
+ Assert.assertFalse(enumerationWrapper.hasMoreElements());
+ }
+
+}
\ No newline at end of file