This project has retired. For details please refer to its
Attic page.
HttpUtils xref
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 java.io.BufferedOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.OutputStream;
26 import java.math.BigInteger;
27 import java.net.HttpURLConnection;
28 import java.net.URL;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.zip.GZIPInputStream;
34 import java.util.zip.GZIPOutputStream;
35 import java.util.zip.Inflater;
36 import java.util.zip.InflaterInputStream;
37
38 import org.apache.chemistry.opencmis.client.bindings.impl.ClientVersion;
39 import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
40 import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
41 import org.apache.chemistry.opencmis.commons.SessionParameter;
42 import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
43 import org.apache.chemistry.opencmis.commons.impl.Base64;
44 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
45 import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48
49
50
51
52 public class HttpUtils {
53
54 private static final Log log = LogFactory.getLog(HttpUtils.class);
55
56 private static final int BUFFER_SIZE = 2 * 1024 * 1024;
57
58 private HttpUtils() {
59 }
60
61 public static Response invokeGET(UrlBuilder url, BindingSession session) {
62 return invoke(url, "GET", null, null, null, session, null, null);
63 }
64
65 public static Response invokeGET(UrlBuilder url, BindingSession session, BigInteger offset, BigInteger length) {
66 return invoke(url, "GET", null, null, null, session, offset, length);
67 }
68
69 public static Response invokePOST(UrlBuilder url, String contentType, Output writer, BindingSession session) {
70 return invoke(url, "POST", contentType, null, writer, session, null, null);
71 }
72
73 public static Response invokePUT(UrlBuilder url, String contentType, Map<String, String> headers, Output writer,
74 BindingSession session) {
75 return invoke(url, "PUT", contentType, headers, writer, session, null, null);
76 }
77
78 public static Response invokeDELETE(UrlBuilder url, BindingSession session) {
79 return invoke(url, "DELETE", null, null, null, session, null, null);
80 }
81
82 private static Response invoke(UrlBuilder url, String method, String contentType, Map<String, String> headers,
83 Output writer, BindingSession session, BigInteger offset, BigInteger length) {
84 try {
85
86 if (log.isDebugEnabled()) {
87 log.debug(method + " " + url);
88 }
89
90
91 HttpURLConnection conn = (HttpURLConnection) (new URL(url.toString())).openConnection();
92 conn.setRequestMethod(method);
93 conn.setDoInput(true);
94 conn.setDoOutput(writer != null);
95 conn.setAllowUserInteraction(false);
96 conn.setUseCaches(false);
97 conn.setRequestProperty("User-Agent", ClientVersion.OPENCMIS_CLIENT);
98
99
100 int connectTimeout = session.get(SessionParameter.CONNECT_TIMEOUT, -1);
101 if (connectTimeout >= 0) {
102 conn.setConnectTimeout(connectTimeout);
103 }
104
105 int readTimeout = session.get(SessionParameter.READ_TIMEOUT, -1);
106 if (readTimeout >= 0) {
107 conn.setReadTimeout(readTimeout);
108 }
109
110
111 if (contentType != null) {
112 conn.setRequestProperty("Content-Type", contentType);
113 }
114
115 if (headers != null) {
116 for (Map.Entry<String, String> header : headers.entrySet()) {
117 conn.addRequestProperty(header.getKey(), header.getValue());
118 }
119 }
120
121
122 AuthenticationProvider authProvider = CmisBindingsHelper.getAuthenticationProvider(session);
123 if (authProvider != null) {
124 Map<String, List<String>> httpHeaders = authProvider.getHTTPHeaders(url.toString());
125 if (httpHeaders != null) {
126 for (Map.Entry<String, List<String>> header : httpHeaders.entrySet()) {
127 if (header.getValue() != null) {
128 for (String value : header.getValue()) {
129 conn.addRequestProperty(header.getKey(), value);
130 }
131 }
132 }
133 }
134 }
135
136
137 if ((offset != null) || (length != null)) {
138 StringBuilder sb = new StringBuilder("bytes=");
139
140 if ((offset == null) || (offset.signum() == -1)) {
141 offset = BigInteger.ZERO;
142 }
143
144 sb.append(offset.toString());
145 sb.append("-");
146
147 if ((length != null) && (length.signum() == 1)) {
148 sb.append(offset.add(length.subtract(BigInteger.ONE)).toString());
149 }
150
151 conn.setRequestProperty("Range", sb.toString());
152 }
153
154
155 Object compression = session.get(SessionParameter.COMPRESSION);
156 if ((compression != null) && Boolean.parseBoolean(compression.toString())) {
157 conn.setRequestProperty("Accept-Encoding", "gzip,deflate");
158 }
159
160
161 if (session.get(CmisBindingsHelper.ACCEPT_LANGUAGE) instanceof String) {
162 conn.setRequestProperty("Accept-Language", session.get(CmisBindingsHelper.ACCEPT_LANGUAGE).toString());
163 }
164
165
166 if (writer != null) {
167 conn.setChunkedStreamingMode((64 * 1024) - 1);
168
169 OutputStream connOut = null;
170
171 Object clientCompression = session.get(SessionParameter.CLIENT_COMPRESSION);
172 if ((clientCompression != null) && Boolean.parseBoolean(clientCompression.toString())) {
173 conn.setRequestProperty("Content-Encoding", "gzip");
174 connOut = new GZIPOutputStream(conn.getOutputStream(), 4096);
175 } else {
176 connOut = conn.getOutputStream();
177 }
178
179 OutputStream out = new BufferedOutputStream(connOut, BUFFER_SIZE);
180 writer.write(out);
181 out.flush();
182 }
183
184
185 conn.connect();
186
187
188 int respCode = conn.getResponseCode();
189 InputStream inputStream = null;
190 if ((respCode == 200) || (respCode == 201) || (respCode == 203) || (respCode == 206)) {
191 inputStream = conn.getInputStream();
192 }
193
194
195 if (log.isTraceEnabled()) {
196 log.trace(method + " " + url + " > Headers: " + conn.getHeaderFields());
197 }
198
199
200 if (authProvider != null) {
201 authProvider.putResponseHeaders(url.toString(), respCode, conn.getHeaderFields());
202 }
203
204
205 return new Response(respCode, conn.getResponseMessage(), conn.getHeaderFields(), inputStream,
206 conn.getErrorStream());
207 } catch (Exception e) {
208 throw new CmisConnectionException("Cannot access " + url + ": " + e.getMessage(), e);
209 }
210 }
211
212
213
214
215 public static class Response {
216 private final int responseCode;
217 private final String responseMessage;
218 private final Map<String, List<String>> headers;
219 private InputStream stream;
220 private String errorContent;
221 private BigInteger length;
222 private String charset;
223
224 public Response(int responseCode, String responseMessage, Map<String, List<String>> headers,
225 InputStream responseStream, InputStream errorStream) {
226 this.responseCode = responseCode;
227 this.responseMessage = responseMessage;
228 stream = responseStream;
229
230 this.headers = new HashMap<String, List<String>>();
231 if (headers != null) {
232 for (Map.Entry<String, List<String>> e : headers.entrySet()) {
233 this.headers.put(e.getKey() == null ? null : e.getKey().toLowerCase(), e.getValue());
234 }
235 }
236
237
238 charset = "UTF-8";
239 String contentType = getContentTypeHeader();
240 if (contentType != null) {
241 String[] parts = contentType.split(";");
242 for (int i = 1; i < parts.length; i++) {
243 String part = parts[i].trim().toLowerCase();
244 if (part.startsWith("charset")) {
245 int x = part.indexOf('=');
246 charset = part.substring(x + 1).trim();
247 break;
248 }
249 }
250 }
251
252
253 if (errorStream != null) {
254 if (contentType != null) {
255 String contentTypeLower = contentType.toLowerCase().split(";")[0];
256 if (contentTypeLower.startsWith("text/") || contentTypeLower.endsWith("+xml")
257 || contentTypeLower.startsWith("application/json")) {
258 StringBuilder sb = new StringBuilder();
259
260 try {
261 String encoding = getContentEncoding();
262 if (encoding != null) {
263 if (encoding.toLowerCase().trim().equals("gzip")) {
264 try {
265 errorStream = new GZIPInputStream(errorStream, 4096);
266 } catch (IOException e) {
267 }
268 } else if (encoding.toLowerCase().trim().equals("deflate")) {
269 errorStream = new InflaterInputStream(errorStream, new Inflater(true), 4096);
270 }
271 }
272
273 InputStreamReader reader = new InputStreamReader(errorStream, charset);
274 char[] buffer = new char[4096];
275 int b;
276 while ((b = reader.read(buffer)) > -1) {
277 sb.append(buffer, 0, b);
278 }
279 reader.close();
280
281 errorContent = sb.toString();
282 } catch (IOException e) {
283 errorContent = "Unable to retrieve content: " + e.getMessage();
284 }
285 }
286 } else {
287 try {
288 errorStream.close();
289 } catch (IOException e) {
290 }
291 }
292
293 if (responseStream != null) {
294 try {
295 responseStream.close();
296 } catch (IOException e) {
297 }
298 }
299
300 return;
301 }
302
303
304 String lengthStr = getHeader("Content-Length");
305 if (lengthStr != null) {
306 try {
307 length = new BigInteger(lengthStr);
308 } catch (NumberFormatException e) {
309 }
310 }
311
312 if (stream != null) {
313 String encoding = getContentEncoding();
314 if (encoding != null) {
315 if (encoding.toLowerCase().trim().equals("gzip")) {
316
317 length = null;
318 try {
319 stream = new GZIPInputStream(stream, 4096);
320 } catch (IOException e) {
321 errorContent = e.getMessage();
322 stream = null;
323 try {
324 responseStream.close();
325 } catch (IOException ec) {
326 }
327 }
328 } else if (encoding.toLowerCase().trim().equals("deflate")) {
329
330 length = null;
331 stream = new InflaterInputStream(stream, new Inflater(true), 4096);
332 }
333 }
334
335 String transferEncoding = getContentTransferEncoding();
336 if ((stream != null) && (transferEncoding != null)
337 && (transferEncoding.toLowerCase().trim().equals("base64"))) {
338
339 length = null;
340 stream = new Base64.InputStream(stream);
341 }
342 }
343 }
344
345 public int getResponseCode() {
346 return responseCode;
347 }
348
349 public String getResponseMessage() {
350 return responseMessage;
351 }
352
353 public Map<String, List<String>> getHeaders() {
354 return headers;
355 }
356
357 public String getHeader(String name) {
358 List<String> list = headers.get(name.toLowerCase(Locale.US));
359 if ((list == null) || (list.isEmpty())) {
360 return null;
361 }
362
363 return list.get(0);
364 }
365
366 public String getContentTypeHeader() {
367 return getHeader("Content-Type");
368 }
369
370 public BigInteger getContentLengthHeader() {
371 String lengthStr = getHeader("Content-Length");
372 if (lengthStr == null) {
373 return null;
374 }
375
376 try {
377 return new BigInteger(lengthStr);
378 } catch (NumberFormatException e) {
379 return null;
380 }
381 }
382
383 public String getLocactionHeader() {
384 return getHeader("Location");
385 }
386
387 public String getContentLocactionHeader() {
388 return getHeader("Content-Location");
389 }
390
391 public String getContentTransferEncoding() {
392 return getHeader("Content-Transfer-Encoding");
393 }
394
395 public String getContentEncoding() {
396 return getHeader("Content-Encoding");
397 }
398
399 public String getCharset() {
400 return charset;
401 }
402
403 public BigInteger getContentLength() {
404 return length;
405 }
406
407 public InputStream getStream() {
408 return stream;
409 }
410
411 public String getErrorContent() {
412 return errorContent;
413 }
414 }
415
416
417
418
419 public interface Output {
420 void write(OutputStream out) throws Exception;
421 }
422 }