1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.client.bindings.spi.http;
20
21 import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
22
23 import java.io.BufferedInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.math.BigInteger;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.zip.GZIPInputStream;
33 import java.util.zip.Inflater;
34 import java.util.zip.InflaterInputStream;
35
36 import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
37 import org.apache.chemistry.opencmis.commons.impl.Base64;
38 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
39
40
41
42
43 public class Response {
44 private static final int MAX_ERROR_LENGTH = 128 * 1024;
45
46 private final int responseCode;
47 private final String responseMessage;
48 private final Map<String, List<String>> headers;
49 private InputStream stream;
50 private String errorContent;
51 private BigInteger length;
52 private String charset;
53 private boolean hasResponseStream;
54
55 public Response(int responseCode, String responseMessage, Map<String, List<String>> headers,
56 InputStream responseStream, InputStream errorStream) {
57 this.responseCode = responseCode;
58 this.responseMessage = responseMessage;
59 this.stream = responseStream;
60 this.hasResponseStream = stream != null;
61 boolean isGZIP = responseStream instanceof GZIPInputStream;
62
63 this.headers = new HashMap<String, List<String>>();
64 if (headers != null) {
65 for (Map.Entry<String, List<String>> e : headers.entrySet()) {
66 this.headers.put(e.getKey() == null ? null : e.getKey().toLowerCase(Locale.ENGLISH), e.getValue());
67 }
68 }
69
70
71 charset = IOUtils.UTF8;
72 String contentType = getContentTypeHeader();
73 if (contentType != null) {
74 String[] parts = contentType.split(";");
75 for (int i = 1; i < parts.length; i++) {
76 String part = parts[i].trim().toLowerCase(Locale.ENGLISH);
77 if (part.startsWith("charset")) {
78 int x = part.indexOf('=');
79 charset = part.substring(x + 1).trim();
80 break;
81 }
82 }
83 }
84
85
86 if (errorStream != null) {
87 if (contentType != null) {
88 String contentTypeLower = contentType.toLowerCase(Locale.ENGLISH).split(";")[0];
89 if (contentTypeLower.startsWith("text/") || contentTypeLower.endsWith("+xml")
90 || contentTypeLower.startsWith("application/xml")
91 || contentTypeLower.startsWith("application/json")) {
92 errorStream = new BufferedInputStream(errorStream, 64 * 1024);
93 StringBuilder sb = new StringBuilder(4096);
94
95 try {
96 String encoding = getContentEncoding();
97 if (encoding != null) {
98 String encLower = encoding.trim().toLowerCase(Locale.ENGLISH);
99 if (encLower.equals("gzip") && !isGZIP) {
100 errorStream = new GZIPInputStream(errorStream, 64 * 1024);
101 } else if (encLower.equals("deflate")) {
102 errorStream = new InflaterInputStream(errorStream, new Inflater(true), 64 * 1024);
103 }
104 }
105
106 InputStreamReader reader = new InputStreamReader(errorStream, charset);
107 char[] buffer = new char[4096];
108 int b;
109 while ((b = reader.read(buffer)) > -1) {
110 sb.append(buffer, 0, b);
111 if (sb.length() >= MAX_ERROR_LENGTH) {
112 break;
113 }
114 }
115 reader.close();
116
117 errorContent = sb.toString();
118 } catch (IOException e) {
119 errorContent = "Unable to retrieve content: " + e.getMessage();
120 }
121 }
122 } else {
123 IOUtils.closeQuietly(errorStream);
124 }
125
126 IOUtils.closeQuietly(responseStream);
127
128 return;
129 }
130
131
132 length = null;
133 String lengthStr = getHeader("Content-Length");
134 if (lengthStr != null && !isGZIP) {
135 try {
136 length = new BigInteger(lengthStr);
137 } catch (NumberFormatException e) {
138
139 }
140 }
141
142 if (stream == null || BigInteger.ZERO.equals(length) || responseCode == 204) {
143 hasResponseStream = false;
144 } else {
145 stream = new BufferedInputStream(stream, 64 * 1024);
146 try {
147 hasResponseStream = IOUtils.checkForBytes(stream);
148 } catch (IOException ioe) {
149 throw new CmisConnectionException("IO exception!", ioe);
150 }
151
152 if (hasResponseStream) {
153 String encoding = getContentEncoding();
154 if (encoding != null) {
155 String encLower = encoding.trim().toLowerCase(Locale.ENGLISH);
156 if (encLower.equals("gzip") && !isGZIP) {
157
158 length = null;
159 try {
160 stream = new GZIPInputStream(stream, 64 * 1024);
161 } catch (IOException e) {
162 errorContent = e.getMessage();
163 stream = null;
164 IOUtils.closeQuietly(responseStream);
165 }
166 } else if (encLower.equals("deflate")) {
167
168 length = null;
169 stream = new InflaterInputStream(stream, new Inflater(true), 64 * 1024);
170 }
171 }
172
173 String transferEncoding = getContentTransferEncoding();
174 if (transferEncoding != null && transferEncoding.trim().toLowerCase(Locale.ENGLISH).equals("base64")) {
175
176 length = null;
177 stream = new Base64.InputStream(stream);
178 }
179 }
180 }
181 }
182
183 public int getResponseCode() {
184 return responseCode;
185 }
186
187 public String getResponseMessage() {
188 return responseMessage;
189 }
190
191 public Map<String, List<String>> getHeaders() {
192 return headers;
193 }
194
195 public String getHeader(String name) {
196 List<String> list = headers.get(name.toLowerCase(Locale.US));
197 if (isNullOrEmpty(list)) {
198 return null;
199 }
200
201 return list.get(0);
202 }
203
204 public String getContentTypeHeader() {
205 return getHeader("Content-Type");
206 }
207
208 public BigInteger getContentLengthHeader() {
209 String lengthStr = getHeader("Content-Length");
210 if (lengthStr == null) {
211 return null;
212 }
213
214 try {
215 return new BigInteger(lengthStr);
216 } catch (NumberFormatException e) {
217 return null;
218 }
219 }
220
221 public String getLocactionHeader() {
222 return getHeader("Location");
223 }
224
225 public String getContentLocactionHeader() {
226 return getHeader("Content-Location");
227 }
228
229 public String getContentTransferEncoding() {
230 return getHeader("Content-Transfer-Encoding");
231 }
232
233 public String getContentEncoding() {
234 return getHeader("Content-Encoding");
235 }
236
237 public String getContentDisposition() {
238 return getHeader("Content-Disposition");
239 }
240
241 public String getCharset() {
242 return charset;
243 }
244
245 public BigInteger getContentLength() {
246 return length;
247 }
248
249 public boolean hasResponseStream() {
250 return hasResponseStream;
251 }
252
253 public InputStream getStream() {
254 return stream;
255 }
256
257 public String getErrorContent() {
258 return errorContent;
259 }
260 }