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