1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.util;
16  
17  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.servlet.HttpHeaders;
21  import com.liferay.portal.kernel.util.ContentTypes;
22  import com.liferay.portal.kernel.util.FileUtil;
23  import com.liferay.portal.kernel.util.GetterUtil;
24  import com.liferay.portal.kernel.util.Http;
25  import com.liferay.portal.kernel.util.HttpUtil;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.util.Validator;
30  import com.liferay.util.SystemProperties;
31  
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.UnsupportedEncodingException;
35  
36  import java.net.InetAddress;
37  import java.net.URL;
38  import java.net.URLConnection;
39  import java.net.URLDecoder;
40  import java.net.URLEncoder;
41  
42  import java.util.ArrayList;
43  import java.util.Date;
44  import java.util.LinkedHashMap;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.StringTokenizer;
48  import java.util.regex.Pattern;
49  
50  import javax.portlet.ActionRequest;
51  import javax.portlet.RenderRequest;
52  
53  import javax.servlet.http.Cookie;
54  import javax.servlet.http.HttpServletRequest;
55  
56  import org.apache.commons.httpclient.Credentials;
57  import org.apache.commons.httpclient.Header;
58  import org.apache.commons.httpclient.HostConfiguration;
59  import org.apache.commons.httpclient.HttpClient;
60  import org.apache.commons.httpclient.HttpMethod;
61  import org.apache.commons.httpclient.HttpState;
62  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
63  import org.apache.commons.httpclient.NTCredentials;
64  import org.apache.commons.httpclient.NameValuePair;
65  import org.apache.commons.httpclient.URI;
66  import org.apache.commons.httpclient.UsernamePasswordCredentials;
67  import org.apache.commons.httpclient.auth.AuthPolicy;
68  import org.apache.commons.httpclient.auth.AuthScope;
69  import org.apache.commons.httpclient.cookie.CookiePolicy;
70  import org.apache.commons.httpclient.methods.DeleteMethod;
71  import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
72  import org.apache.commons.httpclient.methods.GetMethod;
73  import org.apache.commons.httpclient.methods.HeadMethod;
74  import org.apache.commons.httpclient.methods.PostMethod;
75  import org.apache.commons.httpclient.methods.PutMethod;
76  import org.apache.commons.httpclient.methods.RequestEntity;
77  import org.apache.commons.httpclient.methods.StringRequestEntity;
78  import org.apache.commons.httpclient.params.HttpClientParams;
79  import org.apache.commons.httpclient.params.HttpConnectionParams;
80  
81  /**
82   * <a href="HttpImpl.java.html"><b><i>View Source</i></b></a>
83   *
84   * @author Brian Wing Shun Chan
85   */
86  public class HttpImpl implements Http {
87  
88      public HttpImpl() {
89  
90          // Mimic behavior found in
91          // http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html
92  
93          if (Validator.isNotNull(_NON_PROXY_HOSTS)) {
94              String nonProxyHostsRegEx = _NON_PROXY_HOSTS;
95  
96              nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll(
97                  "\\.", "\\\\.");
98              nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll(
99                  "\\*", ".*?");
100             nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll(
101                 "\\|", ")|(");
102 
103             nonProxyHostsRegEx = "(" + nonProxyHostsRegEx + ")";
104 
105             _nonProxyHostsPattern = Pattern.compile(nonProxyHostsRegEx);
106         }
107 
108         MultiThreadedHttpConnectionManager httpConnectionManager =
109             new MultiThreadedHttpConnectionManager();
110 
111         HttpConnectionParams params = httpConnectionManager.getParams();
112 
113         params.setParameter(
114             "maxConnectionsPerHost", new Integer(_MAX_CONNECTIONS_PER_HOST));
115         params.setParameter(
116             "maxTotalConnections", new Integer(_MAX_TOTAL_CONNECTIONS));
117         params.setConnectionTimeout(_TIMEOUT);
118         params.setSoTimeout(_TIMEOUT);
119 
120         _client.setHttpConnectionManager(httpConnectionManager);
121         _proxyClient.setHttpConnectionManager(httpConnectionManager);
122 
123         if (hasProxyConfig() && Validator.isNotNull(_PROXY_USERNAME)) {
124             if (_PROXY_AUTH_TYPE.equals("username-password")) {
125                 _proxyCredentials = new UsernamePasswordCredentials(
126                     _PROXY_USERNAME, _PROXY_PASSWORD);
127             }
128             else if (_PROXY_AUTH_TYPE.equals("ntlm")) {
129                 _proxyCredentials = new NTCredentials(
130                     _PROXY_USERNAME, _PROXY_PASSWORD, _PROXY_NTLM_HOST,
131                     _PROXY_NTLM_DOMAIN);
132 
133                 List<String> authPrefs = new ArrayList<String>();
134 
135                 authPrefs.add(AuthPolicy.NTLM);
136                 authPrefs.add(AuthPolicy.BASIC);
137                 authPrefs.add(AuthPolicy.DIGEST);
138 
139                 _proxyClient.getParams().setParameter(
140                     AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
141             }
142         }
143     }
144 
145     public String addParameter(String url, String name, boolean value) {
146         return addParameter(url, name, String.valueOf(value));
147     }
148 
149     public String addParameter(String url, String name, double value) {
150         return addParameter(url, name, String.valueOf(value));
151     }
152 
153     public String addParameter(String url, String name, int value) {
154         return addParameter(url, name, String.valueOf(value));
155     }
156 
157     public String addParameter(String url, String name, long value) {
158         return addParameter(url, name, String.valueOf(value));
159     }
160 
161     public String addParameter(String url, String name, short value) {
162         return addParameter(url, name, String.valueOf(value));
163     }
164 
165     public String addParameter(String url, String name, String value) {
166         if (url == null) {
167             return null;
168         }
169 
170         String anchor = StringPool.BLANK;
171 
172         int pos = url.indexOf(StringPool.POUND);
173 
174         if (pos != -1) {
175             anchor = url.substring(pos);
176             url = url.substring(0, pos);
177         }
178 
179         if (url.indexOf(StringPool.QUESTION) == -1) {
180             url += StringPool.QUESTION;
181         }
182 
183         if (!url.endsWith(StringPool.QUESTION) &&
184             !url.endsWith(StringPool.AMPERSAND)) {
185 
186             url += StringPool.AMPERSAND;
187         }
188 
189         return url + name + StringPool.EQUAL + encodeURL(value) + anchor;
190     }
191 
192     public String decodePath(String path) {
193         path =  StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
194         path = HttpUtil.decodeURL(path, true);
195         path =  StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
196 
197         return path;
198     }
199 
200     public String decodeURL(String url) {
201         return decodeURL(url, false);
202     }
203 
204     public String decodeURL(String url, boolean unescapeSpace) {
205         if (url == null) {
206             return null;
207         }
208 
209         if (url.length() == 0) {
210             return StringPool.BLANK;
211         }
212 
213         try {
214             url = URLDecoder.decode(url, StringPool.UTF8);
215 
216             if (unescapeSpace) {
217                 url = StringUtil.replace(url, "%20", StringPool.PLUS);
218             }
219 
220             return url;
221         }
222         catch (UnsupportedEncodingException uee) {
223             _log.error(uee, uee);
224 
225             return StringPool.BLANK;
226         }
227     }
228 
229     public void destroy() {
230         MultiThreadedHttpConnectionManager.shutdownAll();
231     }
232 
233     public String encodePath(String path) {
234         path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
235         path = HttpUtil.encodeURL(path, true);
236         path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
237 
238         return path;
239     }
240 
241     public String encodeURL(String url) {
242         return encodeURL(url, false);
243     }
244 
245     public String encodeURL(String url, boolean escapeSpaces) {
246         if (url == null) {
247             return null;
248         }
249 
250         if (url.length() == 0) {
251             return StringPool.BLANK;
252         }
253 
254         try {
255             url = URLEncoder.encode(url, StringPool.UTF8);
256 
257             if (escapeSpaces) {
258                 url = StringUtil.replace(url, StringPool.PLUS, "%20");
259             }
260 
261             return url;
262         }
263         catch (UnsupportedEncodingException uee) {
264             _log.error(uee, uee);
265 
266             return StringPool.BLANK;
267         }
268     }
269 
270     public String fixPath(String path) {
271         return fixPath(path, true, true);
272     }
273 
274     public String fixPath(String path, boolean leading, boolean trailing) {
275         if (path == null) {
276             return StringPool.BLANK;
277         }
278 
279         if (leading) {
280             path = path.replaceAll("^/+", StringPool.BLANK);
281         }
282 
283         if (trailing) {
284             path = path.replaceAll("/+$", StringPool.BLANK);
285         }
286 
287         return path;
288     }
289 
290     public HttpClient getClient(HostConfiguration hostConfig) {
291         if (isProxyHost(hostConfig.getHost())) {
292             return _proxyClient;
293         }
294         else {
295             return _client;
296         }
297     }
298 
299     public String getCompleteURL(HttpServletRequest request) {
300         StringBuffer sb = request.getRequestURL();
301 
302         if (sb == null) {
303             sb = new StringBuffer();
304         }
305 
306         if (request.getQueryString() != null) {
307             sb.append(StringPool.QUESTION);
308             sb.append(request.getQueryString());
309         }
310 
311         String completeURL = sb.toString();
312 
313         if (_log.isWarnEnabled()) {
314             if (completeURL.contains("?&")) {
315                 _log.warn("Invalid url " + completeURL);
316             }
317         }
318 
319         return completeURL;
320     }
321 
322     public Cookie[] getCookies() {
323         return _cookies.get();
324     }
325 
326     public String getDomain(String url) {
327         url = removeProtocol(url);
328 
329         int pos = url.indexOf(StringPool.SLASH);
330 
331         if (pos != -1) {
332             return url.substring(0, pos);
333         }
334         else {
335             return url;
336         }
337     }
338 
339     public HostConfiguration getHostConfig(String location) throws IOException {
340         if (_log.isDebugEnabled()) {
341             _log.debug("Location is " + location);
342         }
343 
344         HostConfiguration hostConfig = new HostConfiguration();
345 
346         hostConfig.setHost(new URI(location, false));
347 
348         if (isProxyHost(hostConfig.getHost())) {
349             hostConfig.setProxy(_PROXY_HOST, _PROXY_PORT);
350         }
351 
352         return hostConfig;
353     }
354 
355     public String getIpAddress(String url) {
356         try {
357             URL urlObj = new URL(url);
358 
359             InetAddress address = InetAddress.getByName(urlObj.getHost());
360 
361             return address.getHostAddress();
362         }
363         catch (Exception e) {
364             return url;
365         }
366     }
367 
368     public String getParameter(String url, String name) {
369         return getParameter(url, name, true);
370     }
371 
372     public String getParameter(String url, String name, boolean escaped) {
373         if (Validator.isNull(url) || Validator.isNull(name)) {
374             return StringPool.BLANK;
375         }
376 
377         String[] parts = StringUtil.split(url, StringPool.QUESTION);
378 
379         if (parts.length == 2) {
380             String[] params = null;
381 
382             if (escaped) {
383                 params = StringUtil.split(parts[1], "&amp;");
384             }
385             else {
386                 params = StringUtil.split(parts[1], StringPool.AMPERSAND);
387             }
388 
389             for (int i = 0; i < params.length; i++) {
390                 String[] kvp = StringUtil.split(params[i], StringPool.EQUAL);
391 
392                 if ((kvp.length == 2) && kvp[0].equals(name)) {
393                     return kvp[1];
394                 }
395             }
396         }
397 
398         return StringPool.BLANK;
399     }
400 
401     public Map<String, String[]> getParameterMap(String queryString) {
402         return parameterMapFromString(queryString);
403     }
404 
405     public String getProtocol(ActionRequest actionRequest) {
406         return getProtocol(actionRequest.isSecure());
407     }
408 
409     public String getProtocol(boolean secure) {
410         if (!secure) {
411             return Http.HTTP;
412         }
413         else {
414             return Http.HTTPS;
415         }
416     }
417 
418     public String getProtocol(HttpServletRequest request) {
419         return getProtocol(request.isSecure());
420     }
421 
422     public String getProtocol(RenderRequest renderRequest) {
423         return getProtocol(renderRequest.isSecure());
424     }
425 
426     public String getProtocol(String url) {
427         int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
428 
429         if (pos != -1) {
430             return url.substring(0, pos);
431         }
432         else {
433             return Http.HTTP;
434         }
435     }
436 
437     public String getQueryString(String url) {
438         if (Validator.isNull(url)) {
439             return url;
440         }
441 
442         int pos = url.indexOf(StringPool.QUESTION);
443 
444         if (pos == -1) {
445             return StringPool.BLANK;
446         }
447         else {
448             return url.substring(pos + 1, url.length());
449         }
450     }
451 
452     public String getRequestURL(HttpServletRequest request) {
453         return request.getRequestURL().toString();
454     }
455 
456     public boolean hasDomain(String url) {
457         return Validator.isNotNull(getDomain(url));
458     }
459 
460     public boolean hasProtocol(String url) {
461         int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
462 
463         if (pos != -1) {
464             return true;
465         }
466         else {
467             return false;
468         }
469     }
470 
471     public boolean hasProxyConfig() {
472         if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
473             return true;
474         }
475         else {
476             return false;
477         }
478     }
479 
480     public boolean isNonProxyHost(String host) {
481         if (_nonProxyHostsPattern == null ||
482             _nonProxyHostsPattern.matcher(host).matches()) {
483 
484             return true;
485         }
486         else {
487             return false;
488         }
489     }
490 
491     public boolean isProxyHost(String host) {
492         if (hasProxyConfig() && !isNonProxyHost(host)) {
493             return true;
494         }
495         else {
496             return false;
497         }
498     }
499 
500     public Map<String, String[]> parameterMapFromString(String queryString) {
501         Map<String, String[]> parameterMap =
502             new LinkedHashMap<String, String[]>();
503 
504         if (Validator.isNull(queryString)) {
505             return parameterMap;
506         }
507 
508         Map<String, List<String>> tempParameterMap =
509             new LinkedHashMap<String, List<String>>();
510 
511         StringTokenizer st = new StringTokenizer(
512             queryString, StringPool.AMPERSAND);
513 
514         while (st.hasMoreTokens()) {
515             String token = st.nextToken();
516 
517             if (Validator.isNotNull(token)) {
518                 String[] kvp = StringUtil.split(token, StringPool.EQUAL);
519 
520                 String key = kvp[0];
521 
522                 String value = StringPool.BLANK;
523 
524                 if (kvp.length > 1) {
525                     value = kvp[1];
526                 }
527 
528                 List<String> values = tempParameterMap.get(key);
529 
530                 if (values == null) {
531                     values = new ArrayList<String>();
532 
533                     tempParameterMap.put(key, values);
534                 }
535 
536                 values.add(value);
537             }
538         }
539 
540         for (Map.Entry<String, List<String>> entry :
541                 tempParameterMap.entrySet()) {
542 
543             String key = entry.getKey();
544             List<String> values = entry.getValue();
545 
546             parameterMap.put(key, values.toArray(new String[values.size()]));
547         }
548 
549         return parameterMap;
550     }
551 
552     public String parameterMapToString(Map<String, String[]> parameterMap) {
553         return parameterMapToString(parameterMap, true);
554     }
555 
556     public String parameterMapToString(
557         Map<String, String[]> parameterMap, boolean addQuestion) {
558 
559         StringBundler sb = new StringBundler();
560 
561         if (parameterMap.size() > 0) {
562             if (addQuestion) {
563                 sb.append(StringPool.QUESTION);
564             }
565 
566             for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
567                 String name = entry.getKey();
568                 String[] values = entry.getValue();
569 
570                 for (String value : values) {
571                     sb.append(name);
572                     sb.append(StringPool.EQUAL);
573                     sb.append(encodeURL(value));
574                     sb.append(StringPool.AMPERSAND);
575                 }
576             }
577 
578             if (sb.index() > 1) {
579                 sb.setIndex(sb.index() - 1);
580             }
581         }
582 
583         return sb.toString();
584     }
585 
586     public String protocolize(String url, ActionRequest actionRequest) {
587         return protocolize(url, actionRequest.isSecure());
588     }
589 
590     public String protocolize(String url, boolean secure) {
591         if (secure) {
592             if (url.startsWith(Http.HTTP_WITH_SLASH)) {
593                 return StringUtil.replace(
594                     url, Http.HTTP_WITH_SLASH, Http.HTTPS_WITH_SLASH);
595             }
596         }
597         else {
598             if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
599                 return StringUtil.replace(
600                     url, Http.HTTPS_WITH_SLASH, Http.HTTP_WITH_SLASH);
601             }
602         }
603 
604         return url;
605     }
606 
607     public String protocolize(String url, HttpServletRequest request) {
608         return protocolize(url, request.isSecure());
609     }
610 
611     public String protocolize(String url, RenderRequest renderRequest) {
612         return protocolize(url, renderRequest.isSecure());
613     }
614 
615     public String removeDomain(String url) {
616         url = removeProtocol(url);
617 
618         int pos = url.indexOf(StringPool.SLASH);
619 
620         if (pos > 0) {
621             return url.substring(pos);
622         }
623         else {
624             return url;
625         }
626     }
627 
628     public String removeParameter(String url, String name) {
629         int pos = url.indexOf(StringPool.QUESTION);
630 
631         if (pos == -1) {
632             return url;
633         }
634 
635         String anchor = StringPool.BLANK;
636 
637         int anchorPos = url.indexOf(StringPool.POUND);
638 
639         if (anchorPos != -1) {
640             anchor = url.substring(anchorPos);
641             url = url.substring(0, anchorPos);
642         }
643 
644         StringBundler sb = new StringBundler();
645 
646         sb.append(url.substring(0, pos + 1));
647 
648         StringTokenizer st = new StringTokenizer(
649             url.substring(pos + 1, url.length()), StringPool.AMPERSAND);
650 
651         while (st.hasMoreTokens()) {
652             String token = st.nextToken();
653 
654             if (Validator.isNotNull(token)) {
655                 String[] kvp = StringUtil.split(token, StringPool.EQUAL);
656 
657                 String key = kvp[0];
658 
659                 String value = StringPool.BLANK;
660 
661                 if (kvp.length > 1) {
662                     value = kvp[1];
663                 }
664 
665                 if (!key.equals(name)) {
666                     sb.append(key);
667                     sb.append(StringPool.EQUAL);
668                     sb.append(value);
669                     sb.append(StringPool.AMPERSAND);
670                 }
671             }
672         }
673 
674         url = StringUtil.replace(
675             sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
676             StringPool.AMPERSAND);
677 
678         if (url.endsWith(StringPool.AMPERSAND)) {
679             url = url.substring(0, url.length() - 1);
680         }
681 
682         if (url.endsWith(StringPool.QUESTION)) {
683             url = url.substring(0, url.length() - 1);
684         }
685 
686         return url + anchor;
687     }
688 
689     public String removeProtocol(String url) {
690         if (url.startsWith(Http.HTTP_WITH_SLASH)) {
691             return url.substring(Http.HTTP_WITH_SLASH.length() , url.length());
692         }
693         else if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
694             return url.substring(Http.HTTPS_WITH_SLASH.length() , url.length());
695         }
696         else {
697             return url;
698         }
699     }
700 
701     public String setParameter(String url, String name, boolean value) {
702         return setParameter(url, name, String.valueOf(value));
703     }
704 
705     public String setParameter(String url, String name, double value) {
706         return setParameter(url, name, String.valueOf(value));
707     }
708 
709     public String setParameter(String url, String name, int value) {
710         return setParameter(url, name, String.valueOf(value));
711     }
712 
713     public String setParameter(String url, String name, long value) {
714         return setParameter(url, name, String.valueOf(value));
715     }
716 
717     public String setParameter(String url, String name, short value) {
718         return setParameter(url, name, String.valueOf(value));
719     }
720 
721     public String setParameter(String url, String name, String value) {
722         if (url == null) {
723             return null;
724         }
725 
726         url = removeParameter(url, name);
727 
728         return addParameter(url, name, value);
729     }
730 
731     public byte[] URLtoByteArray(Http.Options options) throws IOException {
732         return URLtoByteArray(
733             options.getLocation(), options.getMethod(), options.getHeaders(),
734             options.getCookies(), options.getAuth(), options.getBody(),
735             options.getParts(), options.getResponse(),
736             options.isFollowRedirects());
737     }
738 
739     public byte[] URLtoByteArray(String location) throws IOException {
740         Http.Options options = new Http.Options();
741 
742         options.setLocation(location);
743 
744         return URLtoByteArray(options);
745     }
746 
747     public byte[] URLtoByteArray(String location, boolean post)
748         throws IOException {
749 
750         Http.Options options = new Http.Options();
751 
752         options.setLocation(location);
753         options.setPost(post);
754 
755         return URLtoByteArray(options);
756     }
757 
758     public String URLtoString(Http.Options options) throws IOException {
759         return new String(URLtoByteArray(options));
760     }
761 
762     public String URLtoString(String location) throws IOException {
763         return new String(URLtoByteArray(location));
764     }
765 
766     public String URLtoString(String location, boolean post)
767         throws IOException {
768 
769         return new String(URLtoByteArray(location, post));
770     }
771 
772     /**
773      * This method only uses the default Commons HttpClient implementation when
774      * the URL object represents a HTTP resource. The URL object could also
775      * represent a file or some JNDI resource. In that case, the default Java
776      * implementation is used.
777      *
778      * @return A string representation of the resource referenced by the URL
779      *         object
780      */
781     public String URLtoString(URL url) throws IOException {
782         String xml = null;
783 
784         if (url != null) {
785             String protocol = url.getProtocol().toLowerCase();
786 
787             if (protocol.startsWith(Http.HTTP) ||
788                 protocol.startsWith(Http.HTTPS)) {
789 
790                 return URLtoString(url.toString());
791             }
792 
793             URLConnection con = url.openConnection();
794 
795             InputStream is = con.getInputStream();
796 
797             UnsyncByteArrayOutputStream ubaos =
798                 new UnsyncByteArrayOutputStream();
799             byte[] bytes = new byte[512];
800 
801             for (int i = is.read(bytes, 0, 512); i != -1;
802                     i = is.read(bytes, 0, 512)) {
803 
804                 ubaos.write(bytes, 0, i);
805             }
806 
807             xml = new String(ubaos.unsafeGetByteArray(), 0, ubaos.size());
808 
809             is.close();
810             ubaos.close();
811         }
812 
813         return xml;
814     }
815 
816     protected void proxifyState(HttpState state, HostConfiguration hostConfig) {
817         Credentials proxyCredentials = _proxyCredentials;
818 
819         String host = hostConfig.getHost();
820 
821         if (isProxyHost(host) && (proxyCredentials != null)) {
822             AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
823 
824             state.setProxyCredentials(scope, proxyCredentials);
825         }
826     }
827 
828     protected org.apache.commons.httpclient.Cookie toCommonsCookie(
829         Cookie cookie) {
830 
831         org.apache.commons.httpclient.Cookie commonsCookie =
832             new org.apache.commons.httpclient.Cookie(
833             cookie.getDomain(), cookie.getName(), cookie.getValue(),
834             cookie.getPath(), cookie.getMaxAge(), cookie.getSecure());
835 
836         commonsCookie.setVersion(cookie.getVersion());
837 
838         return commonsCookie;
839     }
840 
841     protected org.apache.commons.httpclient.Cookie[] toCommonsCookies(
842         Cookie[] cookies) {
843 
844         if (cookies == null) {
845             return null;
846         }
847 
848         org.apache.commons.httpclient.Cookie[] commonCookies =
849             new org.apache.commons.httpclient.Cookie[cookies.length];
850 
851         for (int i = 0; i < cookies.length; i++) {
852             commonCookies[i] = toCommonsCookie(cookies[i]);
853         }
854 
855         return commonCookies;
856     }
857 
858     protected Cookie toServletCookie(
859         org.apache.commons.httpclient.Cookie commonsCookie) {
860 
861         Cookie cookie = new Cookie(
862             commonsCookie.getName(), commonsCookie.getValue());
863 
864         cookie.setDomain(commonsCookie.getDomain());
865 
866         Date expiryDate = commonsCookie.getExpiryDate();
867 
868         if (expiryDate != null) {
869             int maxAge =
870                 (int)(expiryDate.getTime() - System.currentTimeMillis());
871 
872             maxAge = maxAge / 1000;
873 
874             if (maxAge > -1) {
875                 cookie.setMaxAge(maxAge);
876             }
877         }
878 
879         cookie.setPath(commonsCookie.getPath());
880         cookie.setSecure(commonsCookie.getSecure());
881         cookie.setVersion(commonsCookie.getVersion());
882 
883         return cookie;
884     }
885 
886     protected Cookie[] toServletCookies(
887         org.apache.commons.httpclient.Cookie[] commonsCookies) {
888 
889         if (commonsCookies == null) {
890             return null;
891         }
892 
893         Cookie[] cookies = new Cookie[commonsCookies.length];
894 
895         for (int i = 0; i < commonsCookies.length; i++) {
896             cookies[i] = toServletCookie(commonsCookies[i]);
897         }
898 
899         return cookies;
900     }
901 
902     protected byte[] URLtoByteArray(
903             String location, Http.Method method, Map<String, String> headers,
904             Cookie[] cookies, Http.Auth auth, Http.Body body, Map<String,
905             String> parts, Http.Response response, boolean followRedirects)
906         throws IOException {
907 
908         byte[] bytes = null;
909 
910         HttpMethod httpMethod = null;
911         HttpState httpState = null;
912 
913         try {
914             _cookies.set(null);
915 
916             if (location == null) {
917                 return bytes;
918             }
919             else if (!location.startsWith(Http.HTTP_WITH_SLASH) &&
920                      !location.startsWith(Http.HTTPS_WITH_SLASH)) {
921 
922                 location = Http.HTTP_WITH_SLASH + location;
923             }
924 
925             HostConfiguration hostConfig = getHostConfig(location);
926 
927             HttpClient httpClient = getClient(hostConfig);
928 
929             if ((method == Http.Method.POST) ||
930                 (method == Http.Method.PUT)) {
931 
932                 if (method == Http.Method.POST) {
933                     httpMethod = new PostMethod(location);
934                 }
935                 else {
936                     httpMethod = new PutMethod(location);
937                 }
938 
939                 if (body != null) {
940                     RequestEntity requestEntity = new StringRequestEntity(
941                         body.getContent(), body.getContentType(),
942                         body.getCharset());
943 
944                     EntityEnclosingMethod entityEnclosingMethod =
945                         (EntityEnclosingMethod)httpMethod;
946 
947                     entityEnclosingMethod.setRequestEntity(requestEntity);
948                 }
949                 else if ((parts != null) && (parts.size() > 0) &&
950                          (method == Http.Method.POST)) {
951 
952                     List<NameValuePair> nvpList =
953                         new ArrayList<NameValuePair>();
954 
955                     for (Map.Entry<String, String> entry : parts.entrySet()) {
956                         String key = entry.getKey();
957                         String value = entry.getValue();
958 
959                         if (value != null) {
960                             nvpList.add(new NameValuePair(key, value));
961                         }
962                     }
963 
964                     NameValuePair[] nvpArray = nvpList.toArray(
965                         new NameValuePair[nvpList.size()]);
966 
967                     PostMethod postMethod = (PostMethod)httpMethod;
968 
969                     postMethod.setRequestBody(nvpArray);
970                 }
971             }
972             else if (method == Http.Method.DELETE) {
973                 httpMethod = new DeleteMethod(location);
974             }
975             else if (method == Http.Method.HEAD) {
976                 httpMethod = new HeadMethod(location);
977             }
978             else {
979                 httpMethod = new GetMethod(location);
980             }
981 
982             if (headers != null) {
983                 for (Map.Entry<String, String> header : headers.entrySet()) {
984                     httpMethod.addRequestHeader(
985                         header.getKey(), header.getValue());
986                 }
987             }
988 
989             if ((method == Http.Method.POST) || (method == Http.Method.PUT) &&
990                 (body != null)) {
991             }
992             else if (!_hasRequestHeader(httpMethod, HttpHeaders.CONTENT_TYPE)) {
993                 httpMethod.addRequestHeader(
994                     HttpHeaders.CONTENT_TYPE,
995                     ContentTypes.APPLICATION_X_WWW_FORM_URLENCODED);
996             }
997 
998             if (!_hasRequestHeader(httpMethod, HttpHeaders.USER_AGENT)) {
999                 httpMethod.addRequestHeader(
1000                    HttpHeaders.USER_AGENT, _DEFAULT_USER_AGENT);
1001            }
1002
1003            httpMethod.getParams().setIntParameter(
1004                HttpClientParams.SO_TIMEOUT, 0);
1005
1006            httpState = new HttpState();
1007
1008            if ((cookies != null) && (cookies.length > 0)) {
1009                org.apache.commons.httpclient.Cookie[] commonsCookies =
1010                    toCommonsCookies(cookies);
1011
1012                httpState.addCookies(commonsCookies);
1013
1014                httpMethod.getParams().setCookiePolicy(
1015                    CookiePolicy.BROWSER_COMPATIBILITY);
1016            }
1017
1018            if (auth != null) {
1019                httpMethod.setDoAuthentication(true);
1020
1021                httpState.setCredentials(
1022                    new AuthScope(
1023                        auth.getHost(), auth.getPort(), auth.getRealm()),
1024                    new UsernamePasswordCredentials(
1025                        auth.getUsername(), auth.getPassword()));
1026            }
1027
1028            proxifyState(httpState, hostConfig);
1029
1030            httpClient.executeMethod(hostConfig, httpMethod, httpState);
1031
1032            Header locationHeader = httpMethod.getResponseHeader("location");
1033
1034            if ((locationHeader != null) && !locationHeader.equals(location)) {
1035                String redirect = locationHeader.getValue();
1036
1037                if (followRedirects) {
1038                    return URLtoByteArray(
1039                        redirect, Http.Method.GET, headers,
1040                        cookies, auth, body, parts, response, followRedirects);
1041                }
1042                else {
1043                    response.setRedirect(redirect);
1044                }
1045            }
1046
1047            InputStream is = httpMethod.getResponseBodyAsStream();
1048
1049            if (is != null) {
1050                Header contentLength = httpMethod.getResponseHeader(
1051                    HttpHeaders.CONTENT_LENGTH);
1052
1053                if (contentLength != null) {
1054                    response.setContentLength(
1055                        GetterUtil.getInteger(contentLength.getValue()));
1056                }
1057
1058                Header contentType = httpMethod.getResponseHeader(
1059                    HttpHeaders.CONTENT_TYPE);
1060
1061                if (contentType != null) {
1062                    response.setContentType(contentType.getValue());
1063                }
1064
1065                bytes = FileUtil.getBytes(is);
1066
1067                is.close();
1068            }
1069
1070            for (Header header : httpMethod.getResponseHeaders()) {
1071                response.addHeader(header.getName(), header.getValue());
1072            }
1073
1074            return bytes;
1075        }
1076        finally {
1077            try {
1078                if (httpState != null) {
1079                    _cookies.set(toServletCookies(httpState.getCookies()));
1080                }
1081            }
1082            catch (Exception e) {
1083                _log.error(e, e);
1084            }
1085
1086            try {
1087                if (httpMethod != null) {
1088                    httpMethod.releaseConnection();
1089                }
1090            }
1091            catch (Exception e) {
1092                _log.error(e, e);
1093            }
1094        }
1095    }
1096
1097    private boolean _hasRequestHeader(HttpMethod httpMethod, String name) {
1098        if (httpMethod.getRequestHeaders(name).length == 0) {
1099            return false;
1100        }
1101        else {
1102            return true;
1103        }
1104    }
1105
1106    private static final String _DEFAULT_USER_AGENT =
1107        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
1108
1109    private static final int _MAX_CONNECTIONS_PER_HOST = GetterUtil.getInteger(
1110        PropsUtil.get(HttpImpl.class.getName() + ".max.connections.per.host"),
1111        2);
1112
1113    private static final int _MAX_TOTAL_CONNECTIONS = GetterUtil.getInteger(
1114        PropsUtil.get(HttpImpl.class.getName() + ".max.total.connections"),
1115        20);
1116
1117    private static final String _NON_PROXY_HOSTS =
1118        SystemProperties.get("http.nonProxyHosts");
1119
1120    private static final String _PROXY_AUTH_TYPE = GetterUtil.getString(
1121        PropsUtil.get(HttpImpl.class.getName() + ".proxy.auth.type"));
1122
1123    private static final String _PROXY_HOST = GetterUtil.getString(
1124        SystemProperties.get("http.proxyHost"));
1125
1126    private static final String _PROXY_NTLM_DOMAIN = GetterUtil.getString(
1127        PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.domain"));
1128
1129    private static final String _PROXY_NTLM_HOST = GetterUtil.getString(
1130        PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.host"));
1131
1132    private static final String _PROXY_PASSWORD = GetterUtil.getString(
1133        PropsUtil.get(HttpImpl.class.getName() + ".proxy.password"));
1134
1135    private static final int _PROXY_PORT = GetterUtil.getInteger(
1136        SystemProperties.get("http.proxyPort"));
1137
1138    private static final String _PROXY_USERNAME = GetterUtil.getString(
1139        PropsUtil.get(HttpImpl.class.getName() + ".proxy.username"));
1140
1141    private static final String _TEMP_SLASH = "_LIFERAY_TEMP_SLASH_";
1142
1143    private static final int _TIMEOUT = GetterUtil.getInteger(
1144        PropsUtil.get(HttpImpl.class.getName() + ".timeout"), 5000);
1145
1146    private static Log _log = LogFactoryUtil.getLog(HttpImpl.class);
1147
1148    private static ThreadLocal<Cookie[]> _cookies = new ThreadLocal<Cookie[]>();
1149
1150    private HttpClient _client = new HttpClient();
1151    private Pattern _nonProxyHostsPattern;
1152    private HttpClient _proxyClient = new HttpClient();
1153    private Credentials _proxyCredentials;
1154
1155}