1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   * 
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 HttpClient getClient(HostConfiguration hostConfig) {
271         if (isProxyHost(hostConfig.getHost())) {
272             return _proxyClient;
273         }
274         else {
275             return _client;
276         }
277     }
278 
279     public String getCompleteURL(HttpServletRequest request) {
280         StringBuffer sb = request.getRequestURL();
281 
282         if (sb == null) {
283             sb = new StringBuffer();
284         }
285 
286         if (request.getQueryString() != null) {
287             sb.append(StringPool.QUESTION);
288             sb.append(request.getQueryString());
289         }
290 
291         String completeURL = sb.toString();
292 
293         if (_log.isWarnEnabled()) {
294             if (completeURL.contains("?&")) {
295                 _log.warn("Invalid url " + completeURL);
296             }
297         }
298 
299         return completeURL;
300     }
301 
302     public Cookie[] getCookies() {
303         return _cookies.get();
304     }
305 
306     public String getDomain(String url) {
307         url = removeProtocol(url);
308 
309         int pos = url.indexOf(StringPool.SLASH);
310 
311         if (pos != -1) {
312             return url.substring(0, pos);
313         }
314         else {
315             return url;
316         }
317     }
318 
319     public HostConfiguration getHostConfig(String location) throws IOException {
320         if (_log.isDebugEnabled()) {
321             _log.debug("Location is " + location);
322         }
323 
324         HostConfiguration hostConfig = new HostConfiguration();
325 
326         hostConfig.setHost(new URI(location, false));
327 
328         if (isProxyHost(hostConfig.getHost())) {
329             hostConfig.setProxy(_PROXY_HOST, _PROXY_PORT);
330         }
331 
332         return hostConfig;
333     }
334 
335     public String getIpAddress(String url) {
336         try {
337             URL urlObj = new URL(url);
338 
339             InetAddress address = InetAddress.getByName(urlObj.getHost());
340 
341             return address.getHostAddress();
342         }
343         catch (Exception e) {
344             return url;
345         }
346     }
347 
348     public String getParameter(String url, String name) {
349         return getParameter(url, name, true);
350     }
351 
352     public String getParameter(String url, String name, boolean escaped) {
353         if (Validator.isNull(url) || Validator.isNull(name)) {
354             return StringPool.BLANK;
355         }
356 
357         String[] parts = StringUtil.split(url, StringPool.QUESTION);
358 
359         if (parts.length == 2) {
360             String[] params = null;
361 
362             if (escaped) {
363                 params = StringUtil.split(parts[1], "&amp;");
364             }
365             else {
366                 params = StringUtil.split(parts[1], StringPool.AMPERSAND);
367             }
368 
369             for (int i = 0; i < params.length; i++) {
370                 String[] kvp = StringUtil.split(params[i], StringPool.EQUAL);
371 
372                 if ((kvp.length == 2) && kvp[0].equals(name)) {
373                     return kvp[1];
374                 }
375             }
376         }
377 
378         return StringPool.BLANK;
379     }
380 
381     public Map<String, String[]> getParameterMap(String queryString) {
382         return parameterMapFromString(queryString);
383     }
384 
385     public String getProtocol(ActionRequest actionRequest) {
386         return getProtocol(actionRequest.isSecure());
387     }
388 
389     public String getProtocol(boolean secure) {
390         if (!secure) {
391             return Http.HTTP;
392         }
393         else {
394             return Http.HTTPS;
395         }
396     }
397 
398     public String getProtocol(HttpServletRequest request) {
399         return getProtocol(request.isSecure());
400     }
401 
402     public String getProtocol(RenderRequest renderRequest) {
403         return getProtocol(renderRequest.isSecure());
404     }
405 
406     public String getProtocol(String url) {
407         int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
408 
409         if (pos != -1) {
410             return url.substring(0, pos);
411         }
412         else {
413             return Http.HTTP;
414         }
415     }
416 
417     public String getQueryString(String url) {
418         if (Validator.isNull(url)) {
419             return url;
420         }
421 
422         int pos = url.indexOf(StringPool.QUESTION);
423 
424         if (pos == -1) {
425             return StringPool.BLANK;
426         }
427         else {
428             return url.substring(pos + 1, url.length());
429         }
430     }
431 
432     public String getRequestURL(HttpServletRequest request) {
433         return request.getRequestURL().toString();
434     }
435 
436     public boolean hasDomain(String url) {
437         return Validator.isNotNull(getDomain(url));
438     }
439 
440     public boolean hasProtocol(String url) {
441         int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
442 
443         if (pos != -1) {
444             return true;
445         }
446         else {
447             return false;
448         }
449     }
450 
451     public boolean hasProxyConfig() {
452         if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
453             return true;
454         }
455         else {
456             return false;
457         }
458     }
459 
460     public boolean isNonProxyHost(String host) {
461         if (_nonProxyHostsPattern == null ||
462             _nonProxyHostsPattern.matcher(host).matches()) {
463 
464             return true;
465         }
466         else {
467             return false;
468         }
469     }
470 
471     public boolean isProxyHost(String host) {
472         if (hasProxyConfig() && !isNonProxyHost(host)) {
473             return true;
474         }
475         else {
476             return false;
477         }
478     }
479 
480     public Map<String, String[]> parameterMapFromString(String queryString) {
481         Map<String, String[]> parameterMap =
482             new LinkedHashMap<String, String[]>();
483 
484         if (Validator.isNull(queryString)) {
485             return parameterMap;
486         }
487 
488         Map<String, List<String>> tempParameterMap =
489             new LinkedHashMap<String, List<String>>();
490 
491         StringTokenizer st = new StringTokenizer(
492             queryString, StringPool.AMPERSAND);
493 
494         while (st.hasMoreTokens()) {
495             String token = st.nextToken();
496 
497             if (Validator.isNotNull(token)) {
498                 String[] kvp = StringUtil.split(token, StringPool.EQUAL);
499 
500                 String key = kvp[0];
501 
502                 String value = StringPool.BLANK;
503 
504                 if (kvp.length > 1) {
505                     value = kvp[1];
506                 }
507 
508                 List<String> values = tempParameterMap.get(key);
509 
510                 if (values == null) {
511                     values = new ArrayList<String>();
512 
513                     tempParameterMap.put(key, values);
514                 }
515 
516                 values.add(value);
517             }
518         }
519 
520         for (Map.Entry<String, List<String>> entry :
521                 tempParameterMap.entrySet()) {
522 
523             String key = entry.getKey();
524             List<String> values = entry.getValue();
525 
526             parameterMap.put(key, values.toArray(new String[values.size()]));
527         }
528 
529         return parameterMap;
530     }
531 
532     public String parameterMapToString(Map<String, String[]> parameterMap) {
533         return parameterMapToString(parameterMap, true);
534     }
535 
536     public String parameterMapToString(
537         Map<String, String[]> parameterMap, boolean addQuestion) {
538 
539         StringBundler sb = new StringBundler();
540 
541         if (parameterMap.size() > 0) {
542             if (addQuestion) {
543                 sb.append(StringPool.QUESTION);
544             }
545 
546             for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
547                 String name = entry.getKey();
548                 String[] values = entry.getValue();
549 
550                 for (String value : values) {
551                     sb.append(name);
552                     sb.append(StringPool.EQUAL);
553                     sb.append(encodeURL(value));
554                     sb.append(StringPool.AMPERSAND);
555                 }
556             }
557 
558             if (sb.index() > 1) {
559                 sb.setIndex(sb.index() - 1);
560             }
561         }
562 
563         return sb.toString();
564     }
565 
566     public String protocolize(String url, ActionRequest actionRequest) {
567         return protocolize(url, actionRequest.isSecure());
568     }
569 
570     public String protocolize(String url, boolean secure) {
571         if (secure) {
572             if (url.startsWith(Http.HTTP_WITH_SLASH)) {
573                 return StringUtil.replace(
574                     url, Http.HTTP_WITH_SLASH, Http.HTTPS_WITH_SLASH);
575             }
576         }
577         else {
578             if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
579                 return StringUtil.replace(
580                     url, Http.HTTPS_WITH_SLASH, Http.HTTP_WITH_SLASH);
581             }
582         }
583 
584         return url;
585     }
586 
587     public String protocolize(String url, HttpServletRequest request) {
588         return protocolize(url, request.isSecure());
589     }
590 
591     public String protocolize(String url, RenderRequest renderRequest) {
592         return protocolize(url, renderRequest.isSecure());
593     }
594 
595     public String removeDomain(String url) {
596         url = removeProtocol(url);
597 
598         int pos = url.indexOf(StringPool.SLASH);
599 
600         if (pos > 0) {
601             return url.substring(pos);
602         }
603         else {
604             return url;
605         }
606     }
607 
608     public String removeParameter(String url, String name) {
609         int pos = url.indexOf(StringPool.QUESTION);
610 
611         if (pos == -1) {
612             return url;
613         }
614 
615         String anchor = StringPool.BLANK;
616 
617         int anchorPos = url.indexOf(StringPool.POUND);
618 
619         if (anchorPos != -1) {
620             anchor = url.substring(anchorPos);
621             url = url.substring(0, anchorPos);
622         }
623 
624         StringBundler sb = new StringBundler();
625 
626         sb.append(url.substring(0, pos + 1));
627 
628         StringTokenizer st = new StringTokenizer(
629             url.substring(pos + 1, url.length()), StringPool.AMPERSAND);
630 
631         while (st.hasMoreTokens()) {
632             String token = st.nextToken();
633 
634             if (Validator.isNotNull(token)) {
635                 String[] kvp = StringUtil.split(token, StringPool.EQUAL);
636 
637                 String key = kvp[0];
638 
639                 String value = StringPool.BLANK;
640 
641                 if (kvp.length > 1) {
642                     value = kvp[1];
643                 }
644 
645                 if (!key.equals(name)) {
646                     sb.append(key);
647                     sb.append(StringPool.EQUAL);
648                     sb.append(value);
649                     sb.append(StringPool.AMPERSAND);
650                 }
651             }
652         }
653 
654         url = StringUtil.replace(
655             sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
656             StringPool.AMPERSAND);
657 
658         if (url.endsWith(StringPool.AMPERSAND)) {
659             url = url.substring(0, url.length() - 1);
660         }
661 
662         if (url.endsWith(StringPool.QUESTION)) {
663             url = url.substring(0, url.length() - 1);
664         }
665 
666         return url + anchor;
667     }
668 
669     public String removeProtocol(String url) {
670         if (url.startsWith(Http.HTTP_WITH_SLASH)) {
671             return url.substring(Http.HTTP_WITH_SLASH.length() , url.length());
672         }
673         else if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
674             return url.substring(Http.HTTPS_WITH_SLASH.length() , url.length());
675         }
676         else {
677             return url;
678         }
679     }
680 
681     public String setParameter(String url, String name, boolean value) {
682         return setParameter(url, name, String.valueOf(value));
683     }
684 
685     public String setParameter(String url, String name, double value) {
686         return setParameter(url, name, String.valueOf(value));
687     }
688 
689     public String setParameter(String url, String name, int value) {
690         return setParameter(url, name, String.valueOf(value));
691     }
692 
693     public String setParameter(String url, String name, long value) {
694         return setParameter(url, name, String.valueOf(value));
695     }
696 
697     public String setParameter(String url, String name, short value) {
698         return setParameter(url, name, String.valueOf(value));
699     }
700 
701     public String setParameter(String url, String name, String value) {
702         if (url == null) {
703             return null;
704         }
705 
706         url = removeParameter(url, name);
707 
708         return addParameter(url, name, value);
709     }
710 
711     public byte[] URLtoByteArray(Http.Options options) throws IOException {
712         return URLtoByteArray(
713             options.getLocation(), options.getMethod(), options.getHeaders(),
714             options.getCookies(), options.getAuth(), options.getBody(),
715             options.getParts(), options.getResponse(),
716             options.isFollowRedirects());
717     }
718 
719     public byte[] URLtoByteArray(String location) throws IOException {
720         Http.Options options = new Http.Options();
721 
722         options.setLocation(location);
723 
724         return URLtoByteArray(options);
725     }
726 
727     public byte[] URLtoByteArray(String location, boolean post)
728         throws IOException {
729 
730         Http.Options options = new Http.Options();
731 
732         options.setLocation(location);
733         options.setPost(post);
734 
735         return URLtoByteArray(options);
736     }
737 
738     /**
739      * @deprecated
740      */
741     public byte[] URLtoByteArray(
742             String location, Cookie[] cookies, Http.Auth auth, Http.Body body,
743             boolean post)
744         throws IOException {
745 
746         Http.Options options = new Http.Options();
747 
748         options.setAuth(auth);
749         options.setBody(body);
750         options.setCookies(cookies);
751         options.setLocation(location);
752         options.setPost(post);
753 
754         return URLtoByteArray(options);
755     }
756 
757     /**
758      * @deprecated
759      */
760     public byte[] URLtoByteArray(
761             String location, Cookie[] cookies, Http.Auth auth,
762             Map<String, String> parts, boolean post)
763         throws IOException {
764 
765         Http.Options options = new Http.Options();
766 
767         options.setAuth(auth);
768         options.setCookies(cookies);
769         options.setLocation(location);
770         options.setParts(parts);
771         options.setPost(post);
772 
773         return URLtoByteArray(options);
774     }
775 
776     public String URLtoString(Http.Options options) throws IOException {
777         return new String(URLtoByteArray(options));
778     }
779 
780     public String URLtoString(String location) throws IOException {
781         return new String(URLtoByteArray(location));
782     }
783 
784     public String URLtoString(String location, boolean post)
785         throws IOException {
786 
787         return new String(URLtoByteArray(location, post));
788     }
789 
790     /**
791      * @deprecated
792      */
793     public String URLtoString(
794             String location, Cookie[] cookies, Http.Auth auth, Http.Body body,
795             boolean post)
796         throws IOException {
797 
798         Http.Options options = new Http.Options();
799 
800         options.setAuth(auth);
801         options.setBody(body);
802         options.setCookies(cookies);
803         options.setLocation(location);
804         options.setPost(post);
805 
806         return new String(URLtoByteArray(options));
807     }
808 
809     /**
810      * @deprecated
811      */
812     public String URLtoString(
813             String location, Cookie[] cookies, Http.Auth auth,
814             Map<String, String> parts, boolean post)
815         throws IOException {
816 
817         Http.Options options = new Http.Options();
818 
819         options.setAuth(auth);
820         options.setCookies(cookies);
821         options.setLocation(location);
822         options.setParts(parts);
823         options.setPost(post);
824 
825         return new String(URLtoByteArray(options));
826     }
827 
828     /**
829      * This method only uses the default Commons HttpClient implementation when
830      * the URL object represents a HTTP resource. The URL object could also
831      * represent a file or some JNDI resource. In that case, the default Java
832      * implementation is used.
833      *
834      * @param  url URL object
835      * @return A string representation of the resource referenced by the
836      *         URL object
837      */
838     public String URLtoString(URL url) throws IOException {
839         String xml = null;
840 
841         if (url != null) {
842             String protocol = url.getProtocol().toLowerCase();
843 
844             if (protocol.startsWith(Http.HTTP) ||
845                 protocol.startsWith(Http.HTTPS)) {
846 
847                 return URLtoString(url.toString());
848             }
849 
850             URLConnection con = url.openConnection();
851 
852             InputStream is = con.getInputStream();
853 
854             UnsyncByteArrayOutputStream ubaos =
855                 new UnsyncByteArrayOutputStream();
856             byte[] bytes = new byte[512];
857 
858             for (int i = is.read(bytes, 0, 512); i != -1;
859                     i = is.read(bytes, 0, 512)) {
860 
861                 ubaos.write(bytes, 0, i);
862             }
863 
864             xml = new String(ubaos.unsafeGetByteArray(), 0, ubaos.size());
865 
866             is.close();
867             ubaos.close();
868         }
869 
870         return xml;
871     }
872 
873     protected void proxifyState(HttpState state, HostConfiguration hostConfig) {
874         Credentials proxyCredentials = _proxyCredentials;
875 
876         String host = hostConfig.getHost();
877 
878         if (isProxyHost(host) && (proxyCredentials != null)) {
879             AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
880 
881             state.setProxyCredentials(scope, proxyCredentials);
882         }
883     }
884 
885     protected org.apache.commons.httpclient.Cookie toCommonsCookie(
886         Cookie cookie) {
887 
888         org.apache.commons.httpclient.Cookie commonsCookie =
889             new org.apache.commons.httpclient.Cookie(
890             cookie.getDomain(), cookie.getName(), cookie.getValue(),
891             cookie.getPath(), cookie.getMaxAge(), cookie.getSecure());
892 
893         commonsCookie.setVersion(cookie.getVersion());
894 
895         return commonsCookie;
896     }
897 
898     protected org.apache.commons.httpclient.Cookie[] toCommonsCookies(
899         Cookie[] cookies) {
900 
901         if (cookies == null) {
902             return null;
903         }
904 
905         org.apache.commons.httpclient.Cookie[] commonCookies =
906             new org.apache.commons.httpclient.Cookie[cookies.length];
907 
908         for (int i = 0; i < cookies.length; i++) {
909             commonCookies[i] = toCommonsCookie(cookies[i]);
910         }
911 
912         return commonCookies;
913     }
914 
915     protected Cookie toServletCookie(
916         org.apache.commons.httpclient.Cookie commonsCookie) {
917 
918         Cookie cookie = new Cookie(
919             commonsCookie.getName(), commonsCookie.getValue());
920 
921         cookie.setDomain(commonsCookie.getDomain());
922 
923         Date expiryDate = commonsCookie.getExpiryDate();
924 
925         if (expiryDate != null) {
926             int maxAge =
927                 (int)(expiryDate.getTime() - System.currentTimeMillis());
928 
929             maxAge = maxAge / 1000;
930 
931             if (maxAge > -1) {
932                 cookie.setMaxAge(maxAge);
933             }
934         }
935 
936         cookie.setPath(commonsCookie.getPath());
937         cookie.setSecure(commonsCookie.getSecure());
938         cookie.setVersion(commonsCookie.getVersion());
939 
940         return cookie;
941     }
942 
943     protected Cookie[] toServletCookies(
944         org.apache.commons.httpclient.Cookie[] commonsCookies) {
945 
946         if (commonsCookies == null) {
947             return null;
948         }
949 
950         Cookie[] cookies = new Cookie[commonsCookies.length];
951 
952         for (int i = 0; i < commonsCookies.length; i++) {
953             cookies[i] = toServletCookie(commonsCookies[i]);
954         }
955 
956         return cookies;
957     }
958 
959     protected byte[] URLtoByteArray(
960             String location, Http.Method method, Map<String, String> headers,
961             Cookie[] cookies, Http.Auth auth, Http.Body body, Map<String,
962             String> parts, Http.Response response, boolean followRedirects)
963         throws IOException {
964 
965         byte[] bytes = null;
966 
967         HttpMethod httpMethod = null;
968         HttpState httpState = null;
969 
970         try {
971             _cookies.set(null);
972 
973             if (location == null) {
974                 return bytes;
975             }
976             else if (!location.startsWith(Http.HTTP_WITH_SLASH) &&
977                      !location.startsWith(Http.HTTPS_WITH_SLASH)) {
978 
979                 location = Http.HTTP_WITH_SLASH + location;
980             }
981 
982             HostConfiguration hostConfig = getHostConfig(location);
983 
984             HttpClient httpClient = getClient(hostConfig);
985 
986             if ((method == Http.Method.POST) ||
987                 (method == Http.Method.PUT)) {
988 
989                 if (method == Http.Method.POST) {
990                     httpMethod = new PostMethod(location);
991                 }
992                 else {
993                     httpMethod = new PutMethod(location);
994                 }
995 
996                 if (body != null) {
997                     RequestEntity requestEntity = new StringRequestEntity(
998                         body.getContent(), body.getContentType(),
999                         body.getCharset());
1000
1001                    EntityEnclosingMethod entityEnclosingMethod =
1002                        (EntityEnclosingMethod)httpMethod;
1003
1004                    entityEnclosingMethod.setRequestEntity(requestEntity);
1005                }
1006                else if ((parts != null) && (parts.size() > 0) &&
1007                         (method == Http.Method.POST)) {
1008
1009                    List<NameValuePair> nvpList =
1010                        new ArrayList<NameValuePair>();
1011
1012                    for (Map.Entry<String, String> entry : parts.entrySet()) {
1013                        String key = entry.getKey();
1014                        String value = entry.getValue();
1015
1016                        if (value != null) {
1017                            nvpList.add(new NameValuePair(key, value));
1018                        }
1019                    }
1020
1021                    NameValuePair[] nvpArray = nvpList.toArray(
1022                        new NameValuePair[nvpList.size()]);
1023
1024                    PostMethod postMethod = (PostMethod)httpMethod;
1025
1026                    postMethod.setRequestBody(nvpArray);
1027                }
1028            }
1029            else if (method == Http.Method.DELETE) {
1030                httpMethod = new DeleteMethod(location);
1031            }
1032            else if (method == Http.Method.HEAD) {
1033                httpMethod = new HeadMethod(location);
1034            }
1035            else {
1036                httpMethod = new GetMethod(location);
1037            }
1038
1039            if (headers != null) {
1040                for (Map.Entry<String, String> header : headers.entrySet()) {
1041                    httpMethod.addRequestHeader(
1042                        header.getKey(), header.getValue());
1043                }
1044            }
1045
1046            if ((method == Http.Method.POST) || (method == Http.Method.PUT) &&
1047                (body != null)) {
1048            }
1049            else if (!_hasRequestHeader(httpMethod, HttpHeaders.CONTENT_TYPE)) {
1050                httpMethod.addRequestHeader(
1051                    HttpHeaders.CONTENT_TYPE,
1052                    ContentTypes.APPLICATION_X_WWW_FORM_URLENCODED);
1053            }
1054
1055            if (!_hasRequestHeader(httpMethod, HttpHeaders.USER_AGENT)) {
1056                httpMethod.addRequestHeader(
1057                    HttpHeaders.USER_AGENT, _DEFAULT_USER_AGENT);
1058            }
1059
1060            httpMethod.getParams().setIntParameter(
1061                HttpClientParams.SO_TIMEOUT, 0);
1062
1063            httpState = new HttpState();
1064
1065            if ((cookies != null) && (cookies.length > 0)) {
1066                org.apache.commons.httpclient.Cookie[] commonsCookies =
1067                    toCommonsCookies(cookies);
1068
1069                httpState.addCookies(commonsCookies);
1070
1071                httpMethod.getParams().setCookiePolicy(
1072                    CookiePolicy.BROWSER_COMPATIBILITY);
1073            }
1074
1075            if (auth != null) {
1076                httpMethod.setDoAuthentication(true);
1077
1078                httpState.setCredentials(
1079                    new AuthScope(
1080                        auth.getHost(), auth.getPort(), auth.getRealm()),
1081                    new UsernamePasswordCredentials(
1082                        auth.getUsername(), auth.getPassword()));
1083            }
1084
1085            proxifyState(httpState, hostConfig);
1086
1087            httpClient.executeMethod(hostConfig, httpMethod, httpState);
1088
1089            Header locationHeader = httpMethod.getResponseHeader("location");
1090
1091            if ((locationHeader != null) && !locationHeader.equals(location)) {
1092                String redirect = locationHeader.getValue();
1093
1094                if (followRedirects) {
1095                    return URLtoByteArray(
1096                        redirect, Http.Method.GET, headers,
1097                        cookies, auth, body, parts, response, followRedirects);
1098                }
1099                else {
1100                    response.setRedirect(redirect);
1101                }
1102            }
1103
1104            InputStream is = httpMethod.getResponseBodyAsStream();
1105
1106            if (is != null) {
1107                Header contentLength = httpMethod.getResponseHeader(
1108                    HttpHeaders.CONTENT_LENGTH);
1109
1110                if (contentLength != null) {
1111                    response.setContentLength(
1112                        GetterUtil.getInteger(contentLength.getValue()));
1113                }
1114
1115                Header contentType = httpMethod.getResponseHeader(
1116                    HttpHeaders.CONTENT_TYPE);
1117
1118                if (contentType != null) {
1119                    response.setContentType(contentType.getValue());
1120                }
1121
1122                bytes = FileUtil.getBytes(is);
1123
1124                is.close();
1125            }
1126
1127            for (Header header : httpMethod.getResponseHeaders()) {
1128                response.addHeader(header.getName(), header.getValue());
1129            }
1130
1131            return bytes;
1132        }
1133        finally {
1134            try {
1135                if (httpState != null) {
1136                    _cookies.set(toServletCookies(httpState.getCookies()));
1137                }
1138            }
1139            catch (Exception e) {
1140                _log.error(e, e);
1141            }
1142
1143            try {
1144                if (httpMethod != null) {
1145                    httpMethod.releaseConnection();
1146                }
1147            }
1148            catch (Exception e) {
1149                _log.error(e, e);
1150            }
1151        }
1152    }
1153
1154    private boolean _hasRequestHeader(HttpMethod httpMethod, String name) {
1155        if (httpMethod.getRequestHeaders(name).length == 0) {
1156            return false;
1157        }
1158        else {
1159            return true;
1160        }
1161    }
1162
1163    private static final String _DEFAULT_USER_AGENT =
1164        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
1165
1166    private static final int _MAX_CONNECTIONS_PER_HOST = GetterUtil.getInteger(
1167        PropsUtil.get(HttpImpl.class.getName() + ".max.connections.per.host"),
1168        2);
1169
1170    private static final int _MAX_TOTAL_CONNECTIONS = GetterUtil.getInteger(
1171        PropsUtil.get(HttpImpl.class.getName() + ".max.total.connections"),
1172        20);
1173
1174    private static final String _NON_PROXY_HOSTS =
1175        SystemProperties.get("http.nonProxyHosts");
1176
1177    private static final String _PROXY_AUTH_TYPE = GetterUtil.getString(
1178        PropsUtil.get(HttpImpl.class.getName() + ".proxy.auth.type"));
1179
1180    private static final String _PROXY_HOST = GetterUtil.getString(
1181        SystemProperties.get("http.proxyHost"));
1182
1183    private static final String _PROXY_NTLM_DOMAIN = GetterUtil.getString(
1184        PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.domain"));
1185
1186    private static final String _PROXY_NTLM_HOST = GetterUtil.getString(
1187        PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.host"));
1188
1189    private static final String _PROXY_PASSWORD = GetterUtil.getString(
1190        PropsUtil.get(HttpImpl.class.getName() + ".proxy.password"));
1191
1192    private static final int _PROXY_PORT = GetterUtil.getInteger(
1193        SystemProperties.get("http.proxyPort"));
1194
1195    private static final String _PROXY_USERNAME = GetterUtil.getString(
1196        PropsUtil.get(HttpImpl.class.getName() + ".proxy.username"));
1197
1198    private static final String _TEMP_SLASH = "_LIFERAY_TEMP_SLASH_";
1199
1200    private static final int _TIMEOUT = GetterUtil.getInteger(
1201        PropsUtil.get(HttpImpl.class.getName() + ".timeout"), 5000);
1202
1203    private static Log _log = LogFactoryUtil.getLog(HttpImpl.class);
1204
1205    private static ThreadLocal<Cookie[]> _cookies = new ThreadLocal<Cookie[]>();
1206
1207    private HttpClient _client = new HttpClient();
1208    private Pattern _nonProxyHostsPattern;
1209    private HttpClient _proxyClient = new HttpClient();
1210    private Credentials _proxyCredentials;
1211
1212}