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