
001package ca.uhn.fhir.rest.client.apache; 002 003/* 004 * #%L 005 * HAPI FHIR - Client Framework 006 * %% 007 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022import ca.uhn.fhir.i18n.Msg; 023import java.io.*; 024import java.nio.charset.Charset; 025import java.nio.charset.StandardCharsets; 026import java.util.*; 027 028import ca.uhn.fhir.rest.client.impl.BaseHttpResponse; 029import ca.uhn.fhir.util.StopWatch; 030import org.apache.commons.io.IOUtils; 031import org.apache.http.*; 032import org.apache.http.client.methods.CloseableHttpResponse; 033import org.apache.http.entity.ContentType; 034 035import ca.uhn.fhir.rest.api.Constants; 036import ca.uhn.fhir.rest.client.api.IHttpResponse; 037import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 038 039/** 040 * A Http Response based on Apache. This is an adapter around the class 041 * {@link org.apache.http.HttpResponse HttpResponse} 042 * 043 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 044 */ 045public class ApacheHttpResponse extends BaseHttpResponse implements IHttpResponse { 046 047 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheHttpResponse.class); 048 049 private boolean myEntityBuffered = false; 050 private byte[] myEntityBytes; 051 private final HttpResponse myResponse; 052 053 public ApacheHttpResponse(HttpResponse theResponse, StopWatch theResponseStopWatch) { 054 super(theResponseStopWatch); 055 this.myResponse = theResponse; 056 } 057 058 @Override 059 public void bufferEntity() throws IOException { 060 if (myEntityBuffered) { 061 return; 062 } 063 try (InputStream respEntity = readEntity()) { 064 if (respEntity != null) { 065 this.myEntityBuffered = true; 066 try { 067 this.myEntityBytes = IOUtils.toByteArray(respEntity); 068 } catch (IllegalStateException e) { 069 throw new InternalErrorException(Msg.code(1478) + e); 070 } 071 } 072 } 073 } 074 075 @Override 076 public void close() { 077 if (myResponse instanceof CloseableHttpResponse) { 078 try { 079 ((CloseableHttpResponse) myResponse).close(); 080 } catch (IOException e) { 081 ourLog.debug("Failed to close response", e); 082 } 083 } 084 } 085 086 @Override 087 public Reader createReader() throws IOException { 088 HttpEntity entity = myResponse.getEntity(); 089 if (entity == null) { 090 return new StringReader(""); 091 } 092 Charset charset = null; 093 if (entity.getContentType() != null && entity.getContentType().getElements() != null 094 && entity.getContentType().getElements().length > 0) { 095 ContentType ct = ContentType.get(entity); 096 charset = ct.getCharset(); 097 } 098 if (charset == null) { 099 if (Constants.STATUS_HTTP_204_NO_CONTENT != myResponse.getStatusLine().getStatusCode()) { 100 ourLog.debug("Response did not specify a charset, defaulting to utf-8"); 101 } 102 charset = StandardCharsets.UTF_8; 103 } 104 105 return new InputStreamReader(readEntity(), charset); 106 } 107 108 @Override 109 public Map<String, List<String>> getAllHeaders() { 110 Map<String, List<String>> headers = new HashMap<>(); 111 if (myResponse.getAllHeaders() != null) { 112 for (Header next : myResponse.getAllHeaders()) { 113 String name = next.getName().toLowerCase(); 114 List<String> list = headers.computeIfAbsent(name, k -> new ArrayList<>()); 115 list.add(next.getValue()); 116 } 117 118 } 119 return headers; 120 } 121 122 @Override 123 public List<String> getHeaders(String theName) { 124 Header[] headers = myResponse.getHeaders(theName); 125 if (headers == null) { 126 headers = new Header[0]; 127 } 128 List<String> retVal = new ArrayList<>(); 129 for (Header next : headers) { 130 retVal.add(next.getValue()); 131 } 132 return retVal; 133 } 134 135 @Override 136 public String getMimeType() { 137 ContentType ct = ContentType.get(myResponse.getEntity()); 138 return ct != null ? ct.getMimeType() : null; 139 } 140 141 @Override 142 public HttpResponse getResponse() { 143 return myResponse; 144 } 145 146 @Override 147 public int getStatus() { 148 return myResponse.getStatusLine().getStatusCode(); 149 } 150 151 @Override 152 public String getStatusInfo() { 153 return myResponse.getStatusLine().getReasonPhrase(); 154 } 155 156 @Override 157 public InputStream readEntity() throws IOException { 158 if (this.myEntityBuffered) { 159 return new ByteArrayInputStream(myEntityBytes); 160 } else if (myResponse.getEntity() != null) { 161 return myResponse.getEntity().getContent(); 162 } else { 163 return null; 164 } 165 } 166}