001    /**
002     * Copyright (c) 2000-present 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.io.unsync.UnsyncFilterInputStream;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.memory.FinalizeAction;
023    import com.liferay.portal.kernel.memory.FinalizeManager;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.servlet.HttpHeaders;
026    import com.liferay.portal.kernel.util.ArrayUtil;
027    import com.liferay.portal.kernel.util.CharPool;
028    import com.liferay.portal.kernel.util.ContentTypes;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.Http;
032    import com.liferay.portal.kernel.util.PortalUtil;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.SystemProperties;
037    import com.liferay.portal.kernel.util.URLCodec;
038    import com.liferay.portal.kernel.util.Validator;
039    
040    import java.io.IOException;
041    import java.io.InputStream;
042    
043    import java.lang.ref.Reference;
044    
045    import java.net.InetAddress;
046    import java.net.InetSocketAddress;
047    import java.net.Socket;
048    import java.net.SocketAddress;
049    import java.net.URL;
050    import java.net.URLConnection;
051    import java.net.UnknownHostException;
052    
053    import java.util.ArrayList;
054    import java.util.Date;
055    import java.util.LinkedHashMap;
056    import java.util.List;
057    import java.util.Map;
058    import java.util.regex.Matcher;
059    import java.util.regex.Pattern;
060    
061    import javax.net.SocketFactory;
062    
063    import javax.portlet.ActionRequest;
064    import javax.portlet.RenderRequest;
065    
066    import javax.servlet.http.Cookie;
067    import javax.servlet.http.HttpServletRequest;
068    import javax.servlet.http.HttpSession;
069    
070    import org.apache.commons.httpclient.ConnectTimeoutException;
071    import org.apache.commons.httpclient.Credentials;
072    import org.apache.commons.httpclient.Header;
073    import org.apache.commons.httpclient.HostConfiguration;
074    import org.apache.commons.httpclient.HttpClient;
075    import org.apache.commons.httpclient.HttpConnectionManager;
076    import org.apache.commons.httpclient.HttpMethod;
077    import org.apache.commons.httpclient.HttpState;
078    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
079    import org.apache.commons.httpclient.NTCredentials;
080    import org.apache.commons.httpclient.URI;
081    import org.apache.commons.httpclient.UsernamePasswordCredentials;
082    import org.apache.commons.httpclient.auth.AuthPolicy;
083    import org.apache.commons.httpclient.auth.AuthScope;
084    import org.apache.commons.httpclient.cookie.CookiePolicy;
085    import org.apache.commons.httpclient.methods.DeleteMethod;
086    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
087    import org.apache.commons.httpclient.methods.GetMethod;
088    import org.apache.commons.httpclient.methods.HeadMethod;
089    import org.apache.commons.httpclient.methods.PostMethod;
090    import org.apache.commons.httpclient.methods.PutMethod;
091    import org.apache.commons.httpclient.methods.RequestEntity;
092    import org.apache.commons.httpclient.methods.StringRequestEntity;
093    import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
094    import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
095    import org.apache.commons.httpclient.methods.multipart.Part;
096    import org.apache.commons.httpclient.methods.multipart.StringPart;
097    import org.apache.commons.httpclient.params.HostParams;
098    import org.apache.commons.httpclient.params.HttpClientParams;
099    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
100    import org.apache.commons.httpclient.params.HttpConnectionParams;
101    import org.apache.commons.httpclient.params.HttpMethodParams;
102    import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
103    import org.apache.commons.httpclient.protocol.Protocol;
104    
105    /**
106     * @author Brian Wing Shun Chan
107     * @author Hugo Huijser
108     * @author Shuyang Zhou
109     */
110    @DoPrivileged
111    public class HttpImpl implements Http {
112    
113            public HttpImpl() {
114    
115                    // Override the default protocol socket factory because it uses
116                    // reflection for JDK 1.4 compatibility, which we do not need. It also
117                    // attemps to create a new socket in a different thread so that we
118                    // cannot track which class loader initiated the call.
119    
120                    Protocol protocol = new Protocol(
121                            "http", new FastProtocolSocketFactory(), 80);
122    
123                    Protocol.registerProtocol("http", protocol);
124    
125                    // Mimic behavior found in
126                    // http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html
127    
128                    if (Validator.isNotNull(_NON_PROXY_HOSTS)) {
129                            String nonProxyHostsRegEx = _NON_PROXY_HOSTS;
130    
131                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\.", "\\\\.");
132                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\*", ".*?");
133                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\|", ")|(");
134    
135                            nonProxyHostsRegEx = "(" + nonProxyHostsRegEx + ")";
136    
137                            _nonProxyHostsPattern = Pattern.compile(nonProxyHostsRegEx);
138                    }
139                    else {
140                            _nonProxyHostsPattern = null;
141                    }
142    
143                    MultiThreadedHttpConnectionManager httpConnectionManager =
144                            new MultiThreadedHttpConnectionManager();
145    
146                    HttpConnectionManagerParams httpConnectionManagerParams =
147                            httpConnectionManager.getParams();
148    
149                    httpConnectionManagerParams.setConnectionTimeout(_TIMEOUT);
150                    httpConnectionManagerParams.setDefaultMaxConnectionsPerHost(
151                            Integer.valueOf(_MAX_CONNECTIONS_PER_HOST));
152                    httpConnectionManagerParams.setMaxTotalConnections(
153                            Integer.valueOf(_MAX_TOTAL_CONNECTIONS));
154                    httpConnectionManagerParams.setSoTimeout(_TIMEOUT);
155    
156                    _httpClient.setHttpConnectionManager(httpConnectionManager);
157                    _proxyHttpClient.setHttpConnectionManager(httpConnectionManager);
158    
159                    if (!hasProxyConfig() || Validator.isNull(_PROXY_USERNAME)) {
160                            _proxyCredentials = null;
161    
162                            return;
163                    }
164    
165                    List<String> authPrefs = new ArrayList<>();
166    
167                    if (_PROXY_AUTH_TYPE.equals("username-password")) {
168                            _proxyCredentials = new UsernamePasswordCredentials(
169                                    _PROXY_USERNAME, _PROXY_PASSWORD);
170    
171                            authPrefs.add(AuthPolicy.BASIC);
172                            authPrefs.add(AuthPolicy.DIGEST);
173                            authPrefs.add(AuthPolicy.NTLM);
174                    }
175                    else if (_PROXY_AUTH_TYPE.equals("ntlm")) {
176                            _proxyCredentials = new NTCredentials(
177                                    _PROXY_USERNAME, _PROXY_PASSWORD, _PROXY_NTLM_HOST,
178                                    _PROXY_NTLM_DOMAIN);
179    
180                            authPrefs.add(AuthPolicy.NTLM);
181                            authPrefs.add(AuthPolicy.BASIC);
182                            authPrefs.add(AuthPolicy.DIGEST);
183                    }
184                    else {
185                            _proxyCredentials = null;
186                    }
187    
188                    HttpClientParams httpClientParams = _proxyHttpClient.getParams();
189    
190                    httpClientParams.setParameter(
191                            AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
192            }
193    
194            @Override
195            public String addParameter(String url, String name, boolean value) {
196                    return addParameter(url, name, String.valueOf(value));
197            }
198    
199            @Override
200            public String addParameter(String url, String name, double value) {
201                    return addParameter(url, name, String.valueOf(value));
202            }
203    
204            @Override
205            public String addParameter(String url, String name, int value) {
206                    return addParameter(url, name, String.valueOf(value));
207            }
208    
209            @Override
210            public String addParameter(String url, String name, long value) {
211                    return addParameter(url, name, String.valueOf(value));
212            }
213    
214            @Override
215            public String addParameter(String url, String name, short value) {
216                    return addParameter(url, name, String.valueOf(value));
217            }
218    
219            @Override
220            public String addParameter(String url, String name, String value) {
221                    if (url == null) {
222                            return null;
223                    }
224    
225                    String[] urlArray = PortalUtil.stripURLAnchor(url, StringPool.POUND);
226    
227                    url = urlArray[0];
228    
229                    String anchor = urlArray[1];
230    
231                    StringBundler sb = new StringBundler(6);
232    
233                    sb.append(url);
234    
235                    if (url.indexOf(CharPool.QUESTION) == -1) {
236                            sb.append(StringPool.QUESTION);
237                    }
238                    else if (!url.endsWith(StringPool.QUESTION) &&
239                                     !url.endsWith(StringPool.AMPERSAND)) {
240    
241                            sb.append(StringPool.AMPERSAND);
242                    }
243    
244                    sb.append(name);
245                    sb.append(StringPool.EQUAL);
246                    sb.append(encodeURL(value));
247                    sb.append(anchor);
248    
249                    String result = sb.toString();
250    
251                    if (result.length() > URL_MAXIMUM_LENGTH) {
252                            result = shortenURL(result, 2);
253                    }
254    
255                    return result;
256            }
257    
258            @Override
259            public String decodePath(String path) {
260                    if (Validator.isNull(path)) {
261                            return path;
262                    }
263    
264                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
265                    path = decodeURL(path, true);
266                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
267    
268                    return path;
269            }
270    
271            @Override
272            public String decodeURL(String url) {
273                    return decodeURL(url, false);
274            }
275    
276            /**
277             * @deprecated As of 7.0.0, replaced by {@link #decodeURL(String)}
278             */
279            @Deprecated
280            @Override
281            public String decodeURL(String url, boolean unescapeSpaces) {
282                    if (Validator.isNull(url)) {
283                            return url;
284                    }
285    
286                    return URLCodec.decodeURL(url, StringPool.UTF8);
287            }
288    
289            public void destroy() {
290                    MultiThreadedHttpConnectionManager.shutdownAll();
291            }
292    
293            @Override
294            public String encodeParameters(String url) {
295                    if (Validator.isNull(url)) {
296                            return url;
297                    }
298    
299                    String queryString = getQueryString(url);
300    
301                    if (Validator.isNull(queryString)) {
302                            return url;
303                    }
304    
305                    String encodedQueryString = parameterMapToString(
306                            parameterMapFromString(queryString), false);
307    
308                    return StringUtil.replace(url, queryString, encodedQueryString);
309            }
310    
311            @Override
312            public String encodePath(String path) {
313                    if (Validator.isNull(path)) {
314                            return path;
315                    }
316    
317                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
318                    path = encodeURL(path, true);
319                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
320    
321                    return path;
322            }
323    
324            @Override
325            public String encodeURL(String url) {
326                    return encodeURL(url, false);
327            }
328    
329            @Override
330            public String encodeURL(String url, boolean escapeSpaces) {
331                    if (Validator.isNull(url)) {
332                            return url;
333                    }
334    
335                    return URLCodec.encodeURL(url, StringPool.UTF8, escapeSpaces);
336            }
337    
338            @Override
339            public String fixPath(String path) {
340                    return fixPath(path, true, true);
341            }
342    
343            @Override
344            public String fixPath(String path, boolean leading, boolean trailing) {
345                    if (path == null) {
346                            return StringPool.BLANK;
347                    }
348    
349                    int leadingSlashCount = 0;
350                    int trailingSlashCount = 0;
351    
352                    if (leading) {
353                            for (int i = 0; i < path.length(); i++) {
354                                    if (path.charAt(i) == CharPool.SLASH) {
355                                            leadingSlashCount++;
356                                    }
357                                    else {
358                                            break;
359                                    }
360                            }
361                    }
362    
363                    if (trailing) {
364                            for (int i = path.length() - 1; i >= 0; i--) {
365                                    if (path.charAt(i) == CharPool.SLASH) {
366                                            trailingSlashCount++;
367                                    }
368                                    else {
369                                            break;
370                                    }
371                            }
372                    }
373    
374                    int slashCount = leadingSlashCount + trailingSlashCount;
375    
376                    if (slashCount > path.length()) {
377                            return StringPool.BLANK;
378                    }
379    
380                    if (slashCount > 0) {
381                            path = path.substring(
382                                    leadingSlashCount, path.length() - trailingSlashCount);
383                    }
384    
385                    return path;
386            }
387    
388            public HttpClient getClient(HostConfiguration hostConfiguration) {
389                    if (isProxyHost(hostConfiguration.getHost())) {
390                            return _proxyHttpClient;
391                    }
392    
393                    return _httpClient;
394            }
395    
396            @Override
397            public String getCompleteURL(HttpServletRequest request) {
398                    StringBuffer sb = request.getRequestURL();
399    
400                    if (sb == null) {
401                            sb = new StringBuffer();
402                    }
403    
404                    if (request.getQueryString() != null) {
405                            sb.append(StringPool.QUESTION);
406                            sb.append(request.getQueryString());
407                    }
408    
409                    String proxyPath = PortalUtil.getPathProxy();
410    
411                    if (Validator.isNotNull(proxyPath)) {
412                            int x =
413                                    sb.indexOf(Http.PROTOCOL_DELIMITER) +
414                                            Http.PROTOCOL_DELIMITER.length();
415                            int y = sb.indexOf(StringPool.SLASH, x);
416    
417                            sb.insert(y, proxyPath);
418                    }
419    
420                    String completeURL = sb.toString();
421    
422                    if (request.isRequestedSessionIdFromURL()) {
423                            HttpSession session = request.getSession();
424    
425                            String sessionId = session.getId();
426    
427                            completeURL = PortalUtil.getURLWithSessionId(
428                                    completeURL, sessionId);
429                    }
430    
431                    if (_log.isWarnEnabled()) {
432                            if (completeURL.contains("?&")) {
433                                    _log.warn("Invalid url " + completeURL);
434                            }
435                    }
436    
437                    return completeURL;
438            }
439    
440            @Override
441            public Cookie[] getCookies() {
442                    return _cookies.get();
443            }
444    
445            @Override
446            public String getDomain(String url) {
447                    if (Validator.isNull(url)) {
448                            return url;
449                    }
450    
451                    url = removeProtocol(url);
452    
453                    int pos = url.indexOf(CharPool.SLASH);
454    
455                    if (pos != -1) {
456                            return url.substring(0, pos);
457                    }
458    
459                    return url;
460            }
461    
462            /**
463             * @deprecated As of 6.1.0, replaced by {@link
464             *             #getHostConfiguration(String)}
465             */
466            @Deprecated
467            public HostConfiguration getHostConfig(String location) throws IOException {
468                    return getHostConfiguration(location);
469            }
470    
471            public HostConfiguration getHostConfiguration(String location)
472                    throws IOException {
473    
474                    if (_log.isDebugEnabled()) {
475                            _log.debug("Location is " + location);
476                    }
477    
478                    HostConfiguration hostConfiguration = new HostConfiguration();
479    
480                    hostConfiguration.setHost(new URI(location, false));
481    
482                    if (isProxyHost(hostConfiguration.getHost())) {
483                            hostConfiguration.setProxy(_PROXY_HOST, _PROXY_PORT);
484                    }
485    
486                    HttpConnectionManager httpConnectionManager =
487                            _httpClient.getHttpConnectionManager();
488    
489                    HttpConnectionManagerParams httpConnectionManagerParams =
490                            httpConnectionManager.getParams();
491    
492                    int defaultMaxConnectionsPerHost =
493                            httpConnectionManagerParams.getMaxConnectionsPerHost(
494                                    hostConfiguration);
495    
496                    int maxConnectionsPerHost = GetterUtil.getInteger(
497                            PropsUtil.get(
498                                    HttpImpl.class.getName() + ".max.connections.per.host",
499                                    new Filter(hostConfiguration.getHost())));
500    
501                    if ((maxConnectionsPerHost > 0) &&
502                            (maxConnectionsPerHost != defaultMaxConnectionsPerHost)) {
503    
504                            httpConnectionManagerParams.setMaxConnectionsPerHost(
505                                    hostConfiguration, maxConnectionsPerHost);
506                    }
507    
508                    int timeout = GetterUtil.getInteger(
509                            PropsUtil.get(
510                                    HttpImpl.class.getName() + ".timeout",
511                                    new Filter(hostConfiguration.getHost())));
512    
513                    if (timeout > 0) {
514                            HostParams hostParams = hostConfiguration.getParams();
515    
516                            hostParams.setIntParameter(
517                                    HttpConnectionParams.CONNECTION_TIMEOUT, timeout);
518                            hostParams.setIntParameter(
519                                    HttpConnectionParams.SO_TIMEOUT, timeout);
520                    }
521    
522                    return hostConfiguration;
523            }
524    
525            @Override
526            public String getIpAddress(String url) {
527                    if (Validator.isNull(url)) {
528                            return url;
529                    }
530    
531                    try {
532                            URL urlObj = new URL(url);
533    
534                            InetAddress address = InetAddress.getByName(urlObj.getHost());
535    
536                            return address.getHostAddress();
537                    }
538                    catch (Exception e) {
539                            return url;
540                    }
541            }
542    
543            @Override
544            public String getParameter(String url, String name) {
545                    return getParameter(url, name, true);
546            }
547    
548            @Override
549            public String getParameter(String url, String name, boolean escaped) {
550                    if (Validator.isNull(url) || Validator.isNull(name)) {
551                            return StringPool.BLANK;
552                    }
553    
554                    String[] parts = StringUtil.split(url, CharPool.QUESTION);
555    
556                    if (parts.length == 2) {
557                            String[] params = null;
558    
559                            if (escaped) {
560                                    params = StringUtil.split(parts[1], "&amp;");
561                            }
562                            else {
563                                    params = StringUtil.split(parts[1], CharPool.AMPERSAND);
564                            }
565    
566                            for (String param : params) {
567                                    String[] kvp = StringUtil.split(param, CharPool.EQUAL);
568    
569                                    if ((kvp.length == 2) && kvp[0].equals(name)) {
570                                            return kvp[1];
571                                    }
572                            }
573                    }
574    
575                    return StringPool.BLANK;
576            }
577    
578            @Override
579            public Map<String, String[]> getParameterMap(String queryString) {
580                    return parameterMapFromString(queryString);
581            }
582    
583            @Override
584            public String getPath(String url) {
585                    if (Validator.isNull(url)) {
586                            return url;
587                    }
588    
589                    if (url.startsWith(Http.HTTP)) {
590                            int pos = url.indexOf(
591                                    StringPool.SLASH, Http.HTTPS_WITH_SLASH.length());
592    
593                            url = url.substring(pos);
594                    }
595    
596                    int pos = url.indexOf(CharPool.QUESTION);
597    
598                    if (pos == -1) {
599                            return url;
600                    }
601    
602                    return url.substring(0, pos);
603            }
604    
605            @Override
606            public String getProtocol(ActionRequest actionRequest) {
607                    return getProtocol(actionRequest.isSecure());
608            }
609    
610            @Override
611            public String getProtocol(boolean secure) {
612                    if (!secure) {
613                            return Http.HTTP;
614                    }
615    
616                    return Http.HTTPS;
617            }
618    
619            @Override
620            public String getProtocol(HttpServletRequest request) {
621                    return getProtocol(request.isSecure());
622            }
623    
624            @Override
625            public String getProtocol(RenderRequest renderRequest) {
626                    return getProtocol(renderRequest.isSecure());
627            }
628    
629            @Override
630            public String getProtocol(String url) {
631                    if (Validator.isNull(url)) {
632                            return url;
633                    }
634    
635                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
636    
637                    if (pos != -1) {
638                            return url.substring(0, pos);
639                    }
640    
641                    return Http.HTTP;
642            }
643    
644            @Override
645            public String getQueryString(String url) {
646                    if (Validator.isNull(url)) {
647                            return url;
648                    }
649    
650                    int pos = url.indexOf(CharPool.QUESTION);
651    
652                    if (pos == -1) {
653                            return StringPool.BLANK;
654                    }
655    
656                    return url.substring(pos + 1);
657            }
658    
659            @Override
660            public String getRequestURL(HttpServletRequest request) {
661                    return String.valueOf(request.getRequestURL());
662            }
663    
664            @Override
665            public boolean hasDomain(String url) {
666                    if (Validator.isNull(url)) {
667                            return false;
668                    }
669    
670                    return Validator.isNotNull(getDomain(url));
671            }
672    
673            @Override
674            public boolean hasProtocol(String url) {
675                    if (Validator.isNull(url)) {
676                            return false;
677                    }
678    
679                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
680    
681                    if (pos != -1) {
682                            return true;
683                    }
684    
685                    return false;
686            }
687    
688            @Override
689            public boolean hasProxyConfig() {
690                    if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
691                            return true;
692                    }
693    
694                    return false;
695            }
696    
697            @Override
698            public boolean isNonProxyHost(String host) {
699                    if (Validator.isNull(host)) {
700                            return false;
701                    }
702    
703                    if (_nonProxyHostsPattern != null) {
704                            Matcher matcher = _nonProxyHostsPattern.matcher(host);
705    
706                            if (matcher.matches()) {
707                                    return true;
708                            }
709                    }
710    
711                    return false;
712            }
713    
714            @Override
715            public boolean isProxyHost(String host) {
716                    if (Validator.isNull(host)) {
717                            return false;
718                    }
719    
720                    if (hasProxyConfig() && !isNonProxyHost(host)) {
721                            return true;
722                    }
723    
724                    return false;
725            }
726    
727            @Override
728            public boolean isSecure(String url) {
729                    String protocol = getProtocol(url);
730    
731                    return StringUtil.equalsIgnoreCase(protocol, Http.HTTPS);
732            }
733    
734            @Override
735            public String normalizePath(String uri) {
736                    if (Validator.isNull(uri)) {
737                            return uri;
738                    }
739    
740                    uri = removePathParameters(uri);
741    
742                    String path = null;
743                    String queryString = null;
744    
745                    int pos = uri.indexOf('?');
746    
747                    if (pos != -1) {
748                            path = uri.substring(0, pos);
749                            queryString = uri.substring(pos + 1);
750                    }
751                    else {
752                            path = uri;
753                    }
754    
755                    String[] uriParts = StringUtil.split(
756                            path.substring(1), StringPool.SLASH);
757    
758                    List<String> parts = new ArrayList<>(uriParts.length);
759    
760                    for (int i = 0; i < uriParts.length; i++) {
761                            String curUriPart = URLCodec.decodeURL(uriParts[i]);
762                            String prevUriPart = null;
763    
764                            if (i > 0) {
765                                    prevUriPart = URLCodec.decodeURL(uriParts[i - 1]);
766                            }
767    
768                            if (curUriPart.equals(StringPool.DOUBLE_PERIOD)) {
769                                    if (!prevUriPart.equals(StringPool.PERIOD)) {
770                                            parts.remove(parts.size() - 1);
771                                    }
772                            }
773                            else if ((curUriPart.length() > 0) &&
774                                             !curUriPart.equals(StringPool.PERIOD)) {
775    
776                                    parts.add(URLCodec.encodeURL(curUriPart));
777                            }
778                    }
779    
780                    if (parts.isEmpty()) {
781                            return StringPool.SLASH;
782                    }
783    
784                    StringBundler sb = new StringBundler(parts.size() * 2 + 2);
785    
786                    for (String part : parts) {
787                            sb.append(StringPool.SLASH);
788                            sb.append(part);
789                    }
790    
791                    if (Validator.isNotNull(queryString)) {
792                            sb.append(StringPool.QUESTION);
793                            sb.append(queryString);
794                    }
795    
796                    return sb.toString();
797            }
798    
799            @Override
800            public Map<String, String[]> parameterMapFromString(String queryString) {
801                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
802    
803                    if (Validator.isNull(queryString)) {
804                            return parameterMap;
805                    }
806    
807                    Map<String, List<String>> tempParameterMap = new LinkedHashMap<>();
808    
809                    String[] parameters = StringUtil.split(queryString, CharPool.AMPERSAND);
810    
811                    for (String parameter : parameters) {
812                            if (parameter.length() > 0) {
813                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
814    
815                                    if (kvp.length == 0) {
816                                            continue;
817                                    }
818    
819                                    String key = kvp[0];
820    
821                                    String value = StringPool.BLANK;
822    
823                                    if (kvp.length > 1) {
824                                            try {
825                                                    value = decodeURL(kvp[1]);
826                                            }
827                                            catch (IllegalArgumentException iae) {
828                                                    if (_log.isInfoEnabled()) {
829                                                            _log.info(
830                                                                    "Skipping parameter with key " + key +
831                                                                            " because of invalid value " + kvp[1],
832                                                                    iae);
833                                                    }
834    
835                                                    continue;
836                                            }
837                                    }
838    
839                                    List<String> values = tempParameterMap.get(key);
840    
841                                    if (values == null) {
842                                            values = new ArrayList<>();
843    
844                                            tempParameterMap.put(key, values);
845                                    }
846    
847                                    values.add(value);
848                            }
849                    }
850    
851                    for (Map.Entry<String, List<String>> entry :
852                                    tempParameterMap.entrySet()) {
853    
854                            String key = entry.getKey();
855                            List<String> values = entry.getValue();
856    
857                            parameterMap.put(key, values.toArray(new String[values.size()]));
858                    }
859    
860                    return parameterMap;
861            }
862    
863            @Override
864            public String parameterMapToString(Map<String, String[]> parameterMap) {
865                    return parameterMapToString(parameterMap, true);
866            }
867    
868            @Override
869            public String parameterMapToString(
870                    Map<String, String[]> parameterMap, boolean addQuestion) {
871    
872                    if (parameterMap.isEmpty()) {
873                            return StringPool.BLANK;
874                    }
875    
876                    StringBundler sb = new StringBundler();
877    
878                    if (addQuestion) {
879                            sb.append(StringPool.QUESTION);
880                    }
881    
882                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
883                            String name = entry.getKey();
884                            String[] values = entry.getValue();
885    
886                            for (String value : values) {
887                                    sb.append(name);
888                                    sb.append(StringPool.EQUAL);
889                                    sb.append(encodeURL(value));
890                                    sb.append(StringPool.AMPERSAND);
891                            }
892                    }
893    
894                    if (sb.index() > 1) {
895                            sb.setIndex(sb.index() - 1);
896                    }
897    
898                    return sb.toString();
899            }
900    
901            @Override
902            public String protocolize(String url, ActionRequest actionRequest) {
903                    return protocolize(url, actionRequest.isSecure());
904            }
905    
906            @Override
907            public String protocolize(String url, boolean secure) {
908                    return protocolize(url, -1, secure);
909            }
910    
911            @Override
912            public String protocolize(String url, HttpServletRequest request) {
913                    return protocolize(url, request.isSecure());
914            }
915    
916            @Override
917            public String protocolize(String url, int port, boolean secure) {
918                    if (Validator.isNull(url)) {
919                            return url;
920                    }
921    
922                    try {
923                            URL urlObj = new URL(url);
924    
925                            String protocol = Http.HTTP;
926    
927                            if (secure) {
928                                    protocol = Http.HTTPS;
929                            }
930    
931                            if (port == -1) {
932                                    port = urlObj.getPort();
933                            }
934    
935                            urlObj = new URL(
936                                    protocol, urlObj.getHost(), port, urlObj.getFile());
937    
938                            return urlObj.toString();
939                    }
940                    catch (Exception e) {
941                            return url;
942                    }
943            }
944    
945            @Override
946            public String protocolize(String url, RenderRequest renderRequest) {
947                    return protocolize(url, renderRequest.isSecure());
948            }
949    
950            public void proxifyState(
951                    HttpState httpState, HostConfiguration hostConfiguration) {
952    
953                    Credentials proxyCredentials = _proxyCredentials;
954    
955                    String host = hostConfiguration.getHost();
956    
957                    if (isProxyHost(host) && (proxyCredentials != null)) {
958                            AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
959    
960                            httpState.setProxyCredentials(scope, proxyCredentials);
961                    }
962            }
963    
964            @Override
965            public String removeDomain(String url) {
966                    if (Validator.isNull(url)) {
967                            return url;
968                    }
969    
970                    url = removeProtocol(url);
971    
972                    int pos = url.indexOf(CharPool.SLASH);
973    
974                    if (pos > 0) {
975                            return url.substring(pos);
976                    }
977    
978                    return url;
979            }
980    
981            @Override
982            public String removeParameter(String url, String name) {
983                    if (Validator.isNull(url) || Validator.isNull(name)) {
984                            return url;
985                    }
986    
987                    int pos = url.indexOf(CharPool.QUESTION);
988    
989                    if (pos == -1) {
990                            return url;
991                    }
992    
993                    String[] array = PortalUtil.stripURLAnchor(url, StringPool.POUND);
994    
995                    url = array[0];
996    
997                    String anchor = array[1];
998    
999                    StringBundler sb = new StringBundler();
1000    
1001                    sb.append(url.substring(0, pos + 1));
1002    
1003                    String[] parameters = StringUtil.split(
1004                            url.substring(pos + 1, url.length()), CharPool.AMPERSAND);
1005    
1006                    for (String parameter : parameters) {
1007                            if (parameter.length() > 0) {
1008                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
1009    
1010                                    String key = kvp[0];
1011    
1012                                    String value = StringPool.BLANK;
1013    
1014                                    if (kvp.length > 1) {
1015                                            value = kvp[1];
1016                                    }
1017    
1018                                    if (!key.equals(name)) {
1019                                            sb.append(key);
1020                                            sb.append(StringPool.EQUAL);
1021                                            sb.append(value);
1022                                            sb.append(StringPool.AMPERSAND);
1023                                    }
1024                            }
1025                    }
1026    
1027                    url = StringUtil.replace(
1028                            sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
1029                            StringPool.AMPERSAND);
1030    
1031                    if (url.endsWith(StringPool.AMPERSAND)) {
1032                            url = url.substring(0, url.length() - 1);
1033                    }
1034    
1035                    if (url.endsWith(StringPool.QUESTION)) {
1036                            url = url.substring(0, url.length() - 1);
1037                    }
1038    
1039                    return url + anchor;
1040            }
1041    
1042            @Override
1043            public String removePathParameters(String uri) {
1044                    if (Validator.isNull(uri)) {
1045                            return uri;
1046                    }
1047    
1048                    int pos = uri.indexOf(StringPool.SEMICOLON);
1049    
1050                    if (pos == -1) {
1051                            return uri;
1052                    }
1053    
1054                    String[] uriParts = StringUtil.split(
1055                            uri.substring(1), StringPool.SLASH);
1056    
1057                    StringBundler sb = new StringBundler(uriParts.length * 2);
1058    
1059                    for (String uriPart : uriParts) {
1060                            pos = uriPart.indexOf(StringPool.SEMICOLON);
1061    
1062                            if (pos == -1) {
1063                                    sb.append(StringPool.SLASH);
1064                                    sb.append(uriPart);
1065                            }
1066                            else if (pos == 0) {
1067                                    continue;
1068                            }
1069                            else {
1070                                    sb.append(StringPool.SLASH);
1071                                    sb.append(uriPart.substring(0, pos));
1072                            }
1073                    }
1074    
1075                    if (sb.length() == 0) {
1076                            return StringPool.SLASH;
1077                    }
1078    
1079                    return sb.toString();
1080            }
1081    
1082            @Override
1083            public String removeProtocol(String url) {
1084                    if (Validator.isNull(url)) {
1085                            return url;
1086                    }
1087    
1088                    if (url.startsWith(Http.HTTP_WITH_SLASH)) {
1089                            return url.substring(Http.HTTP_WITH_SLASH.length());
1090                    }
1091                    else if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
1092                            return url.substring(Http.HTTPS_WITH_SLASH.length());
1093                    }
1094                    else {
1095                            return url;
1096                    }
1097            }
1098    
1099            @Override
1100            public String sanitizeHeader(String header) {
1101                    if (header == null) {
1102                            return null;
1103                    }
1104    
1105                    StringBuilder sb = null;
1106    
1107                    for (int i = 0; i < header.length(); i++) {
1108                            char c = header.charAt(i);
1109    
1110                            if (((c <= 31) && (c != 9)) || (c == 127) || (c > 255)) {
1111                                    if (sb == null) {
1112                                            sb = new StringBuilder(header);
1113                                    }
1114    
1115                                    sb.setCharAt(i, CharPool.SPACE);
1116                            }
1117                    }
1118    
1119                    if (sb != null) {
1120                            header = sb.toString();
1121                    }
1122    
1123                    return header;
1124            }
1125    
1126            @Override
1127            public String setParameter(String url, String name, boolean value) {
1128                    return setParameter(url, name, String.valueOf(value));
1129            }
1130    
1131            @Override
1132            public String setParameter(String url, String name, double value) {
1133                    return setParameter(url, name, String.valueOf(value));
1134            }
1135    
1136            @Override
1137            public String setParameter(String url, String name, int value) {
1138                    return setParameter(url, name, String.valueOf(value));
1139            }
1140    
1141            @Override
1142            public String setParameter(String url, String name, long value) {
1143                    return setParameter(url, name, String.valueOf(value));
1144            }
1145    
1146            @Override
1147            public String setParameter(String url, String name, short value) {
1148                    return setParameter(url, name, String.valueOf(value));
1149            }
1150    
1151            @Override
1152            public String setParameter(String url, String name, String value) {
1153                    if (Validator.isNull(url) || Validator.isNull(name)) {
1154                            return url;
1155                    }
1156    
1157                    url = removeParameter(url, name);
1158    
1159                    return addParameter(url, name, value);
1160            }
1161    
1162            @Override
1163            public String shortenURL(String url, int count) {
1164                    if (count == 0) {
1165                            return null;
1166                    }
1167    
1168                    StringBundler sb = new StringBundler();
1169    
1170                    String[] params = url.split(StringPool.AMPERSAND);
1171    
1172                    for (int i = 0; i < params.length; i++) {
1173                            String param = params[i];
1174    
1175                            if (param.contains("_backURL=") || param.contains("_redirect=") ||
1176                                    param.contains("_returnToFullPageURL=") ||
1177                                    param.startsWith("redirect")) {
1178    
1179                                    int pos = param.indexOf(StringPool.EQUAL);
1180    
1181                                    String qName = param.substring(0, pos);
1182    
1183                                    String redirect = param.substring(pos + 1);
1184    
1185                                    try {
1186                                            redirect = decodeURL(redirect);
1187                                    }
1188                                    catch (IllegalArgumentException iae) {
1189                                            if (_log.isDebugEnabled()) {
1190                                                    _log.debug(
1191                                                            "Skipping undecodable parameter " + param, iae);
1192                                            }
1193    
1194                                            continue;
1195                                    }
1196    
1197                                    String newURL = shortenURL(redirect, count - 1);
1198    
1199                                    if (newURL != null) {
1200                                            newURL = encodeURL(newURL);
1201    
1202                                            sb.append(qName);
1203                                            sb.append(StringPool.EQUAL);
1204                                            sb.append(newURL);
1205    
1206                                            if (i < (params.length - 1)) {
1207                                                    sb.append(StringPool.AMPERSAND);
1208                                            }
1209                                    }
1210                            }
1211                            else {
1212                                    sb.append(param);
1213    
1214                                    if (i < (params.length - 1)) {
1215                                            sb.append(StringPool.AMPERSAND);
1216                                    }
1217                            }
1218                    }
1219    
1220                    return sb.toString();
1221            }
1222    
1223            @Override
1224            public byte[] URLtoByteArray(Http.Options options) throws IOException {
1225                    return URLtoByteArray(
1226                            options.getLocation(), options.getMethod(), options.getHeaders(),
1227                            options.getCookies(), options.getAuth(), options.getBody(),
1228                            options.getFileParts(), options.getParts(), options.getResponse(),
1229                            options.isFollowRedirects());
1230            }
1231    
1232            @Override
1233            public byte[] URLtoByteArray(String location) throws IOException {
1234                    Http.Options options = new Http.Options();
1235    
1236                    options.setLocation(location);
1237    
1238                    return URLtoByteArray(options);
1239            }
1240    
1241            @Override
1242            public byte[] URLtoByteArray(String location, boolean post)
1243                    throws IOException {
1244    
1245                    Http.Options options = new Http.Options();
1246    
1247                    options.setLocation(location);
1248                    options.setPost(post);
1249    
1250                    return URLtoByteArray(options);
1251            }
1252    
1253            @Override
1254            public InputStream URLtoInputStream(Http.Options options)
1255                    throws IOException {
1256    
1257                    return URLtoInputStream(
1258                            options.getLocation(), options.getMethod(), options.getHeaders(),
1259                            options.getCookies(), options.getAuth(), options.getBody(),
1260                            options.getFileParts(), options.getParts(), options.getResponse(),
1261                            options.isFollowRedirects());
1262            }
1263    
1264            @Override
1265            public InputStream URLtoInputStream(String location) throws IOException {
1266                    Http.Options options = new Http.Options();
1267    
1268                    options.setLocation(location);
1269    
1270                    return URLtoInputStream(options);
1271            }
1272    
1273            @Override
1274            public InputStream URLtoInputStream(String location, boolean post)
1275                    throws IOException {
1276    
1277                    Http.Options options = new Http.Options();
1278    
1279                    options.setLocation(location);
1280                    options.setPost(post);
1281    
1282                    return URLtoInputStream(options);
1283            }
1284    
1285            @Override
1286            public String URLtoString(Http.Options options) throws IOException {
1287                    return new String(URLtoByteArray(options));
1288            }
1289    
1290            @Override
1291            public String URLtoString(String location) throws IOException {
1292                    return new String(URLtoByteArray(location));
1293            }
1294    
1295            @Override
1296            public String URLtoString(String location, boolean post)
1297                    throws IOException {
1298    
1299                    return new String(URLtoByteArray(location, post));
1300            }
1301    
1302            /**
1303             * This method only uses the default Commons HttpClient implementation when
1304             * the URL object represents a HTTP resource. The URL object could also
1305             * represent a file or some JNDI resource. In that case, the default Java
1306             * implementation is used.
1307             *
1308             * @param  url the URL
1309             * @return A string representation of the resource referenced by the URL
1310             *         object
1311             * @throws IOException if an IO exception occurred
1312             */
1313            @Override
1314            public String URLtoString(URL url) throws IOException {
1315                    String xml = null;
1316    
1317                    if (url == null) {
1318                            return null;
1319                    }
1320    
1321                    String protocol = StringUtil.toLowerCase(url.getProtocol());
1322    
1323                    if (protocol.startsWith(Http.HTTP) || protocol.startsWith(Http.HTTPS)) {
1324                            return URLtoString(url.toString());
1325                    }
1326    
1327                    URLConnection urlConnection = url.openConnection();
1328    
1329                    if (urlConnection == null) {
1330                            if (_log.isDebugEnabled()) {
1331                                    _log.debug("Unable to open a connection to " + url);
1332                            }
1333    
1334                            return null;
1335                    }
1336    
1337                    try (InputStream inputStream = urlConnection.getInputStream();
1338                            UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
1339                                    new UnsyncByteArrayOutputStream()) {
1340    
1341                            byte[] bytes = new byte[512];
1342    
1343                            for (int i = inputStream.read(bytes, 0, 512); i != -1;
1344                                    i = inputStream.read(bytes, 0, 512)) {
1345    
1346                                    unsyncByteArrayOutputStream.write(bytes, 0, i);
1347                            }
1348    
1349                            xml = new String(
1350                                    unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
1351                                    unsyncByteArrayOutputStream.size());
1352                    }
1353    
1354                    return xml;
1355            }
1356    
1357            protected boolean hasRequestHeader(HttpMethod httpMethod, String name) {
1358                    Header[] headers = httpMethod.getRequestHeaders(name);
1359    
1360                    if (headers.length == 0) {
1361                            return false;
1362                    }
1363    
1364                    return true;
1365            }
1366    
1367            protected void processPostMethod(
1368                    PostMethod postMethod, List<Http.FilePart> fileParts,
1369                    Map<String, String> parts) {
1370    
1371                    if ((fileParts == null) || fileParts.isEmpty()) {
1372                            if (parts != null) {
1373                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
1374                                            String value = entry.getValue();
1375    
1376                                            if (value != null) {
1377                                                    postMethod.addParameter(entry.getKey(), value);
1378                                            }
1379                                    }
1380                            }
1381                    }
1382                    else {
1383                            List<Part> partsList = new ArrayList<>();
1384    
1385                            if (parts != null) {
1386                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
1387                                            String value = entry.getValue();
1388    
1389                                            if (value != null) {
1390                                                    StringPart stringPart = new StringPart(
1391                                                            entry.getKey(), value);
1392    
1393                                                    partsList.add(stringPart);
1394                                            }
1395                                    }
1396                            }
1397    
1398                            for (Http.FilePart filePart : fileParts) {
1399                                    partsList.add(toCommonsFilePart(filePart));
1400                            }
1401    
1402                            MultipartRequestEntity multipartRequestEntity =
1403                                    new MultipartRequestEntity(
1404                                            partsList.toArray(new Part[partsList.size()]),
1405                                            postMethod.getParams());
1406    
1407                            postMethod.setRequestEntity(multipartRequestEntity);
1408                    }
1409            }
1410    
1411            protected org.apache.commons.httpclient.Cookie toCommonsCookie(
1412                    Cookie cookie) {
1413    
1414                    org.apache.commons.httpclient.Cookie commonsCookie =
1415                            new org.apache.commons.httpclient.Cookie(
1416                                    cookie.getDomain(), cookie.getName(), cookie.getValue(),
1417                                    cookie.getPath(), cookie.getMaxAge(), cookie.getSecure());
1418    
1419                    commonsCookie.setVersion(cookie.getVersion());
1420    
1421                    return commonsCookie;
1422            }
1423    
1424            protected org.apache.commons.httpclient.Cookie[] toCommonsCookies(
1425                    Cookie[] cookies) {
1426    
1427                    if (cookies == null) {
1428                            return null;
1429                    }
1430    
1431                    org.apache.commons.httpclient.Cookie[] commonCookies =
1432                            new org.apache.commons.httpclient.Cookie[cookies.length];
1433    
1434                    for (int i = 0; i < cookies.length; i++) {
1435                            commonCookies[i] = toCommonsCookie(cookies[i]);
1436                    }
1437    
1438                    return commonCookies;
1439            }
1440    
1441            protected org.apache.commons.httpclient.methods.multipart.FilePart
1442                    toCommonsFilePart(Http.FilePart filePart) {
1443    
1444                    return new org.apache.commons.httpclient.methods.multipart.FilePart(
1445                            filePart.getName(),
1446                            new ByteArrayPartSource(
1447                                    filePart.getFileName(), filePart.getValue()),
1448                            filePart.getContentType(), filePart.getCharSet());
1449            }
1450    
1451            protected Cookie toServletCookie(
1452                    org.apache.commons.httpclient.Cookie commonsCookie) {
1453    
1454                    Cookie cookie = new Cookie(
1455                            commonsCookie.getName(), commonsCookie.getValue());
1456    
1457                    if (!PropsValues.SESSION_COOKIE_USE_FULL_HOSTNAME) {
1458                            String domain = commonsCookie.getDomain();
1459    
1460                            if (Validator.isNotNull(domain)) {
1461                                    cookie.setDomain(domain);
1462                            }
1463                    }
1464    
1465                    Date expiryDate = commonsCookie.getExpiryDate();
1466    
1467                    if (expiryDate != null) {
1468                            int maxAge =
1469                                    (int)(expiryDate.getTime() - System.currentTimeMillis());
1470    
1471                            maxAge = maxAge / 1000;
1472    
1473                            if (maxAge > -1) {
1474                                    cookie.setMaxAge(maxAge);
1475                            }
1476                    }
1477    
1478                    String path = commonsCookie.getPath();
1479    
1480                    if (Validator.isNotNull(path)) {
1481                            cookie.setPath(path);
1482                    }
1483    
1484                    cookie.setSecure(commonsCookie.getSecure());
1485                    cookie.setVersion(commonsCookie.getVersion());
1486    
1487                    return cookie;
1488            }
1489    
1490            protected Cookie[] toServletCookies(
1491                    org.apache.commons.httpclient.Cookie[] commonsCookies) {
1492    
1493                    if (commonsCookies == null) {
1494                            return null;
1495                    }
1496    
1497                    Cookie[] cookies = new Cookie[commonsCookies.length];
1498    
1499                    for (int i = 0; i < commonsCookies.length; i++) {
1500                            cookies[i] = toServletCookie(commonsCookies[i]);
1501                    }
1502    
1503                    return cookies;
1504            }
1505    
1506            protected byte[] URLtoByteArray(
1507                            String location, Http.Method method, Map<String, String> headers,
1508                            Cookie[] cookies, Http.Auth auth, Http.Body body,
1509                            List<Http.FilePart> fileParts, Map<String, String> parts,
1510                            Http.Response response, boolean followRedirects)
1511                    throws IOException {
1512    
1513                    InputStream inputStream = URLtoInputStream(
1514                            location, method, headers, cookies, auth, body, fileParts, parts,
1515                            response, followRedirects);
1516    
1517                    if (inputStream == null) {
1518                            return null;
1519                    }
1520    
1521                    try {
1522                            long contentLengthLong = response.getContentLengthLong();
1523    
1524                            if (contentLengthLong > _MAX_BYTE_ARRAY_LENGTH) {
1525                                    StringBundler sb = new StringBundler(5);
1526    
1527                                    sb.append("Retrieving ");
1528                                    sb.append(location);
1529                                    sb.append(" yields a file of size ");
1530                                    sb.append(contentLengthLong);
1531                                    sb.append(
1532                                            " bytes that is too large to convert to a byte array");
1533    
1534                                    throw new OutOfMemoryError(sb.toString());
1535                            }
1536    
1537                            return FileUtil.getBytes(inputStream);
1538                    }
1539                    finally {
1540                            inputStream.close();
1541                    }
1542            }
1543    
1544            protected InputStream URLtoInputStream(
1545                            String location, Http.Method method, Map<String, String> headers,
1546                            Cookie[] cookies, Http.Auth auth, Http.Body body,
1547                            List<Http.FilePart> fileParts, Map<String, String> parts,
1548                            Http.Response response, boolean followRedirects)
1549                    throws IOException {
1550    
1551                    HttpMethod httpMethod = null;
1552                    HttpState httpState = null;
1553    
1554                    try {
1555                            _cookies.set(null);
1556    
1557                            if (location == null) {
1558                                    return null;
1559                            }
1560                            else if (!location.startsWith(Http.HTTP_WITH_SLASH) &&
1561                                             !location.startsWith(Http.HTTPS_WITH_SLASH)) {
1562    
1563                                    location = Http.HTTP_WITH_SLASH + location;
1564                            }
1565    
1566                            HostConfiguration hostConfiguration = getHostConfiguration(
1567                                    location);
1568    
1569                            HttpClient httpClient = getClient(hostConfiguration);
1570    
1571                            if (method.equals(Http.Method.POST) ||
1572                                    method.equals(Http.Method.PUT)) {
1573    
1574                                    if (method.equals(Http.Method.POST)) {
1575                                            httpMethod = new PostMethod(location);
1576                                    }
1577                                    else {
1578                                            httpMethod = new PutMethod(location);
1579                                    }
1580    
1581                                    if (body != null) {
1582                                            RequestEntity requestEntity = new StringRequestEntity(
1583                                                    body.getContent(), body.getContentType(),
1584                                                    body.getCharset());
1585    
1586                                            EntityEnclosingMethod entityEnclosingMethod =
1587                                                    (EntityEnclosingMethod)httpMethod;
1588    
1589                                            entityEnclosingMethod.setRequestEntity(requestEntity);
1590                                    }
1591                                    else if (method.equals(Http.Method.POST)) {
1592                                            PostMethod postMethod = (PostMethod)httpMethod;
1593    
1594                                            if (!hasRequestHeader(
1595                                                            postMethod, HttpHeaders.CONTENT_TYPE)) {
1596    
1597                                                    HttpClientParams httpClientParams =
1598                                                            httpClient.getParams();
1599    
1600                                                    httpClientParams.setParameter(
1601                                                            HttpMethodParams.HTTP_CONTENT_CHARSET,
1602                                                            StringPool.UTF8);
1603                                            }
1604    
1605                                            processPostMethod(postMethod, fileParts, parts);
1606                                    }
1607                            }
1608                            else if (method.equals(Http.Method.DELETE)) {
1609                                    httpMethod = new DeleteMethod(location);
1610                            }
1611                            else if (method.equals(Http.Method.HEAD)) {
1612                                    httpMethod = new HeadMethod(location);
1613                            }
1614                            else {
1615                                    httpMethod = new GetMethod(location);
1616                            }
1617    
1618                            if (headers != null) {
1619                                    for (Map.Entry<String, String> header : headers.entrySet()) {
1620                                            httpMethod.addRequestHeader(
1621                                                    header.getKey(), header.getValue());
1622                                    }
1623                            }
1624    
1625                            if ((method.equals(Http.Method.POST) ||
1626                                     method.equals(Http.Method.PUT)) &&
1627                                    ((body != null) ||
1628                                     ((fileParts != null) && !fileParts.isEmpty()) ||
1629                                     ((parts != null) && !parts.isEmpty())) &&
1630                                    !hasRequestHeader(httpMethod, HttpHeaders.CONTENT_TYPE)) {
1631    
1632                                    httpMethod.addRequestHeader(
1633                                            HttpHeaders.CONTENT_TYPE,
1634                                            ContentTypes.APPLICATION_X_WWW_FORM_URLENCODED_UTF8);
1635                            }
1636    
1637                            if (!hasRequestHeader(httpMethod, HttpHeaders.USER_AGENT)) {
1638                                    httpMethod.addRequestHeader(
1639                                            HttpHeaders.USER_AGENT, _DEFAULT_USER_AGENT);
1640                            }
1641    
1642                            httpState = new HttpState();
1643    
1644                            if (ArrayUtil.isNotEmpty(cookies)) {
1645                                    org.apache.commons.httpclient.Cookie[] commonsCookies =
1646                                            toCommonsCookies(cookies);
1647    
1648                                    httpState.addCookies(commonsCookies);
1649    
1650                                    HttpMethodParams httpMethodParams = httpMethod.getParams();
1651    
1652                                    httpMethodParams.setCookiePolicy(
1653                                            CookiePolicy.BROWSER_COMPATIBILITY);
1654                            }
1655    
1656                            if (auth != null) {
1657                                    httpMethod.setDoAuthentication(true);
1658    
1659                                    httpState.setCredentials(
1660                                            new AuthScope(
1661                                                    auth.getHost(), auth.getPort(), auth.getRealm()),
1662                                            new UsernamePasswordCredentials(
1663                                                    auth.getUsername(), auth.getPassword()));
1664                            }
1665    
1666                            proxifyState(httpState, hostConfiguration);
1667    
1668                            int responseCode = httpClient.executeMethod(
1669                                    hostConfiguration, httpMethod, httpState);
1670    
1671                            response.setResponseCode(responseCode);
1672    
1673                            Header locationHeader = httpMethod.getResponseHeader("location");
1674    
1675                            if ((locationHeader != null) && !locationHeader.equals(location)) {
1676                                    String redirect = locationHeader.getValue();
1677    
1678                                    if (followRedirects) {
1679                                            return URLtoInputStream(
1680                                                    redirect, Http.Method.GET, headers, cookies, auth, body,
1681                                                    fileParts, parts, response, followRedirects);
1682                                    }
1683                                    else {
1684                                            response.setRedirect(redirect);
1685                                    }
1686                            }
1687    
1688                            long contentLengthLong = 0;
1689    
1690                            Header contentLengthHeader = httpMethod.getResponseHeader(
1691                                    HttpHeaders.CONTENT_LENGTH);
1692    
1693                            if (contentLengthHeader != null) {
1694                                    contentLengthLong = GetterUtil.getLong(
1695                                            contentLengthHeader.getValue());
1696    
1697                                    response.setContentLengthLong(contentLengthLong);
1698    
1699                                    if (contentLengthLong > _MAX_BYTE_ARRAY_LENGTH) {
1700                                            response.setContentLength(-1);
1701                                    }
1702                                    else {
1703                                            int contentLength = (int)contentLengthLong;
1704    
1705                                            response.setContentLength(contentLength);
1706                                    }
1707                            }
1708    
1709                            Header contentType = httpMethod.getResponseHeader(
1710                                    HttpHeaders.CONTENT_TYPE);
1711    
1712                            if (contentType != null) {
1713                                    response.setContentType(contentType.getValue());
1714                            }
1715    
1716                            for (Header header : httpMethod.getResponseHeaders()) {
1717                                    response.addHeader(header.getName(), header.getValue());
1718                            }
1719    
1720                            InputStream inputStream = httpMethod.getResponseBodyAsStream();
1721    
1722                            final HttpMethod referenceHttpMethod = httpMethod;
1723    
1724                            final Reference<InputStream> reference = FinalizeManager.register(
1725                                    inputStream,
1726                                    new FinalizeAction() {
1727    
1728                                            @Override
1729                                            public void doFinalize(Reference<?> reference) {
1730                                                    referenceHttpMethod.releaseConnection();
1731                                            }
1732    
1733                                    },
1734                                    FinalizeManager.WEAK_REFERENCE_FACTORY);
1735    
1736                            return new UnsyncFilterInputStream(inputStream) {
1737    
1738                                    @Override
1739                                    public void close() throws IOException {
1740                                            super.close();
1741    
1742                                            referenceHttpMethod.releaseConnection();
1743    
1744                                            reference.clear();
1745                                    }
1746    
1747                            };
1748                    }
1749                    finally {
1750                            try {
1751                                    if (httpState != null) {
1752                                            _cookies.set(toServletCookies(httpState.getCookies()));
1753                                    }
1754                            }
1755                            catch (Exception e) {
1756                                    _log.error(e, e);
1757                            }
1758                    }
1759            }
1760    
1761            private static final String _DEFAULT_USER_AGENT =
1762                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
1763    
1764            private static final int _MAX_BYTE_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
1765    
1766            private static final int _MAX_CONNECTIONS_PER_HOST = GetterUtil.getInteger(
1767                    PropsUtil.get(HttpImpl.class.getName() + ".max.connections.per.host"),
1768                    2);
1769    
1770            private static final int _MAX_TOTAL_CONNECTIONS = GetterUtil.getInteger(
1771                    PropsUtil.get(HttpImpl.class.getName() + ".max.total.connections"), 20);
1772    
1773            private static final String _NON_PROXY_HOSTS = SystemProperties.get(
1774                    "http.nonProxyHosts");
1775    
1776            private static final String _PROXY_AUTH_TYPE = GetterUtil.getString(
1777                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.auth.type"));
1778    
1779            private static final String _PROXY_HOST = GetterUtil.getString(
1780                    SystemProperties.get("http.proxyHost"));
1781    
1782            private static final String _PROXY_NTLM_DOMAIN = GetterUtil.getString(
1783                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.domain"));
1784    
1785            private static final String _PROXY_NTLM_HOST = GetterUtil.getString(
1786                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.host"));
1787    
1788            private static final String _PROXY_PASSWORD = GetterUtil.getString(
1789                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.password"));
1790    
1791            private static final int _PROXY_PORT = GetterUtil.getInteger(
1792                    SystemProperties.get("http.proxyPort"));
1793    
1794            private static final String _PROXY_USERNAME = GetterUtil.getString(
1795                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.username"));
1796    
1797            private static final String _TEMP_SLASH = "_LIFERAY_TEMP_SLASH_";
1798    
1799            private static final int _TIMEOUT = GetterUtil.getInteger(
1800                    PropsUtil.get(HttpImpl.class.getName() + ".timeout"), 5000);
1801    
1802            private static final Log _log = LogFactoryUtil.getLog(HttpImpl.class);
1803    
1804            private static final ThreadLocal<Cookie[]> _cookies = new ThreadLocal<>();
1805    
1806            private final HttpClient _httpClient = new HttpClient();
1807            private final Pattern _nonProxyHostsPattern;
1808            private final Credentials _proxyCredentials;
1809            private final HttpClient _proxyHttpClient = new HttpClient();
1810    
1811            private static class FastProtocolSocketFactory
1812                    extends DefaultProtocolSocketFactory {
1813    
1814                    @Override
1815                    public Socket createSocket(
1816                                    final String host, final int port,
1817                                    final InetAddress localInetAddress, final int localPort,
1818                                    final HttpConnectionParams httpConnectionParams)
1819                            throws ConnectTimeoutException, IOException, UnknownHostException {
1820    
1821                            int connectionTimeout = httpConnectionParams.getConnectionTimeout();
1822    
1823                            if (connectionTimeout == 0) {
1824                                    return createSocket(host, port, localInetAddress, localPort);
1825                            }
1826    
1827                            SocketFactory socketFactory = SocketFactory.getDefault();
1828    
1829                            Socket socket = socketFactory.createSocket();
1830    
1831                            SocketAddress localSocketAddress = new InetSocketAddress(
1832                                    localInetAddress, localPort);
1833    
1834                            SocketAddress remoteSocketAddress = new InetSocketAddress(
1835                                    host, port);
1836    
1837                            socket.bind(localSocketAddress);
1838    
1839                            socket.connect(remoteSocketAddress, connectionTimeout);
1840    
1841                            return socket;
1842                    }
1843    
1844            }
1845    
1846    }