001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.base.util;
019:
020: import java.io.BufferedReader;
021: import java.io.DataOutputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.InputStreamReader;
025: import java.net.HttpURLConnection;
026: import java.net.URL;
027: import java.net.URLConnection;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.Map;
031: import java.util.Set;
032:
033: /**
034: * Send HTTP GET/POST requests.
035: *
036: */
037: public class HttpClient {
038:
039: public static final String module = HttpClient.class.getName();
040:
041: private int timeout = 30000;
042: private boolean debug = false;
043: private boolean lineFeed = true;
044: private boolean followRedirects = true;
045:
046: private String url = null;
047: private String rawStream = null;
048: private String clientCertAlias = null;
049: private Map parameters = null;
050: private Map headers = null;
051:
052: private URL requestUrl = null;
053: private URLConnection con = null;
054:
055: /** Creates an empty HttpClient object. */
056: public HttpClient() {
057: }
058:
059: /** Creates a new HttpClient object. */
060: public HttpClient(URL url) {
061: this .url = url.toExternalForm();
062: }
063:
064: /** Creates a new HttpClient object. */
065: public HttpClient(String url) {
066: this .url = url;
067: }
068:
069: /** Creates a new HttpClient object. */
070: public HttpClient(String url, Map parameters) {
071: this .url = url;
072: this .parameters = parameters;
073: }
074:
075: /** Creates a new HttpClient object. */
076: public HttpClient(URL url, Map parameters) {
077: this .url = url.toExternalForm();
078: this .parameters = parameters;
079: }
080:
081: /** Creates a new HttpClient object. */
082: public HttpClient(String url, Map parameters, Map headers) {
083: this .url = url;
084: this .parameters = parameters;
085: this .headers = headers;
086: }
087:
088: /** Creates a new HttpClient object. */
089: public HttpClient(URL url, Map parameters, Map headers) {
090: this .url = url.toExternalForm();
091: this .parameters = parameters;
092: this .headers = headers;
093: }
094:
095: /** When true overrides Debug.verboseOn() and forces debugging for this instance */
096: public void setDebug(boolean debug) {
097: this .debug = debug;
098: }
099:
100: /** Sets the timeout for waiting for the connection (default 30sec) */
101: public void setTimeout(int timeout) {
102: this .timeout = timeout;
103: }
104:
105: /** Enables this request to follow redirect 3xx codes (default true) */
106: public void followRedirects(boolean followRedirects) {
107: this .followRedirects = followRedirects;
108: }
109:
110: /** Turns on or off line feeds in the request. (default is on) */
111: public void setLineFeed(boolean lineFeed) {
112: this .lineFeed = lineFeed;
113: }
114:
115: /** Set the raw stream for posts. */
116: public void setRawStream(String stream) {
117: this .rawStream = stream;
118: }
119:
120: /** Set the URL for this request. */
121: public void setUrl(URL url) {
122: this .url = url.toExternalForm();
123: }
124:
125: /** Set the URL for this request. */
126: public void setUrl(String url) {
127: this .url = url;
128: }
129:
130: /** Set the parameters for this request. */
131: public void setParameters(Map parameters) {
132: this .parameters = parameters;
133: }
134:
135: /** Set an individual parameter for this request. */
136: public void setParameter(String name, String value) {
137: if (parameters == null)
138: parameters = new HashMap();
139: parameters.put(name, value);
140: }
141:
142: /** Set the headers for this request. */
143: public void setHeaders(Map headers) {
144: this .headers = headers;
145: }
146:
147: /** Set an individual header for this request. */
148: public void setHeader(String name, String value) {
149: if (headers == null)
150: headers = new HashMap();
151: headers.put(name, value);
152: }
153:
154: /** Return a Map of headers. */
155: public Map getHeaders() {
156: return headers;
157: }
158:
159: /** Return a Map of parameters. */
160: public Map getParameters() {
161: return parameters;
162: }
163:
164: /** Return a string representing the requested URL. */
165: public String getUrl() {
166: return url;
167: }
168:
169: /** Sets the client certificate alias (from the keystore) to use for this SSL connection. */
170: public void setClientCertificateAlias(String alias) {
171: this .clientCertAlias = alias;
172: }
173:
174: /** Returns the alias of the client certificate to be used for this SSL connection. */
175: public String getClientCertificateAlias() {
176: return this .clientCertAlias;
177: }
178:
179: /** Invoke HTTP request GET. */
180: public String get() throws HttpClientException {
181: return sendHttpRequest("get");
182: }
183:
184: /** Invoke HTTP request GET. */
185: public InputStream getStream() throws HttpClientException {
186: return sendHttpRequestStream("get");
187: }
188:
189: /** Invoke HTTP request POST. */
190: public String post() throws HttpClientException {
191: return sendHttpRequest("post");
192: }
193:
194: /** Invoke HTTP request POST and pass raw stream. */
195: public String post(String stream) throws HttpClientException {
196: this .rawStream = stream;
197: return sendHttpRequest("post");
198: }
199:
200: /** Invoke HTTP request POST. */
201: public InputStream postStream() throws HttpClientException {
202: return sendHttpRequestStream("post");
203: }
204:
205: /** Returns the value of the specified named response header field. */
206: public String getResponseHeader(String header)
207: throws HttpClientException {
208: if (con == null) {
209: throw new HttpClientException(
210: "Connection not yet established");
211: }
212: return con.getHeaderField(header);
213: }
214:
215: /** Returns the key for the nth response header field. */
216: public String getResponseHeaderFieldKey(int n)
217: throws HttpClientException {
218: if (con == null) {
219: throw new HttpClientException(
220: "Connection not yet established");
221: }
222: return con.getHeaderFieldKey(n);
223: }
224:
225: /** Returns the value for the nth response header field. It returns null of there are fewer then n fields. */
226: public String getResponseHeaderField(int n)
227: throws HttpClientException {
228: if (con == null) {
229: throw new HttpClientException(
230: "Connection not yet established");
231: }
232: return con.getHeaderField(n);
233: }
234:
235: /** Returns the content of the response. */
236: public Object getResponseContent() throws java.io.IOException,
237: HttpClientException {
238: if (con == null) {
239: throw new HttpClientException(
240: "Connection not yet established");
241: }
242: return con.getContent();
243: }
244:
245: /** Returns the content-type of the response. */
246: public String getResponseContentType() throws HttpClientException {
247: if (con == null) {
248: throw new HttpClientException(
249: "Connection not yet established");
250: }
251: return con.getContentType();
252: }
253:
254: /** Returns the content length of the response */
255: public int getResponseContentLength() throws HttpClientException {
256: if (con == null) {
257: throw new HttpClientException(
258: "Connection not yet established");
259: }
260: return con.getContentLength();
261: }
262:
263: /** Returns the content encoding of the response. */
264: public String getResponseContentEncoding()
265: throws HttpClientException {
266: if (con == null) {
267: throw new HttpClientException(
268: "Connection not yet established");
269: }
270: return con.getContentEncoding();
271: }
272:
273: public int getResponseCode() throws HttpClientException {
274: if (con == null) {
275: throw new HttpClientException(
276: "Connection not yet established");
277: }
278: if (!(con instanceof HttpURLConnection)) {
279: throw new HttpClientException(
280: "Connection is not HTTP; no response code");
281: }
282:
283: try {
284: return ((HttpURLConnection) con).getResponseCode();
285: } catch (IOException e) {
286: throw new HttpClientException(e.getMessage(), e);
287: }
288: }
289:
290: private String sendHttpRequest(String method)
291: throws HttpClientException {
292: InputStream in = sendHttpRequestStream(method);
293: if (in == null)
294: return null;
295:
296: StringBuffer buf = new StringBuffer();
297: try {
298: if (Debug.verboseOn() || debug) {
299: try {
300: Debug.log("ContentEncoding: "
301: + con.getContentEncoding()
302: + "; ContentType: "
303: + con.getContentType()
304: + " or: "
305: + URLConnection
306: .guessContentTypeFromStream(in),
307: module);
308: } catch (IOException ioe) {
309: Debug
310: .logWarning(
311: ioe,
312: "Caught exception printing content debugging information",
313: module);
314: }
315: }
316:
317: String charset = null;
318: String contentType = con.getContentType();
319: if (contentType == null) {
320: try {
321: contentType = URLConnection
322: .guessContentTypeFromStream(in);
323: } catch (IOException ioe) {
324: Debug
325: .logWarning(
326: ioe,
327: "Problems guessing content type from steam",
328: module);
329: }
330: }
331:
332: if (Debug.verboseOn() || debug)
333: Debug.log("Content-Type: " + contentType, module);
334:
335: if (contentType != null) {
336: contentType = contentType.toUpperCase();
337: int charsetEqualsLoc = contentType.indexOf("=",
338: contentType.indexOf("CHARSET"));
339: int afterSemiColon = contentType.indexOf(";",
340: charsetEqualsLoc);
341: if (charsetEqualsLoc >= 0 && afterSemiColon >= 0) {
342: charset = contentType.substring(
343: charsetEqualsLoc + 1, afterSemiColon);
344: } else if (charsetEqualsLoc >= 0) {
345: charset = contentType
346: .substring(charsetEqualsLoc + 1);
347: }
348:
349: if (charset != null)
350: charset = charset.trim();
351: if (Debug.verboseOn() || debug)
352: Debug.log(
353: "Getting text from HttpClient with charset: "
354: + charset, module);
355: }
356:
357: BufferedReader post = new BufferedReader(
358: charset == null ? new InputStreamReader(in)
359: : new InputStreamReader(in, charset));
360: String line = new String();
361:
362: if (Debug.verboseOn() || debug)
363: Debug.log("---- HttpClient Response Content ----",
364: module);
365: while ((line = post.readLine()) != null) {
366: if (Debug.verboseOn() || debug)
367: Debug.log("[HttpClient] : " + line, module);
368: buf.append(line);
369: if (lineFeed) {
370: buf.append("\n");
371: }
372: }
373: } catch (Exception e) {
374: throw new HttpClientException(
375: "Error processing input stream", e);
376: }
377: return buf.toString();
378: }
379:
380: private InputStream sendHttpRequestStream(String method)
381: throws HttpClientException {
382: // setup some SSL variables
383: SSLUtil.loadJsseProperties();
384:
385: String arguments = null;
386: InputStream in = null;
387:
388: if (url == null) {
389: throw new HttpClientException("Cannot process a null URL.");
390: }
391:
392: if (rawStream != null) {
393: arguments = rawStream;
394: } else if (parameters != null && parameters.size() > 0) {
395: arguments = UtilHttp.urlEncodeArgs(parameters, false);
396: }
397:
398: // Append the arguments to the query string if GET.
399: if (method.equalsIgnoreCase("get") && arguments != null) {
400: url = url + "?" + arguments;
401: }
402:
403: // Create the URL and open the connection.
404: try {
405: requestUrl = new URL(url);
406: con = URLConnector.openConnection(requestUrl, timeout,
407: clientCertAlias, SSLUtil.HOSTCERT_NORMAL_CHECK);
408: if (Debug.verboseOn() || debug)
409: Debug.log("Connection opened to : "
410: + requestUrl.toExternalForm(), module);
411:
412: if ((con instanceof HttpURLConnection)) {
413: ((HttpURLConnection) con)
414: .setInstanceFollowRedirects(followRedirects);
415: if (Debug.verboseOn() || debug)
416: Debug.log(
417: "Connection is of type HttpURLConnection",
418: module);
419: }
420:
421: con.setDoOutput(true);
422: con.setUseCaches(false);
423: if (Debug.verboseOn() || debug)
424: Debug.log("Do Input = true / Use Caches = false",
425: module);
426:
427: if (method.equalsIgnoreCase("post")) {
428: con.setRequestProperty("Content-type",
429: "application/x-www-form-urlencoded");
430: con.setDoInput(true);
431: if (Debug.verboseOn() || debug)
432: Debug
433: .log(
434: "Set content type to : application/x-www-form-urlencoded",
435: module);
436: }
437:
438: if (headers != null && headers.size() > 0) {
439: Set headerSet = headers.keySet();
440: Iterator i = headerSet.iterator();
441:
442: while (i.hasNext()) {
443: String headerName = (String) i.next();
444: String headerValue = (String) headers
445: .get(headerName);
446: con.setRequestProperty(headerName, headerValue);
447: if (Debug.verboseOn() || debug)
448: Debug.log("Header : " + headerName + " -> "
449: + headerValue, module);
450: }
451: } else {
452: if (Debug.verboseOn() || debug)
453: Debug.log("No headers to set", module);
454: }
455:
456: if (method.equalsIgnoreCase("post")) {
457: DataOutputStream out = new DataOutputStream(con
458: .getOutputStream());
459: if (Debug.verboseOn() || debug)
460: Debug.log("Opened output stream", module);
461:
462: if (arguments != null) {
463: out.writeBytes(arguments);
464: if (Debug.verboseOn() || debug)
465: Debug.log("Wrote arguements (parameters) : "
466: + arguments, module);
467: }
468:
469: out.flush();
470: out.close();
471: if (Debug.verboseOn() || debug)
472: Debug.log("Flushed and closed buffer", module);
473: }
474:
475: if (Debug.verboseOn() || debug) {
476: Map headerFields = con.getHeaderFields();
477: Debug.log("Header Fields : " + headerFields, module);
478: }
479:
480: in = con.getInputStream();
481: } catch (IOException ioe) {
482: throw new HttpClientException(
483: "IO Error processing request", ioe);
484: } catch (Exception e) {
485: throw new HttpClientException("Error processing request", e);
486: }
487:
488: return in;
489: }
490:
491: public static String getUrlContent(String url)
492: throws HttpClientException {
493: HttpClient client = new HttpClient(url);
494: return client.get();
495: }
496:
497: public static int checkHttpRequest(String url)
498: throws HttpClientException {
499: HttpClient client = new HttpClient(url);
500: client.get();
501: return client.getResponseCode();
502: }
503: }
|