001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022    import com.liferay.portal.kernel.servlet.HttpHeaders;
023    import com.liferay.portal.kernel.util.CharPool;
024    import com.liferay.portal.kernel.util.ContentTypes;
025    import com.liferay.portal.kernel.util.FileUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.Http;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.SystemProperties;
032    import com.liferay.portal.kernel.util.URLCodec;
033    import com.liferay.portal.kernel.util.Validator;
034    
035    import java.io.IOException;
036    import java.io.InputStream;
037    
038    import java.net.InetAddress;
039    import java.net.InetSocketAddress;
040    import java.net.Socket;
041    import java.net.SocketAddress;
042    import java.net.URL;
043    import java.net.URLConnection;
044    import java.net.UnknownHostException;
045    
046    import java.util.ArrayList;
047    import java.util.Date;
048    import java.util.LinkedHashMap;
049    import java.util.List;
050    import java.util.Map;
051    import java.util.regex.Matcher;
052    import java.util.regex.Pattern;
053    
054    import javax.net.SocketFactory;
055    
056    import javax.portlet.ActionRequest;
057    import javax.portlet.RenderRequest;
058    
059    import javax.servlet.http.Cookie;
060    import javax.servlet.http.HttpServletRequest;
061    import javax.servlet.http.HttpSession;
062    
063    import org.apache.commons.httpclient.ConnectTimeoutException;
064    import org.apache.commons.httpclient.Credentials;
065    import org.apache.commons.httpclient.Header;
066    import org.apache.commons.httpclient.HostConfiguration;
067    import org.apache.commons.httpclient.HttpClient;
068    import org.apache.commons.httpclient.HttpConnectionManager;
069    import org.apache.commons.httpclient.HttpMethod;
070    import org.apache.commons.httpclient.HttpState;
071    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
072    import org.apache.commons.httpclient.NTCredentials;
073    import org.apache.commons.httpclient.URI;
074    import org.apache.commons.httpclient.UsernamePasswordCredentials;
075    import org.apache.commons.httpclient.auth.AuthPolicy;
076    import org.apache.commons.httpclient.auth.AuthScope;
077    import org.apache.commons.httpclient.cookie.CookiePolicy;
078    import org.apache.commons.httpclient.methods.DeleteMethod;
079    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
080    import org.apache.commons.httpclient.methods.GetMethod;
081    import org.apache.commons.httpclient.methods.HeadMethod;
082    import org.apache.commons.httpclient.methods.PostMethod;
083    import org.apache.commons.httpclient.methods.PutMethod;
084    import org.apache.commons.httpclient.methods.RequestEntity;
085    import org.apache.commons.httpclient.methods.StringRequestEntity;
086    import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
087    import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
088    import org.apache.commons.httpclient.methods.multipart.Part;
089    import org.apache.commons.httpclient.methods.multipart.StringPart;
090    import org.apache.commons.httpclient.params.HostParams;
091    import org.apache.commons.httpclient.params.HttpClientParams;
092    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
093    import org.apache.commons.httpclient.params.HttpConnectionParams;
094    import org.apache.commons.httpclient.params.HttpMethodParams;
095    import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
096    import org.apache.commons.httpclient.protocol.Protocol;
097    
098    /**
099     * @author Brian Wing Shun Chan
100     * @author Hugo Huijser
101     */
102    @DoPrivileged
103    public class HttpImpl implements Http {
104    
105            public HttpImpl() {
106    
107                    // Override the default protocol socket factory because it uses
108                    // reflection for JDK 1.4 compatibility, which we do not need. It also
109                    // attemps to create a new socket in a different thread so that we
110                    // cannot track which class loader initiated the call.
111    
112                    Protocol protocol = new Protocol(
113                            "http", new FastProtocolSocketFactory(), 80);
114    
115                    Protocol.registerProtocol("http", protocol);
116    
117                    // Mimic behavior found in
118                    // http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html
119    
120                    if (Validator.isNotNull(_NON_PROXY_HOSTS)) {
121                            String nonProxyHostsRegEx = _NON_PROXY_HOSTS;
122    
123                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\.", "\\\\.");
124                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\*", ".*?");
125                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\|", ")|(");
126    
127                            nonProxyHostsRegEx = "(" + nonProxyHostsRegEx + ")";
128    
129                            _nonProxyHostsPattern = Pattern.compile(nonProxyHostsRegEx);
130                    }
131    
132                    MultiThreadedHttpConnectionManager httpConnectionManager =
133                            new MultiThreadedHttpConnectionManager();
134    
135                    HttpConnectionManagerParams httpConnectionManagerParams =
136                            httpConnectionManager.getParams();
137    
138                    httpConnectionManagerParams.setConnectionTimeout(_TIMEOUT);
139                    httpConnectionManagerParams.setDefaultMaxConnectionsPerHost(
140                            new Integer(_MAX_CONNECTIONS_PER_HOST));
141                    httpConnectionManagerParams.setMaxTotalConnections(
142                            new Integer(_MAX_TOTAL_CONNECTIONS));
143                    httpConnectionManagerParams.setSoTimeout(_TIMEOUT);
144    
145                    _httpClient.setHttpConnectionManager(httpConnectionManager);
146                    _proxyHttpClient.setHttpConnectionManager(httpConnectionManager);
147    
148                    if (!hasProxyConfig() || Validator.isNull(_PROXY_USERNAME)) {
149                            return;
150                    }
151    
152                    List<String> authPrefs = new ArrayList<String>();
153    
154                    if (_PROXY_AUTH_TYPE.equals("username-password")) {
155                            _proxyCredentials = new UsernamePasswordCredentials(
156                                    _PROXY_USERNAME, _PROXY_PASSWORD);
157    
158                            authPrefs.add(AuthPolicy.BASIC);
159                            authPrefs.add(AuthPolicy.DIGEST);
160                            authPrefs.add(AuthPolicy.NTLM);
161                    }
162                    else if (_PROXY_AUTH_TYPE.equals("ntlm")) {
163                            _proxyCredentials = new NTCredentials(
164                                    _PROXY_USERNAME, _PROXY_PASSWORD, _PROXY_NTLM_HOST,
165                                    _PROXY_NTLM_DOMAIN);
166    
167                            authPrefs.add(AuthPolicy.NTLM);
168                            authPrefs.add(AuthPolicy.BASIC);
169                            authPrefs.add(AuthPolicy.DIGEST);
170                    }
171    
172                    HttpClientParams httpClientParams = _proxyHttpClient.getParams();
173    
174                    httpClientParams.setParameter(
175                            AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
176            }
177    
178            @Override
179            public String addParameter(String url, String name, boolean value) {
180                    return addParameter(url, name, String.valueOf(value));
181            }
182    
183            @Override
184            public String addParameter(String url, String name, double value) {
185                    return addParameter(url, name, String.valueOf(value));
186            }
187    
188            @Override
189            public String addParameter(String url, String name, int value) {
190                    return addParameter(url, name, String.valueOf(value));
191            }
192    
193            @Override
194            public String addParameter(String url, String name, long value) {
195                    return addParameter(url, name, String.valueOf(value));
196            }
197    
198            @Override
199            public String addParameter(String url, String name, short value) {
200                    return addParameter(url, name, String.valueOf(value));
201            }
202    
203            @Override
204            public String addParameter(String url, String name, String value) {
205                    if (url == null) {
206                            return null;
207                    }
208    
209                    String[] urlArray = PortalUtil.stripURLAnchor(url, StringPool.POUND);
210    
211                    url = urlArray[0];
212    
213                    String anchor = urlArray[1];
214    
215                    StringBundler sb = new StringBundler(7);
216    
217                    sb.append(url);
218    
219                    if (url.indexOf(CharPool.QUESTION) == -1) {
220                            sb.append(StringPool.QUESTION);
221                    }
222                    else if (!url.endsWith(StringPool.QUESTION) &&
223                                     !url.endsWith(StringPool.AMPERSAND)) {
224    
225                            sb.append(StringPool.AMPERSAND);
226                    }
227    
228                    sb.append(name);
229                    sb.append(StringPool.EQUAL);
230                    sb.append(encodeURL(value));
231                    sb.append(anchor);
232    
233                    return sb.toString();
234            }
235    
236            @Override
237            public String decodePath(String path) {
238                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
239                    path = decodeURL(path, true);
240                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
241    
242                    return path;
243            }
244    
245            @Override
246            public String decodeURL(String url) {
247                    return decodeURL(url, false);
248            }
249    
250            @Override
251            public String decodeURL(String url, boolean unescapeSpaces) {
252                    return URLCodec.decodeURL(url, StringPool.UTF8, unescapeSpaces);
253            }
254    
255            public void destroy() {
256                    MultiThreadedHttpConnectionManager.shutdownAll();
257            }
258    
259            @Override
260            public String encodeParameters(String url) {
261                    String queryString = getQueryString(url);
262    
263                    if (Validator.isNull(queryString)) {
264                            return url;
265                    }
266    
267                    String encodedQueryString = parameterMapToString(
268                            parameterMapFromString(queryString), false);
269    
270                    return StringUtil.replace(url, queryString, encodedQueryString);
271            }
272    
273            @Override
274            public String encodePath(String path) {
275                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
276                    path = encodeURL(path, true);
277                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
278    
279                    return path;
280            }
281    
282            @Override
283            public String encodeURL(String url) {
284                    return encodeURL(url, false);
285            }
286    
287            @Override
288            public String encodeURL(String url, boolean escapeSpaces) {
289                    return URLCodec.encodeURL(url, StringPool.UTF8, escapeSpaces);
290            }
291    
292            @Override
293            public String fixPath(String path) {
294                    return fixPath(path, true, true);
295            }
296    
297            @Override
298            public String fixPath(String path, boolean leading, boolean trailing) {
299                    if (path == null) {
300                            return StringPool.BLANK;
301                    }
302    
303                    int leadingSlashCount = 0;
304                    int trailingSlashCount = 0;
305    
306                    if (leading) {
307                            for (int i = 0; i < path.length(); i++) {
308                                    if (path.charAt(i) == CharPool.SLASH) {
309                                            leadingSlashCount++;
310                                    }
311                                    else {
312                                            break;
313                                    }
314                            }
315                    }
316    
317                    if (trailing) {
318                            for (int i = path.length() - 1; i >=0; i--) {
319                                    if (path.charAt(i) == CharPool.SLASH) {
320                                            trailingSlashCount++;
321                                    }
322                                    else {
323                                            break;
324                                    }
325                            }
326                    }
327    
328                    int slashCount = leadingSlashCount + trailingSlashCount;
329    
330                    if (slashCount > path.length()) {
331                            return StringPool.BLANK;
332                    }
333    
334                    if (slashCount > 0) {
335                            path = path.substring(
336                                    leadingSlashCount, path.length() - trailingSlashCount);
337                    }
338    
339                    return path;
340            }
341    
342            public HttpClient getClient(HostConfiguration hostConfiguration) {
343                    if (isProxyHost(hostConfiguration.getHost())) {
344                            return _proxyHttpClient;
345                    }
346                    else {
347                            return _httpClient;
348                    }
349            }
350    
351            @Override
352            public String getCompleteURL(HttpServletRequest request) {
353                    StringBuffer sb = request.getRequestURL();
354    
355                    if (sb == null) {
356                            sb = new StringBuffer();
357                    }
358    
359                    if (request.getQueryString() != null) {
360                            sb.append(StringPool.QUESTION);
361                            sb.append(request.getQueryString());
362                    }
363    
364                    String proxyPath = PortalUtil.getPathProxy();
365    
366                    if (Validator.isNotNull(proxyPath)) {
367                            int x =
368                                    sb.indexOf(Http.PROTOCOL_DELIMITER) +
369                                            Http.PROTOCOL_DELIMITER.length();
370                            int y = sb.indexOf(StringPool.SLASH, x);
371    
372                            sb.insert(y, proxyPath);
373                    }
374    
375                    String completeURL = sb.toString();
376    
377                    if (request.isRequestedSessionIdFromURL()) {
378                            HttpSession session = request.getSession();
379    
380                            String sessionId = session.getId();
381    
382                            completeURL = PortalUtil.getURLWithSessionId(
383                                    completeURL, sessionId);
384                    }
385    
386                    if (_log.isWarnEnabled()) {
387                            if (completeURL.contains("?&")) {
388                                    _log.warn("Invalid url " + completeURL);
389                            }
390                    }
391    
392                    return completeURL;
393            }
394    
395            @Override
396            public Cookie[] getCookies() {
397                    return _cookies.get();
398            }
399    
400            @Override
401            public String getDomain(String url) {
402                    url = removeProtocol(url);
403    
404                    int pos = url.indexOf(CharPool.SLASH);
405    
406                    if (pos != -1) {
407                            return url.substring(0, pos);
408                    }
409                    else {
410                            return url;
411                    }
412            }
413    
414            /**
415             * @deprecated {@link #getHostConfiguration(String)}
416             */
417            public HostConfiguration getHostConfig(String location) throws IOException {
418                    return getHostConfiguration(location);
419            }
420    
421            public HostConfiguration getHostConfiguration(String location)
422                    throws IOException {
423    
424                    if (_log.isDebugEnabled()) {
425                            _log.debug("Location is " + location);
426                    }
427    
428                    HostConfiguration hostConfiguration = new HostConfiguration();
429    
430                    hostConfiguration.setHost(new URI(location, false));
431    
432                    if (isProxyHost(hostConfiguration.getHost())) {
433                            hostConfiguration.setProxy(_PROXY_HOST, _PROXY_PORT);
434                    }
435    
436                    HttpConnectionManager httpConnectionManager =
437                            _httpClient.getHttpConnectionManager();
438    
439                    HttpConnectionManagerParams httpConnectionManagerParams =
440                            httpConnectionManager.getParams();
441    
442                    int defaultMaxConnectionsPerHost =
443                            httpConnectionManagerParams.getMaxConnectionsPerHost(
444                                    hostConfiguration);
445    
446                    int maxConnectionsPerHost = GetterUtil.getInteger(
447                            PropsUtil.get(
448                                    HttpImpl.class.getName() + ".max.connections.per.host",
449                                    new Filter(hostConfiguration.getHost())));
450    
451                    if ((maxConnectionsPerHost > 0) &&
452                            (maxConnectionsPerHost != defaultMaxConnectionsPerHost)) {
453    
454                            httpConnectionManagerParams.setMaxConnectionsPerHost(
455                                    hostConfiguration, maxConnectionsPerHost);
456                    }
457    
458                    int timeout = GetterUtil.getInteger(
459                            PropsUtil.get(
460                                    HttpImpl.class.getName() + ".timeout",
461                                    new Filter(hostConfiguration.getHost())));
462    
463                    if (timeout > 0) {
464                            HostParams hostParams = hostConfiguration.getParams();
465    
466                            hostParams.setIntParameter(
467                                    HttpConnectionParams.CONNECTION_TIMEOUT, timeout);
468                            hostParams.setIntParameter(
469                                    HttpConnectionParams.SO_TIMEOUT, timeout);
470                    }
471    
472                    return hostConfiguration;
473            }
474    
475            @Override
476            public String getIpAddress(String url) {
477                    try {
478                            URL urlObj = new URL(url);
479    
480                            InetAddress address = InetAddress.getByName(urlObj.getHost());
481    
482                            return address.getHostAddress();
483                    }
484                    catch (Exception e) {
485                            return url;
486                    }
487            }
488    
489            @Override
490            public String getParameter(String url, String name) {
491                    return getParameter(url, name, true);
492            }
493    
494            @Override
495            public String getParameter(String url, String name, boolean escaped) {
496                    if (Validator.isNull(url) || Validator.isNull(name)) {
497                            return StringPool.BLANK;
498                    }
499    
500                    String[] parts = StringUtil.split(url, CharPool.QUESTION);
501    
502                    if (parts.length == 2) {
503                            String[] params = null;
504    
505                            if (escaped) {
506                                    params = StringUtil.split(parts[1], "&amp;");
507                            }
508                            else {
509                                    params = StringUtil.split(parts[1], CharPool.AMPERSAND);
510                            }
511    
512                            for (String param : params) {
513                                    String[] kvp = StringUtil.split(param, CharPool.EQUAL);
514    
515                                    if ((kvp.length == 2) && kvp[0].equals(name)) {
516                                            return kvp[1];
517                                    }
518                            }
519                    }
520    
521                    return StringPool.BLANK;
522            }
523    
524            @Override
525            public Map<String, String[]> getParameterMap(String queryString) {
526                    return parameterMapFromString(queryString);
527            }
528    
529            @Override
530            public String getPath(String url) {
531                    if (Validator.isNull(url)) {
532                            return url;
533                    }
534    
535                    if (url.startsWith(Http.HTTP)) {
536                            int pos = url.indexOf(
537                                    StringPool.SLASH, Http.HTTPS_WITH_SLASH.length());
538    
539                            url = url.substring(pos);
540                    }
541    
542                    int pos = url.indexOf(CharPool.QUESTION);
543    
544                    if (pos == -1) {
545                            return url;
546                    }
547                    else {
548                            return url.substring(0, pos);
549                    }
550            }
551    
552            @Override
553            public String getProtocol(ActionRequest actionRequest) {
554                    return getProtocol(actionRequest.isSecure());
555            }
556    
557            @Override
558            public String getProtocol(boolean secure) {
559                    if (!secure) {
560                            return Http.HTTP;
561                    }
562                    else {
563                            return Http.HTTPS;
564                    }
565            }
566    
567            @Override
568            public String getProtocol(HttpServletRequest request) {
569                    return getProtocol(request.isSecure());
570            }
571    
572            @Override
573            public String getProtocol(RenderRequest renderRequest) {
574                    return getProtocol(renderRequest.isSecure());
575            }
576    
577            @Override
578            public String getProtocol(String url) {
579                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
580    
581                    if (pos != -1) {
582                            return url.substring(0, pos);
583                    }
584                    else {
585                            return Http.HTTP;
586                    }
587            }
588    
589            @Override
590            public String getQueryString(String url) {
591                    if (Validator.isNull(url)) {
592                            return url;
593                    }
594    
595                    int pos = url.indexOf(CharPool.QUESTION);
596    
597                    if (pos == -1) {
598                            return StringPool.BLANK;
599                    }
600                    else {
601                            return url.substring(pos + 1);
602                    }
603            }
604    
605            @Override
606            public String getRequestURL(HttpServletRequest request) {
607                    return request.getRequestURL().toString();
608            }
609    
610            @Override
611            public boolean hasDomain(String url) {
612                    return Validator.isNotNull(getDomain(url));
613            }
614    
615            @Override
616            public boolean hasProtocol(String url) {
617                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
618    
619                    if (pos != -1) {
620                            return true;
621                    }
622                    else {
623                            return false;
624                    }
625            }
626    
627            @Override
628            public boolean hasProxyConfig() {
629                    if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
630                            return true;
631                    }
632                    else {
633                            return false;
634                    }
635            }
636    
637            @Override
638            public boolean isNonProxyHost(String host) {
639                    if (_nonProxyHostsPattern != null) {
640                            Matcher matcher = _nonProxyHostsPattern.matcher(host);
641    
642                            if (matcher.matches()) {
643                                    return true;
644                            }
645                    }
646    
647                    return false;
648            }
649    
650            @Override
651            public boolean isProxyHost(String host) {
652                    if (hasProxyConfig() && !isNonProxyHost(host)) {
653                            return true;
654                    }
655                    else {
656                            return false;
657                    }
658            }
659    
660            @Override
661            public Map<String, String[]> parameterMapFromString(String queryString) {
662                    Map<String, String[]> parameterMap =
663                            new LinkedHashMap<String, String[]>();
664    
665                    if (Validator.isNull(queryString)) {
666                            return parameterMap;
667                    }
668    
669                    Map<String, List<String>> tempParameterMap =
670                            new LinkedHashMap<String, List<String>>();
671    
672                    String[] parameters = StringUtil.split(queryString, CharPool.AMPERSAND);
673    
674                    for (String parameter : parameters) {
675                            if (parameter.length() > 0) {
676                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
677    
678                                    String key = kvp[0];
679    
680                                    String value = StringPool.BLANK;
681    
682                                    if (kvp.length > 1) {
683                                            value = decodeURL(kvp[1]);
684                                    }
685    
686                                    List<String> values = tempParameterMap.get(key);
687    
688                                    if (values == null) {
689                                            values = new ArrayList<String>();
690    
691                                            tempParameterMap.put(key, values);
692                                    }
693    
694                                    values.add(value);
695                            }
696                    }
697    
698                    for (Map.Entry<String, List<String>> entry :
699                                    tempParameterMap.entrySet()) {
700    
701                            String key = entry.getKey();
702                            List<String> values = entry.getValue();
703    
704                            parameterMap.put(key, values.toArray(new String[values.size()]));
705                    }
706    
707                    return parameterMap;
708            }
709    
710            @Override
711            public String parameterMapToString(Map<String, String[]> parameterMap) {
712                    return parameterMapToString(parameterMap, true);
713            }
714    
715            @Override
716            public String parameterMapToString(
717                    Map<String, String[]> parameterMap, boolean addQuestion) {
718    
719                    if (parameterMap.isEmpty()) {
720                            return StringPool.BLANK;
721                    }
722    
723                    StringBundler sb = new StringBundler();
724    
725                    if (addQuestion) {
726                            sb.append(StringPool.QUESTION);
727                    }
728    
729                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
730                            String name = entry.getKey();
731                            String[] values = entry.getValue();
732    
733                            for (String value : values) {
734                                    sb.append(name);
735                                    sb.append(StringPool.EQUAL);
736                                    sb.append(encodeURL(value));
737                                    sb.append(StringPool.AMPERSAND);
738                            }
739                    }
740    
741                    if (sb.index() > 1) {
742                            sb.setIndex(sb.index() - 1);
743                    }
744    
745                    return sb.toString();
746            }
747    
748            @Override
749            public String protocolize(String url, ActionRequest actionRequest) {
750                    return protocolize(url, actionRequest.isSecure());
751            }
752    
753            @Override
754            public String protocolize(String url, boolean secure) {
755                    if (secure) {
756                            if (url.startsWith(Http.HTTP_WITH_SLASH)) {
757                                    return StringUtil.replace(
758                                            url, Http.HTTP_WITH_SLASH, Http.HTTPS_WITH_SLASH);
759                            }
760                    }
761                    else {
762                            if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
763                                    return StringUtil.replace(
764                                            url, Http.HTTPS_WITH_SLASH, Http.HTTP_WITH_SLASH);
765                            }
766                    }
767    
768                    return url;
769            }
770    
771            @Override
772            public String protocolize(String url, HttpServletRequest request) {
773                    return protocolize(url, request.isSecure());
774            }
775    
776            @Override
777            public String protocolize(String url, RenderRequest renderRequest) {
778                    return protocolize(url, renderRequest.isSecure());
779            }
780    
781            public void proxifyState(
782                    HttpState httpState, HostConfiguration hostConfiguration) {
783    
784                    Credentials proxyCredentials = _proxyCredentials;
785    
786                    String host = hostConfiguration.getHost();
787    
788                    if (isProxyHost(host) && (proxyCredentials != null)) {
789                            AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
790    
791                            httpState.setProxyCredentials(scope, proxyCredentials);
792                    }
793            }
794    
795            @Override
796            public String removeDomain(String url) {
797                    url = removeProtocol(url);
798    
799                    int pos = url.indexOf(CharPool.SLASH);
800    
801                    if (pos > 0) {
802                            return url.substring(pos);
803                    }
804                    else {
805                            return url;
806                    }
807            }
808    
809            @Override
810            public String removeParameter(String url, String name) {
811                    int pos = url.indexOf(CharPool.QUESTION);
812    
813                    if (pos == -1) {
814                            return url;
815                    }
816    
817                    String[] array = PortalUtil.stripURLAnchor(url, StringPool.POUND);
818    
819                    url = array[0];
820    
821                    String anchor = array[1];
822    
823                    StringBundler sb = new StringBundler();
824    
825                    sb.append(url.substring(0, pos + 1));
826    
827                    String[] parameters = StringUtil.split(
828                            url.substring(pos + 1, url.length()), CharPool.AMPERSAND);
829    
830                    for (String parameter : parameters) {
831                            if (parameter.length() > 0) {
832                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
833    
834                                    String key = kvp[0];
835    
836                                    String value = StringPool.BLANK;
837    
838                                    if (kvp.length > 1) {
839                                            value = kvp[1];
840                                    }
841    
842                                    if (!key.equals(name)) {
843                                            sb.append(key);
844                                            sb.append(StringPool.EQUAL);
845                                            sb.append(value);
846                                            sb.append(StringPool.AMPERSAND);
847                                    }
848                            }
849                    }
850    
851                    url = StringUtil.replace(
852                            sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
853                            StringPool.AMPERSAND);
854    
855                    if (url.endsWith(StringPool.AMPERSAND)) {
856                            url = url.substring(0, url.length() - 1);
857                    }
858    
859                    if (url.endsWith(StringPool.QUESTION)) {
860                            url = url.substring(0, url.length() - 1);
861                    }
862    
863                    return url + anchor;
864            }
865    
866            @Override
867            public String removeProtocol(String url) {
868                    if (url.startsWith(Http.HTTP_WITH_SLASH)) {
869                            return url.substring(Http.HTTP_WITH_SLASH.length());
870                    }
871                    else if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
872                            return url.substring(Http.HTTPS_WITH_SLASH.length());
873                    }
874                    else {
875                            return url;
876                    }
877            }
878    
879            @Override
880            public String setParameter(String url, String name, boolean value) {
881                    return setParameter(url, name, String.valueOf(value));
882            }
883    
884            @Override
885            public String setParameter(String url, String name, double value) {
886                    return setParameter(url, name, String.valueOf(value));
887            }
888    
889            @Override
890            public String setParameter(String url, String name, int value) {
891                    return setParameter(url, name, String.valueOf(value));
892            }
893    
894            @Override
895            public String setParameter(String url, String name, long value) {
896                    return setParameter(url, name, String.valueOf(value));
897            }
898    
899            @Override
900            public String setParameter(String url, String name, short value) {
901                    return setParameter(url, name, String.valueOf(value));
902            }
903    
904            @Override
905            public String setParameter(String url, String name, String value) {
906                    if (url == null) {
907                            return null;
908                    }
909    
910                    url = removeParameter(url, name);
911    
912                    return addParameter(url, name, value);
913            }
914    
915            @Override
916            public byte[] URLtoByteArray(Http.Options options) throws IOException {
917                    return URLtoByteArray(
918                            options.getLocation(), options.getMethod(), options.getHeaders(),
919                            options.getCookies(), options.getAuth(), options.getBody(),
920                            options.getFileParts(), options.getParts(), options.getResponse(),
921                            options.isFollowRedirects());
922            }
923    
924            @Override
925            public byte[] URLtoByteArray(String location) throws IOException {
926                    Http.Options options = new Http.Options();
927    
928                    options.setLocation(location);
929    
930                    return URLtoByteArray(options);
931            }
932    
933            @Override
934            public byte[] URLtoByteArray(String location, boolean post)
935                    throws IOException {
936    
937                    Http.Options options = new Http.Options();
938    
939                    options.setLocation(location);
940                    options.setPost(post);
941    
942                    return URLtoByteArray(options);
943            }
944    
945            @Override
946            public String URLtoString(Http.Options options) throws IOException {
947                    return new String(URLtoByteArray(options));
948            }
949    
950            @Override
951            public String URLtoString(String location) throws IOException {
952                    return new String(URLtoByteArray(location));
953            }
954    
955            @Override
956            public String URLtoString(String location, boolean post)
957                    throws IOException {
958    
959                    return new String(URLtoByteArray(location, post));
960            }
961    
962            /**
963             * This method only uses the default Commons HttpClient implementation when
964             * the URL object represents a HTTP resource. The URL object could also
965             * represent a file or some JNDI resource. In that case, the default Java
966             * implementation is used.
967             *
968             * @param  url the URL
969             * @return A string representation of the resource referenced by the URL
970             *         object
971             * @throws IOException if an IO exception occurred
972             */
973            @Override
974            public String URLtoString(URL url) throws IOException {
975                    String xml = null;
976    
977                    if (url == null) {
978                            return null;
979                    }
980    
981                    String protocol = url.getProtocol().toLowerCase();
982    
983                    if (protocol.startsWith(Http.HTTP) || protocol.startsWith(Http.HTTPS)) {
984                            return URLtoString(url.toString());
985                    }
986    
987                    URLConnection urlConnection = url.openConnection();
988    
989                    InputStream inputStream = urlConnection.getInputStream();
990    
991                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
992                            new UnsyncByteArrayOutputStream();
993    
994                    byte[] bytes = new byte[512];
995    
996                    for (int i = inputStream.read(bytes, 0, 512); i != -1;
997                                    i = inputStream.read(bytes, 0, 512)) {
998    
999                            unsyncByteArrayOutputStream.write(bytes, 0, i);
1000                    }
1001    
1002                    xml = new String(
1003                            unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
1004                            unsyncByteArrayOutputStream.size());
1005    
1006                    inputStream.close();
1007    
1008                    unsyncByteArrayOutputStream.close();
1009    
1010                    return xml;
1011            }
1012    
1013            protected boolean hasRequestHeader(HttpMethod httpMethod, String name) {
1014                    Header[] headers = httpMethod.getRequestHeaders(name);
1015    
1016                    if (headers.length == 0) {
1017                            return false;
1018                    }
1019                    else {
1020                            return true;
1021                    }
1022            }
1023    
1024            protected void processPostMethod(
1025                    PostMethod postMethod, List<Http.FilePart> fileParts,
1026                    Map<String, String> parts) {
1027    
1028                    if ((fileParts == null) || fileParts.isEmpty()) {
1029                            if (parts != null) {
1030                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
1031                                            String value = entry.getValue();
1032    
1033                                            if (value != null) {
1034                                                    postMethod.addParameter(entry.getKey(), value);
1035                                            }
1036                                    }
1037                            }
1038                    }
1039                    else {
1040                            List<Part> partsList = new ArrayList<Part>();
1041    
1042                            if (parts != null) {
1043                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
1044                                            String value = entry.getValue();
1045    
1046                                            if (value != null) {
1047                                                    StringPart stringPart = new StringPart(
1048                                                            entry.getKey(), value);
1049    
1050                                                    partsList.add(stringPart);
1051                                            }
1052                                    }
1053                            }
1054    
1055                            for (Http.FilePart filePart : fileParts) {
1056                                    partsList.add(toCommonsFilePart(filePart));
1057                            }
1058    
1059                            MultipartRequestEntity multipartRequestEntity =
1060                                    new MultipartRequestEntity(
1061                                            partsList.toArray(new Part[partsList.size()]),
1062                                            postMethod.getParams());
1063    
1064                            postMethod.setRequestEntity(multipartRequestEntity);
1065                    }
1066            }
1067    
1068            protected org.apache.commons.httpclient.Cookie toCommonsCookie(
1069                    Cookie cookie) {
1070    
1071                    org.apache.commons.httpclient.Cookie commonsCookie =
1072                            new org.apache.commons.httpclient.Cookie(
1073                                    cookie.getDomain(), cookie.getName(), cookie.getValue(),
1074                                    cookie.getPath(), cookie.getMaxAge(), cookie.getSecure());
1075    
1076                    commonsCookie.setVersion(cookie.getVersion());
1077    
1078                    return commonsCookie;
1079            }
1080    
1081            protected org.apache.commons.httpclient.Cookie[] toCommonsCookies(
1082                    Cookie[] cookies) {
1083    
1084                    if (cookies == null) {
1085                            return null;
1086                    }
1087    
1088                    org.apache.commons.httpclient.Cookie[] commonCookies =
1089                            new org.apache.commons.httpclient.Cookie[cookies.length];
1090    
1091                    for (int i = 0; i < cookies.length; i++) {
1092                            commonCookies[i] = toCommonsCookie(cookies[i]);
1093                    }
1094    
1095                    return commonCookies;
1096            }
1097    
1098            protected org.apache.commons.httpclient.methods.multipart.FilePart
1099                    toCommonsFilePart(Http.FilePart filePart) {
1100    
1101                    return new org.apache.commons.httpclient.methods.multipart.FilePart(
1102                            filePart.getName(),
1103                            new ByteArrayPartSource(
1104                                    filePart.getFileName(), filePart.getValue()),
1105                            filePart.getContentType(), filePart.getCharSet());
1106            }
1107    
1108            protected Cookie toServletCookie(
1109                    org.apache.commons.httpclient.Cookie commonsCookie) {
1110    
1111                    Cookie cookie = new Cookie(
1112                            commonsCookie.getName(), commonsCookie.getValue());
1113    
1114                    String domain = commonsCookie.getDomain();
1115    
1116                    if (Validator.isNotNull(domain)) {
1117                            cookie.setDomain(domain);
1118                    }
1119    
1120                    Date expiryDate = commonsCookie.getExpiryDate();
1121    
1122                    if (expiryDate != null) {
1123                            int maxAge =
1124                                    (int)(expiryDate.getTime() - System.currentTimeMillis());
1125    
1126                            maxAge = maxAge / 1000;
1127    
1128                            if (maxAge > -1) {
1129                                    cookie.setMaxAge(maxAge);
1130                            }
1131                    }
1132    
1133                    String path = commonsCookie.getPath();
1134    
1135                    if (Validator.isNotNull(path)) {
1136                            cookie.setPath(path);
1137                    }
1138    
1139                    cookie.setSecure(commonsCookie.getSecure());
1140                    cookie.setVersion(commonsCookie.getVersion());
1141    
1142                    return cookie;
1143            }
1144    
1145            protected Cookie[] toServletCookies(
1146                    org.apache.commons.httpclient.Cookie[] commonsCookies) {
1147    
1148                    if (commonsCookies == null) {
1149                            return null;
1150                    }
1151    
1152                    Cookie[] cookies = new Cookie[commonsCookies.length];
1153    
1154                    for (int i = 0; i < commonsCookies.length; i++) {
1155                            cookies[i] = toServletCookie(commonsCookies[i]);
1156                    }
1157    
1158                    return cookies;
1159            }
1160    
1161            protected byte[] URLtoByteArray(
1162                            String location, Http.Method method, Map<String, String> headers,
1163                            Cookie[] cookies, Http.Auth auth, Http.Body body,
1164                            List<Http.FilePart> fileParts, Map<String, String> parts,
1165                            Http.Response response, boolean followRedirects)
1166                    throws IOException {
1167    
1168                    byte[] bytes = null;
1169    
1170                    HttpMethod httpMethod = null;
1171                    HttpState httpState = null;
1172    
1173                    try {
1174                            _cookies.set(null);
1175    
1176                            if (location == null) {
1177                                    return null;
1178                            }
1179                            else if (!location.startsWith(Http.HTTP_WITH_SLASH) &&
1180                                             !location.startsWith(Http.HTTPS_WITH_SLASH)) {
1181    
1182                                    location = Http.HTTP_WITH_SLASH + location;
1183                            }
1184    
1185                            HostConfiguration hostConfiguration = getHostConfiguration(
1186                                    location);
1187    
1188                            HttpClient httpClient = getClient(hostConfiguration);
1189    
1190                            if (method.equals(Http.Method.POST) ||
1191                                    method.equals(Http.Method.PUT)) {
1192    
1193                                    if (method.equals(Http.Method.POST)) {
1194                                            httpMethod = new PostMethod(location);
1195                                    }
1196                                    else {
1197                                            httpMethod = new PutMethod(location);
1198                                    }
1199    
1200                                    if (body != null) {
1201                                            RequestEntity requestEntity = new StringRequestEntity(
1202                                                    body.getContent(), body.getContentType(),
1203                                                    body.getCharset());
1204    
1205                                            EntityEnclosingMethod entityEnclosingMethod =
1206                                                    (EntityEnclosingMethod)httpMethod;
1207    
1208                                            entityEnclosingMethod.setRequestEntity(requestEntity);
1209                                    }
1210                                    else if (method.equals(Http.Method.POST)) {
1211                                            PostMethod postMethod = (PostMethod)httpMethod;
1212    
1213                                            if (!hasRequestHeader(
1214                                                            postMethod, HttpHeaders.CONTENT_TYPE)) {
1215    
1216                                                    postMethod.addRequestHeader(
1217                                                            HttpHeaders.CONTENT_TYPE,
1218                                                            ContentTypes.
1219                                                                    APPLICATION_X_WWW_FORM_URLENCODED_UTF8);
1220                                            }
1221    
1222                                            processPostMethod(postMethod, fileParts, parts);
1223                                    }
1224                            }
1225                            else if (method.equals(Http.Method.DELETE)) {
1226                                    httpMethod = new DeleteMethod(location);
1227                            }
1228                            else if (method.equals(Http.Method.HEAD)) {
1229                                    httpMethod = new HeadMethod(location);
1230                            }
1231                            else {
1232                                    httpMethod = new GetMethod(location);
1233                            }
1234    
1235                            if (headers != null) {
1236                                    for (Map.Entry<String, String> header : headers.entrySet()) {
1237                                            httpMethod.addRequestHeader(
1238                                                    header.getKey(), header.getValue());
1239                                    }
1240                            }
1241    
1242                            if ((method.equals(Http.Method.POST) ||
1243                                     method.equals(Http.Method.PUT)) &&
1244                                    ((body != null) ||
1245                                     ((fileParts != null) && !fileParts.isEmpty()) ||
1246                                     ((parts != null) && !parts.isEmpty()))) {
1247                            }
1248                            else if (!hasRequestHeader(httpMethod, HttpHeaders.CONTENT_TYPE)) {
1249                                    httpMethod.addRequestHeader(
1250                                            HttpHeaders.CONTENT_TYPE,
1251                                            ContentTypes.APPLICATION_X_WWW_FORM_URLENCODED_UTF8);
1252                            }
1253    
1254                            if (!hasRequestHeader(httpMethod, HttpHeaders.USER_AGENT)) {
1255                                    httpMethod.addRequestHeader(
1256                                            HttpHeaders.USER_AGENT, _DEFAULT_USER_AGENT);
1257                            }
1258    
1259                            httpState = new HttpState();
1260    
1261                            if ((cookies != null) && (cookies.length > 0)) {
1262                                    org.apache.commons.httpclient.Cookie[] commonsCookies =
1263                                            toCommonsCookies(cookies);
1264    
1265                                    httpState.addCookies(commonsCookies);
1266    
1267                                    HttpMethodParams httpMethodParams = httpMethod.getParams();
1268    
1269                                    httpMethodParams.setCookiePolicy(
1270                                            CookiePolicy.BROWSER_COMPATIBILITY);
1271                            }
1272    
1273                            if (auth != null) {
1274                                    httpMethod.setDoAuthentication(true);
1275    
1276                                    httpState.setCredentials(
1277                                            new AuthScope(
1278                                                    auth.getHost(), auth.getPort(), auth.getRealm()),
1279                                            new UsernamePasswordCredentials(
1280                                                    auth.getUsername(), auth.getPassword()));
1281                            }
1282    
1283                            proxifyState(httpState, hostConfiguration);
1284    
1285                            httpClient.executeMethod(hostConfiguration, httpMethod, httpState);
1286    
1287                            Header locationHeader = httpMethod.getResponseHeader("location");
1288    
1289                            if ((locationHeader != null) && !locationHeader.equals(location)) {
1290                                    String redirect = locationHeader.getValue();
1291    
1292                                    if (followRedirects) {
1293                                            return URLtoByteArray(
1294                                                    redirect, Http.Method.GET, headers, cookies, auth, body,
1295                                                    fileParts, parts, response, followRedirects);
1296                                    }
1297                                    else {
1298                                            response.setRedirect(redirect);
1299                                    }
1300                            }
1301    
1302                            InputStream inputStream = httpMethod.getResponseBodyAsStream();
1303    
1304                            if (inputStream != null) {
1305                                    Header contentLength = httpMethod.getResponseHeader(
1306                                            HttpHeaders.CONTENT_LENGTH);
1307    
1308                                    if (contentLength != null) {
1309                                            response.setContentLength(
1310                                                    GetterUtil.getInteger(contentLength.getValue()));
1311                                    }
1312    
1313                                    Header contentType = httpMethod.getResponseHeader(
1314                                            HttpHeaders.CONTENT_TYPE);
1315    
1316                                    if (contentType != null) {
1317                                            response.setContentType(contentType.getValue());
1318                                    }
1319    
1320                                    bytes = FileUtil.getBytes(inputStream);
1321                            }
1322    
1323                            for (Header header : httpMethod.getResponseHeaders()) {
1324                                    response.addHeader(header.getName(), header.getValue());
1325                            }
1326    
1327                            return bytes;
1328                    }
1329                    finally {
1330                            try {
1331                                    if (httpState != null) {
1332                                            _cookies.set(toServletCookies(httpState.getCookies()));
1333                                    }
1334                            }
1335                            catch (Exception e) {
1336                                    _log.error(e, e);
1337                            }
1338    
1339                            try {
1340                                    if (httpMethod != null) {
1341                                            httpMethod.releaseConnection();
1342                                    }
1343                            }
1344                            catch (Exception e) {
1345                                    _log.error(e, e);
1346                            }
1347                    }
1348            }
1349    
1350            private static final String _DEFAULT_USER_AGENT =
1351                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
1352    
1353            private static final int _MAX_CONNECTIONS_PER_HOST = GetterUtil.getInteger(
1354                    PropsUtil.get(HttpImpl.class.getName() + ".max.connections.per.host"),
1355                    2);
1356    
1357            private static final int _MAX_TOTAL_CONNECTIONS = GetterUtil.getInteger(
1358                    PropsUtil.get(HttpImpl.class.getName() + ".max.total.connections"), 20);
1359    
1360            private static final String _NON_PROXY_HOSTS = SystemProperties.get(
1361                    "http.nonProxyHosts");
1362    
1363            private static final String _PROXY_AUTH_TYPE = GetterUtil.getString(
1364                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.auth.type"));
1365    
1366            private static final String _PROXY_HOST = GetterUtil.getString(
1367                    SystemProperties.get("http.proxyHost"));
1368    
1369            private static final String _PROXY_NTLM_DOMAIN = GetterUtil.getString(
1370                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.domain"));
1371    
1372            private static final String _PROXY_NTLM_HOST = GetterUtil.getString(
1373                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.host"));
1374    
1375            private static final String _PROXY_PASSWORD = GetterUtil.getString(
1376                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.password"));
1377    
1378            private static final int _PROXY_PORT = GetterUtil.getInteger(
1379                    SystemProperties.get("http.proxyPort"));
1380    
1381            private static final String _PROXY_USERNAME = GetterUtil.getString(
1382                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.username"));
1383    
1384            private static final String _TEMP_SLASH = "_LIFERAY_TEMP_SLASH_";
1385    
1386            private static final int _TIMEOUT = GetterUtil.getInteger(
1387                    PropsUtil.get(HttpImpl.class.getName() + ".timeout"), 5000);
1388    
1389            private static Log _log = LogFactoryUtil.getLog(HttpImpl.class);
1390    
1391            private static ThreadLocal<Cookie[]> _cookies = new ThreadLocal<Cookie[]>();
1392    
1393            private HttpClient _httpClient = new HttpClient();
1394            private Pattern _nonProxyHostsPattern;
1395            private Credentials _proxyCredentials;
1396            private HttpClient _proxyHttpClient = new HttpClient();
1397    
1398            private class FastProtocolSocketFactory
1399                    extends DefaultProtocolSocketFactory {
1400    
1401                    @Override
1402                    public Socket createSocket(
1403                                    final String host, final int port,
1404                                    final InetAddress localInetAddress, final int localPort,
1405                                    final HttpConnectionParams httpConnectionParams)
1406                            throws ConnectTimeoutException, IOException, UnknownHostException {
1407    
1408                            int connectionTimeout = httpConnectionParams.getConnectionTimeout();
1409    
1410                            if (connectionTimeout == 0) {
1411                                    return createSocket(host, port, localInetAddress, localPort);
1412                            }
1413    
1414                            SocketFactory socketFactory = SocketFactory.getDefault();
1415    
1416                            Socket socket = socketFactory.createSocket();
1417    
1418                            SocketAddress localSocketAddress = new InetSocketAddress(
1419                                    localInetAddress, localPort);
1420    
1421                            SocketAddress remoteSocketAddress = new InetSocketAddress(
1422                                    host, port);
1423    
1424                            socket.bind(localSocketAddress);
1425    
1426                            socket.connect(remoteSocketAddress, connectionTimeout);
1427    
1428                            return socket;
1429                    }
1430    
1431            }
1432    
1433    }