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.response; 17 18 import software.amazon.awssdk.annotations.SdkInternalApi; 19 import software.amazon.awssdk.crt.http.HttpClientConnection; 20 import software.amazon.awssdk.crt.http.HttpHeader; 21 import software.amazon.awssdk.crt.http.HttpHeaderBlock; 22 import software.amazon.awssdk.crt.http.HttpStream; 23 import software.amazon.awssdk.http.HttpStatusFamily; 24 import software.amazon.awssdk.http.SdkHttpResponse; 25 26 /** 27 * This is the helper class that contains common logic shared between {@link CrtResponseAdapter} and 28 * {@link InputStreamAdaptingHttpStreamResponseHandler}. 29 * 30 * CRT connection will only be closed, i.e., not reused, in one of the following conditions: 31 * 1. 5xx server error OR 32 * 2. It fails to read the response OR 33 * 3. the response stream is closed/aborted by the caller. 34 */ 35 @SdkInternalApi 36 public class ResponseHandlerHelper { 37 38 private final SdkHttpResponse.Builder responseBuilder; 39 private final HttpClientConnection connection; 40 private boolean connectionClosed; 41 private final Object lock = new Object(); 42 ResponseHandlerHelper(SdkHttpResponse.Builder responseBuilder, HttpClientConnection connection)43 public ResponseHandlerHelper(SdkHttpResponse.Builder responseBuilder, HttpClientConnection connection) { 44 this.responseBuilder = responseBuilder; 45 this.connection = connection; 46 } 47 onResponseHeaders(HttpStream stream, int responseStatusCode, int headerType, HttpHeader[] nextHeaders)48 public void onResponseHeaders(HttpStream stream, int responseStatusCode, int headerType, HttpHeader[] nextHeaders) { 49 if (headerType == HttpHeaderBlock.MAIN.getValue()) { 50 for (HttpHeader h : nextHeaders) { 51 responseBuilder.appendHeader(h.getName(), h.getValue()); 52 } 53 responseBuilder.statusCode(responseStatusCode); 54 } 55 } 56 57 /** 58 * Release the connection back to the pool so that it can be reused. 59 */ releaseConnection(HttpStream stream)60 public void releaseConnection(HttpStream stream) { 61 synchronized (lock) { 62 if (!connectionClosed) { 63 connectionClosed = true; 64 connection.close(); 65 stream.close(); 66 } 67 } 68 } 69 incrementWindow(HttpStream stream, int windowSize)70 public void incrementWindow(HttpStream stream, int windowSize) { 71 synchronized (lock) { 72 if (!connectionClosed) { 73 stream.incrementWindow(windowSize); 74 } 75 } 76 } 77 78 /** 79 * Close the connection completely 80 */ closeConnection(HttpStream stream)81 public void closeConnection(HttpStream stream) { 82 synchronized (lock) { 83 if (!connectionClosed) { 84 connectionClosed = true; 85 connection.shutdown(); 86 connection.close(); 87 stream.close(); 88 } 89 } 90 } 91 cleanUpConnectionBasedOnStatusCode(HttpStream stream)92 public void cleanUpConnectionBasedOnStatusCode(HttpStream stream) { 93 // always close the connection on a 5XX response code. 94 if (HttpStatusFamily.of(responseBuilder.statusCode()) == HttpStatusFamily.SERVER_ERROR) { 95 closeConnection(stream); 96 } else { 97 releaseConnection(stream); 98 } 99 } 100 } 101