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