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