1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.http.crt.internal.request; 17 18 import java.net.URI; 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.Optional; 22 import software.amazon.awssdk.annotations.SdkInternalApi; 23 import software.amazon.awssdk.crt.http.HttpHeader; 24 import software.amazon.awssdk.crt.http.HttpRequest; 25 import software.amazon.awssdk.http.Header; 26 import software.amazon.awssdk.http.HttpExecuteRequest; 27 import software.amazon.awssdk.http.SdkHttpRequest; 28 import software.amazon.awssdk.http.async.AsyncExecuteRequest; 29 import software.amazon.awssdk.http.crt.internal.CrtAsyncRequestContext; 30 import software.amazon.awssdk.http.crt.internal.CrtRequestContext; 31 32 @SdkInternalApi 33 public final class CrtRequestAdapter { CrtRequestAdapter()34 private CrtRequestAdapter() { 35 } 36 toAsyncCrtRequest(CrtAsyncRequestContext request)37 public static HttpRequest toAsyncCrtRequest(CrtAsyncRequestContext request) { 38 AsyncExecuteRequest sdkExecuteRequest = request.sdkRequest(); 39 SdkHttpRequest sdkRequest = sdkExecuteRequest.request(); 40 41 String method = sdkRequest.method().name(); 42 String encodedPath = sdkRequest.encodedPath(); 43 if (encodedPath == null || encodedPath.isEmpty()) { 44 encodedPath = "/"; 45 } 46 47 String encodedQueryString = sdkRequest.encodedQueryParameters() 48 .map(value -> "?" + value) 49 .orElse(""); 50 51 HttpHeader[] crtHeaderArray = asArray(createAsyncHttpHeaderList(sdkRequest.getUri(), sdkExecuteRequest)); 52 53 return new HttpRequest(method, 54 encodedPath + encodedQueryString, 55 crtHeaderArray, 56 new CrtRequestBodyAdapter(sdkExecuteRequest.requestContentPublisher(), 57 request.readBufferSize())); 58 } 59 toCrtRequest(CrtRequestContext request)60 public static HttpRequest toCrtRequest(CrtRequestContext request) { 61 62 HttpExecuteRequest sdkExecuteRequest = request.sdkRequest(); 63 SdkHttpRequest sdkRequest = sdkExecuteRequest.httpRequest(); 64 65 String method = sdkRequest.method().name(); 66 String encodedPath = sdkRequest.encodedPath(); 67 if (encodedPath == null || encodedPath.isEmpty()) { 68 encodedPath = "/"; 69 } 70 71 String encodedQueryString = sdkRequest.encodedQueryParameters() 72 .map(value -> "?" + value) 73 .orElse(""); 74 75 HttpHeader[] crtHeaderArray = asArray(createHttpHeaderList(sdkRequest.getUri(), sdkExecuteRequest)); 76 77 String finalEncodedPath = encodedPath + encodedQueryString; 78 return sdkExecuteRequest.contentStreamProvider() 79 .map(provider -> new HttpRequest(method, 80 finalEncodedPath, 81 crtHeaderArray, 82 new CrtRequestInputStreamAdapter(provider))) 83 .orElse(new HttpRequest(method, 84 finalEncodedPath, 85 crtHeaderArray, null)); 86 } 87 asArray(List<HttpHeader> crtHeaderList)88 private static HttpHeader[] asArray(List<HttpHeader> crtHeaderList) { 89 return crtHeaderList.toArray(new HttpHeader[0]); 90 } 91 createAsyncHttpHeaderList(URI uri, AsyncExecuteRequest sdkExecuteRequest)92 private static List<HttpHeader> createAsyncHttpHeaderList(URI uri, AsyncExecuteRequest sdkExecuteRequest) { 93 SdkHttpRequest sdkRequest = sdkExecuteRequest.request(); 94 // worst case we may add 3 more headers here 95 List<HttpHeader> crtHeaderList = new ArrayList<>(sdkRequest.numHeaders() + 3); 96 97 // Set Host Header if needed 98 if (!sdkRequest.firstMatchingHeader(Header.HOST).isPresent()) { 99 crtHeaderList.add(new HttpHeader(Header.HOST, uri.getHost())); 100 } 101 102 // Add Connection Keep Alive Header to reuse this Http Connection as long as possible 103 if (!sdkRequest.firstMatchingHeader(Header.CONNECTION).isPresent()) { 104 crtHeaderList.add(new HttpHeader(Header.CONNECTION, Header.KEEP_ALIVE_VALUE)); 105 } 106 107 // Set Content-Length if needed 108 Optional<Long> contentLength = sdkExecuteRequest.requestContentPublisher().contentLength(); 109 if (!sdkRequest.firstMatchingHeader(Header.CONTENT_LENGTH).isPresent() && contentLength.isPresent()) { 110 crtHeaderList.add(new HttpHeader(Header.CONTENT_LENGTH, Long.toString(contentLength.get()))); 111 } 112 113 // Add the rest of the Headers 114 sdkRequest.forEachHeader((key, value) -> value.stream().map(val -> new HttpHeader(key, val)).forEach(crtHeaderList::add)); 115 116 return crtHeaderList; 117 } 118 createHttpHeaderList(URI uri, HttpExecuteRequest sdkExecuteRequest)119 private static List<HttpHeader> createHttpHeaderList(URI uri, HttpExecuteRequest sdkExecuteRequest) { 120 SdkHttpRequest sdkRequest = sdkExecuteRequest.httpRequest(); 121 // worst case we may add 3 more headers here 122 List<HttpHeader> crtHeaderList = new ArrayList<>(sdkRequest.numHeaders() + 3); 123 124 // Set Host Header if needed 125 if (!sdkRequest.firstMatchingHeader(Header.HOST).isPresent()) { 126 crtHeaderList.add(new HttpHeader(Header.HOST, uri.getHost())); 127 } 128 129 // Add Connection Keep Alive Header to reuse this Http Connection as long as possible 130 if (!sdkRequest.firstMatchingHeader(Header.CONNECTION).isPresent()) { 131 crtHeaderList.add(new HttpHeader(Header.CONNECTION, Header.KEEP_ALIVE_VALUE)); 132 } 133 134 // We assume content length was set by the caller if a stream was present, so don't set it here. 135 136 // Add the rest of the Headers 137 sdkRequest.forEachHeader((key, value) -> value.stream().map(val -> new HttpHeader(key, val)).forEach(crtHeaderList::add)); 138 139 return crtHeaderList; 140 } 141 } 142