diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 8e3e4908dcea..aec1560f4113 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -18,16 +18,15 @@ import static io.netty.buffer.Unpooled.copiedBuffer; import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION; -import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import java.io.IOException; import java.net.URI; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import io.netty.handler.codec.DecoderException; import org.apache.cloudstack.storage.template.UploadEntity; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.lang3.StringUtils; @@ -41,6 +40,7 @@ import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpContent; @@ -79,16 +79,46 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler getUploadRequestUsefulHeaders(HttpHeaders headers) { + Map headerMap = new HashMap<>(); + for (Entry entry : headers) { + UploadHeader headerType = UploadHeader.fromName(entry.getKey()); + if (headerType != null) { + headerMap.put(headerType, entry.getValue()); + } + } + for (UploadHeader type : UploadHeader.values()) { + logger.info(String.format("HEADER: %s=%s", type, headerMap.get(type))); + } + return headerMap; + } + public HttpUploadServerHandler(NfsSecondaryStorageResource storageResource) { this.storageResource = storageResource; } @@ -123,36 +153,8 @@ public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Excep URI uri = new URI(request.getUri()); - String signature = null; - String expires = null; - String metadata = null; - String hostname = null; - long contentLength = 0; - - for (Entry entry : request.headers()) { - switch (entry.getKey()) { - case HEADER_SIGNATURE: - signature = entry.getValue(); - break; - case HEADER_METADATA: - metadata = entry.getValue(); - break; - case HEADER_EXPIRES: - expires = entry.getValue(); - break; - case HEADER_HOST: - hostname = entry.getValue(); - break; - case HttpHeaders.Names.CONTENT_LENGTH: - contentLength = Long.parseLong(entry.getValue()); - break; - } - } - logger.info("HEADER: signature=" + signature); - logger.info("HEADER: metadata=" + metadata); - logger.info("HEADER: expires=" + expires); - logger.info("HEADER: hostname=" + hostname); - logger.info("HEADER: content-length=" + contentLength); + Map headers = getUploadRequestUsefulHeaders(request.headers()); + long contentLength = headers.get(UploadHeader.CONTENT_LENGTH) != null ? Long.parseLong(headers.get(UploadHeader.CONTENT_LENGTH)) : 0; QueryStringDecoder decoderQuery = new QueryStringDecoder(uri); Map> uriAttributes = decoderQuery.parameters(); uuid = uriAttributes.get("uuid").get(0); @@ -160,9 +162,10 @@ public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Excep UploadEntity uploadEntity = null; try { // Validate the request here - storageResource.validatePostUploadRequest(signature, metadata, expires, hostname, contentLength, uuid); + storageResource.validatePostUploadRequest(headers.get(UploadHeader.SIGNATURE), headers.get(UploadHeader.METADATA), + headers.get(UploadHeader.EXPIRES), headers.get(UploadHeader.HOST), contentLength, uuid); //create an upload entity. This will fail if entity already exists. - uploadEntity = storageResource.createUploadEntity(uuid, metadata, contentLength); + uploadEntity = storageResource.createUploadEntity(uuid, headers.get(UploadHeader.METADATA), contentLength); } catch (InvalidParameterValueException ex) { logger.error("post request validation failed", ex); responseContent.append(ex.getMessage()); @@ -280,7 +283,7 @@ private void writeResponse(Channel channel, HttpResponseStatus statusCode) { response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); if (!close) { // There's no need to add 'content-length' header if this is the last response. - response.headers().set(CONTENT_LENGTH, buf.readableBytes()); + response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, buf.readableBytes()); } // Write the response. ChannelFuture future = channel.writeAndFlush(response); diff --git a/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandlerTest.java b/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandlerTest.java new file mode 100644 index 000000000000..4f1ae39842e4 --- /dev/null +++ b/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandlerTest.java @@ -0,0 +1,74 @@ +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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.cloudstack.storage.resource; + +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaders; + +@RunWith(MockitoJUnitRunner.class) +public class HttpUploadServerHandlerTest { + + @Spy + @InjectMocks + HttpUploadServerHandler httpUploadServerHandler = new HttpUploadServerHandler(Mockito.mock(NfsSecondaryStorageResource.class)); + + private void runGetUploadRequestUsefulHeadersTestForHost(String hostHeaderKey, String hostHeaderValue) { + HttpHeaders request = new DefaultHttpHeaders(); + request.add(hostHeaderKey, hostHeaderValue); + Map headers = httpUploadServerHandler.getUploadRequestUsefulHeaders(request); + Assert.assertEquals(hostHeaderValue, headers.get(HttpUploadServerHandler.UploadHeader.HOST)); + } + + @Test + public void testGetUploadRequestUsefulHeadersHeaderKeyDifferentCase() { + String host = "SomeHost"; + runGetUploadRequestUsefulHeadersTestForHost(HttpUploadServerHandler.UploadHeader.HOST.getName(), host); + runGetUploadRequestUsefulHeadersTestForHost(HttpUploadServerHandler.UploadHeader.HOST.getName().toUpperCase(), host); + runGetUploadRequestUsefulHeadersTestForHost("X-Forwarded-Host", host); + } + + @Test + public void testGetUploadRequestUsefulHeadersAllKeys() { + HttpHeaders request = new DefaultHttpHeaders(); + String sign = "Sign"; + String metadata = "met"; + String expires = "ex"; + String host = "SomeHost"; + long contentLength = 100L; + request.add("x-Signature", sign); + request.add("X-metadata", metadata); + request.add("X-EXPIRES", expires); + request.add("X-Forwarded-Host", host); + request.add(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); + Map headers = httpUploadServerHandler.getUploadRequestUsefulHeaders(request); + Assert.assertEquals(sign, headers.get(HttpUploadServerHandler.UploadHeader.SIGNATURE)); + Assert.assertEquals(metadata, headers.get(HttpUploadServerHandler.UploadHeader.METADATA)); + Assert.assertEquals(expires, headers.get(HttpUploadServerHandler.UploadHeader.EXPIRES)); + Assert.assertEquals(host, headers.get(HttpUploadServerHandler.UploadHeader.HOST)); + Assert.assertEquals(String.valueOf(contentLength), headers.get(HttpUploadServerHandler.UploadHeader.CONTENT_LENGTH)); + } +}