001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
019    import com.liferay.portal.kernel.io.unsync.UnsyncFilterInputStream;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.memory.FinalizeAction;
023    import com.liferay.portal.kernel.memory.FinalizeManager;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.servlet.HttpHeaders;
026    import com.liferay.portal.kernel.util.ArrayUtil;
027    import com.liferay.portal.kernel.util.CharPool;
028    import com.liferay.portal.kernel.util.ContentTypes;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.Http;
032    import com.liferay.portal.kernel.util.PortalUtil;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.SystemProperties;
037    import com.liferay.portal.kernel.util.URLCodec;
038    import com.liferay.portal.kernel.util.Validator;
039    
040    import java.io.IOException;
041    import java.io.InputStream;
042    
043    import java.lang.ref.Reference;
044    
045    import java.net.InetAddress;
046    import java.net.InetSocketAddress;
047    import java.net.Socket;
048    import java.net.SocketAddress;
049    import java.net.URL;
050    import java.net.URLConnection;
051    import java.net.UnknownHostException;
052    
053    import java.util.ArrayList;
054    import java.util.Date;
055    import java.util.LinkedHashMap;
056    import java.util.List;
057    import java.util.Map;
058    import java.util.regex.Matcher;
059    import java.util.regex.Pattern;
060    
061    import javax.net.SocketFactory;
062    
063    import javax.portlet.ActionRequest;
064    import javax.portlet.RenderRequest;
065    
066    import javax.servlet.http.Cookie;
067    import javax.servlet.http.HttpServletRequest;
068    import javax.servlet.http.HttpSession;
069    
070    import org.apache.commons.httpclient.ConnectTimeoutException;
071    import org.apache.commons.httpclient.Credentials;
072    import org.apache.commons.httpclient.Header;
073    import org.apache.commons.httpclient.HostConfiguration;
074    import org.apache.commons.httpclient.HttpClient;
075    import org.apache.commons.httpclient.HttpConnectionManager;
076    import org.apache.commons.httpclient.HttpMethod;
077    import org.apache.commons.httpclient.HttpState;
078    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
079    import org.apache.commons.httpclient.NTCredentials;
080    import org.apache.commons.httpclient.URI;
081    import org.apache.commons.httpclient.UsernamePasswordCredentials;
082    import org.apache.commons.httpclient.auth.AuthPolicy;
083    import org.apache.commons.httpclient.auth.AuthScope;
084    import org.apache.commons.httpclient.cookie.CookiePolicy;
085    import org.apache.commons.httpclient.methods.DeleteMethod;
086    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
087    import org.apache.commons.httpclient.methods.GetMethod;
088    import org.apache.commons.httpclient.methods.HeadMethod;
089    import org.apache.commons.httpclient.methods.PostMethod;
090    import org.apache.commons.httpclient.methods.PutMethod;
091    import org.apache.commons.httpclient.methods.RequestEntity;
092    import org.apache.commons.httpclient.methods.StringRequestEntity;
093    import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
094    import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
095    import org.apache.commons.httpclient.methods.multipart.Part;
096    import org.apache.commons.httpclient.methods.multipart.StringPart;
097    import org.apache.commons.httpclient.params.HostParams;
098    import org.apache.commons.httpclient.params.HttpClientParams;
099    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
100    import org.apache.commons.httpclient.params.HttpConnectionParams;
101    import org.apache.commons.httpclient.params.HttpMethodParams;
102    import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
103    import org.apache.commons.httpclient.protocol.Protocol;
104    
105    /**
106     * @author Brian Wing Shun Chan
107     * @author Hugo Huijser
108     * @author Shuyang Zhou
109     */
110    @DoPrivileged
111    public class HttpImpl implements Http {
112    
113            public HttpImpl() {
114    
115                    // Override the default protocol socket factory because it uses
116                    // reflection for JDK 1.4 compatibility, which we do not need. It also
117                    // attemps to create a new socket in a different thread so that we
118                    // cannot track which class loader initiated the call.
119    
120                    Protocol protocol = new Protocol(
121                            "http", new FastProtocolSocketFactory(), 80);
122    
123                    Protocol.registerProtocol("http", protocol);
124    
125                    // Mimic behavior found in
126                    // http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html
127    
128                    if (Validator.isNotNull(_NON_PROXY_HOSTS)) {
129                            String nonProxyHostsRegEx = _NON_PROXY_HOSTS;
130    
131                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\.", "\\\\.");
132                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\*", ".*?");
133                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\|", ")|(");
134    
135                            nonProxyHostsRegEx = "(" + nonProxyHostsRegEx + ")";
136    
137                            _nonProxyHostsPattern = Pattern.compile(nonProxyHostsRegEx);
138                    }
139                    else {
140                            _nonProxyHostsPattern = null;
141                    }
142    
143                    MultiThreadedHttpConnectionManager httpConnectionManager =
144                            new MultiThreadedHttpConnectionManager();
145    
146                    HttpConnectionManagerParams httpConnectionManagerParams =
147                            httpConnectionManager.getParams();
148    
149                    httpConnectionManagerParams.setConnectionTimeout(_TIMEOUT);
150                    httpConnectionManagerParams.setDefaultMaxConnectionsPerHost(
151                            Integer.valueOf(_MAX_CONNECTIONS_PER_HOST));
152                    httpConnectionManagerParams.setMaxTotalConnections(
153                            Integer.valueOf(_MAX_TOTAL_CONNECTIONS));
154                    httpConnectionManagerParams.setSoTimeout(_TIMEOUT);
155    
156                    _httpClient.setHttpConnectionManager(httpConnectionManager);
157                    _proxyHttpClient.setHttpConnectionManager(httpConnectionManager);
158    
159                    if (!hasProxyConfig() || Validator.isNull(_PROXY_USERNAME)) {
160                            _proxyCredentials = null;
161    
162                            return;
163                    }
164    
165                    List<String> authPrefs = new ArrayList<>();
166    
167                    if (_PROXY_AUTH_TYPE.equals("username-password")) {
168                            _proxyCredentials = new UsernamePasswordCredentials(
169                                    _PROXY_USERNAME, _PROXY_PASSWORD);
170    
171                            authPrefs.add(AuthPolicy.BASIC);
172                            authPrefs.add(AuthPolicy.DIGEST);
173                            authPrefs.add(AuthPolicy.NTLM);
174                    }
175                    else if (_PROXY_AUTH_TYPE.equals("ntlm")) {
176                            _proxyCredentials = new NTCredentials(
177                                    _PROXY_USERNAME, _PROXY_PASSWORD, _PROXY_NTLM_HOST,
178                                    _PROXY_NTLM_DOMAIN);
179    
180                            authPrefs.add(AuthPolicy.NTLM);
181                            authPrefs.add(AuthPolicy.BASIC);
182                            authPrefs.add(AuthPolicy.DIGEST);
183                    }
184                    else {
185                            _proxyCredentials = null;
186                    }
187    
188                    HttpClientParams httpClientParams = _proxyHttpClient.getParams();
189    
190                    httpClientParams.setParameter(
191                            AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
192            }
193    
194            @Override
195            public String addParameter(String url, String name, boolean value) {
196                    return addParameter(url, name, String.valueOf(value));
197            }
198    
199            @Override
200            public String addParameter(String url, String name, double value) {
201                    return addParameter(url, name, String.valueOf(value));
202            }
203    
204            @Override
205            public String addParameter(String url, String name, int value) {
206                    return addParameter(url, name, String.valueOf(value));
207            }
208    
209            @Override
210            public String addParameter(String url, String name, long value) {
211                    return addParameter(url, name, String.valueOf(value));
212            }
213    
214            @Override
215            public String addParameter(String url, String name, short value) {
216                    return addParameter(url, name, String.valueOf(value));
217            }
218    
219            @Override
220            public String addParameter(String url, String name, String value) {
221                    if (url == null) {
222                            return null;
223                    }
224    
225                    String[] urlArray = PortalUtil.stripURLAnchor(url, StringPool.POUND);
226    
227                    url = urlArray[0];
228    
229                    String anchor = urlArray[1];
230    
231                    StringBundler sb = new StringBundler(6);
232    
233                    sb.append(url);
234    
235                    if (url.indexOf(CharPool.QUESTION) == -1) {
236                            sb.append(StringPool.QUESTION);
237                    }
238                    else if (!url.endsWith(StringPool.QUESTION) &&
239                                     !url.endsWith(StringPool.AMPERSAND)) {
240    
241                            sb.append(StringPool.AMPERSAND);
242                    }
243    
244                    sb.append(name);
245                    sb.append(StringPool.EQUAL);
246                    sb.append(encodeURL(value));
247                    sb.append(anchor);
248    
249                    String result = sb.toString();
250    
251                    if (result.length() > URL_MAXIMUM_LENGTH) {
252                            result = shortenURL(result, 2);
253                    }
254    
255                    return result;
256            }
257    
258            @Override
259            public String decodePath(String path) {
260                    if (Validator.isNull(path)) {
261                            return path;
262                    }
263    
264                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
265                    path = decodeURL(path, true);
266                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
267    
268                    return path;
269            }
270    
271            @Override
272            public String decodeURL(String url) {
273                    return decodeURL(url, false);
274            }
275    
276            /**
277             * @deprecated As of 7.0.0, replaced by {@link #decodeURL(String)}
278             */
279            @Deprecated
280            @Override
281            public String decodeURL(String url, boolean unescapeSpaces) {
282                    if (Validator.isNull(url)) {
283                            return url;
284                    }
285    
286                    return URLCodec.decodeURL(url, StringPool.UTF8);
287            }
288    
289            public void destroy() {
290                    MultiThreadedHttpConnectionManager.shutdownAll();
291            }
292    
293            @Override
294            public String encodeParameters(String url) {
295                    if (Validator.isNull(url)) {
296                            return url;
297                    }
298    
299                    String queryString = getQueryString(url);
300    
301                    if (Validator.isNull(queryString)) {
302                            return url;
303                    }
304    
305                    String encodedQueryString = parameterMapToString(
306                            parameterMapFromString(queryString), false);
307    
308                    return StringUtil.replace(url, queryString, encodedQueryString);
309            }
310    
311            @Override
312            public String encodePath(String path) {
313                    if (Validator.isNull(path)) {
314                            return path;
315                    }
316    
317                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
318                    path = encodeURL(path, true);
319                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
320    
321                    return path;
322            }
323    
324            @Override
325            public String encodeURL(String url) {
326                    return encodeURL(url, false);
327            }
328    
329            @Override
330            public String encodeURL(String url, boolean escapeSpaces) {
331                    if (Validator.isNull(url)) {
332                            return url;
333                    }
334    
335                    return URLCodec.encodeURL(url, StringPool.UTF8, escapeSpaces);
336            }
337    
338            @Override
339            public String fixPath(String path) {
340                    return fixPath(path, true, true);
341            }
342    
343            @Override
344            public String fixPath(String path, boolean leading, boolean trailing) {
345                    if (path == null) {
346                            return StringPool.BLANK;
347                    }
348    
349                    int leadingSlashCount = 0;
350                    int trailingSlashCount = 0;
351    
352                    if (leading) {
353                            for (int i = 0; i < path.length(); i++) {
354                                    if (path.charAt(i) == CharPool.SLASH) {
355                                            leadingSlashCount++;
356                                    }
357                                    else {
358                                            break;
359                                    }
360                            }
361                    }
362    
363                    if (trailing) {
364                            for (int i = path.length() - 1; i >= 0; i--) {
365                                    if (path.charAt(i) == CharPool.SLASH) {
366                                            trailingSlashCount++;
367                                    }
368                                    else {
369                                            break;
370                                    }
371                            }
372                    }
373    
374                    int slashCount = leadingSlashCount + trailingSlashCount;
375    
376                    if (slashCount > path.length()) {
377                            return StringPool.BLANK;
378                    }
379    
380                    if (slashCount > 0) {
381                            path = path.substring(
382                                    leadingSlashCount, path.length() - trailingSlashCount);
383                    }
384    
385                    return path;
386            }
387    
388            public HttpClient getClient(HostConfiguration hostConfiguration) {
389                    if (isProxyHost(hostConfiguration.getHost())) {
390                            return _proxyHttpClient;
391                    }
392    
393                    return _httpClient;
394            }
395    
396            @Override
397            public String getCompleteURL(HttpServletRequest request) {
398                    StringBuffer sb = request.getRequestURL();
399    
400                    if (sb == null) {
401                            sb = new StringBuffer();
402                    }
403    
404                    if (request.getQueryString() != null) {
405                            sb.append(StringPool.QUESTION);
406                            sb.append(request.getQueryString());
407                    }
408    
409                    String proxyPath = PortalUtil.getPathProxy();
410    
411                    if (Validator.isNotNull(proxyPath)) {
412                            int x =
413                                    sb.indexOf(Http.PROTOCOL_DELIMITER) +
414                                            Http.PROTOCOL_DELIMITER.length();
415                            int y = sb.indexOf(StringPool.SLASH, x);
416    
417                            sb.insert(y, proxyPath);
418                    }
419    
420                    String completeURL = sb.toString();
421    
422                    if (request.isRequestedSessionIdFromURL()) {
423                            HttpSession session = request.getSession();
424    
425                            String sessionId = session.getId();
426    
427                            completeURL = PortalUtil.getURLWithSessionId(
428                                    completeURL, sessionId);
429                    }
430    
431                    if (_log.isWarnEnabled()) {
432                            if (completeURL.contains("?&")) {
433                                    _log.warn("Invalid url " + completeURL);
434                            }
435                    }
436    
437                    return completeURL;
438            }
439    
440            @Override
441            public Cookie[] getCookies() {
442                    return _cookies.get();
443            }
444    
445            @Override
446            public String getDomain(String url) {
447                    if (Validator.isNull(url)) {
448                            return url;
449                    }
450    
451                    url = removeProtocol(url);
452    
453                    int pos = url.indexOf(CharPool.SLASH);
454    
455                    if (pos != -1) {
456                            return url.substring(0, pos);
457                    }
458    
459                    return url;
460            }
461    
462            /**
463             * @deprecated As of 6.1.0, replaced by {@link
464             *             #getHostConfiguration(String)}
465             */
466            @Deprecated
467            public HostConfiguration getHostConfig(String location) throws IOException {
468                    return getHostConfiguration(location);
469            }
470    
471            public HostConfiguration getHostConfiguration(String location)
472                    throws IOException {
473    
474                    if (_log.isDebugEnabled()) {
475                            _log.debug("Location is " + location);
476                    }
477    
478                    HostConfiguration hostConfiguration = new HostConfiguration();
479    
480                    hostConfiguration.setHost(new URI(location, false));
481    
482                    if (isProxyHost(hostConfiguration.getHost())) {
483                            hostConfiguration.setProxy(_PROXY_HOST, _PROXY_PORT);
484                    }
485    
486                    HttpConnectionManager httpConnectionManager =
487                            _httpClient.getHttpConnectionManager();
488    
489                    HttpConnectionManagerParams httpConnectionManagerParams =
490                            httpConnectionManager.getParams();
491    
492                    int defaultMaxConnectionsPerHost =
493                            httpConnectionManagerParams.getMaxConnectionsPerHost(
494                                    hostConfiguration);
495    
496                    int maxConnectionsPerHost = GetterUtil.getInteger(
497                            PropsUtil.get(
498                                    HttpImpl.class.getName() + ".max.connections.per.host",
499                                    new Filter(hostConfiguration.getHost())));
500    
501                    if ((maxConnectionsPerHost > 0) &&
502                            (maxConnectionsPerHost != defaultMaxConnectionsPerHost)) {
503    
504                            httpConnectionManagerParams.setMaxConnectionsPerHost(
505                                    hostConfiguration, maxConnectionsPerHost);
506                    }
507    
508                    int timeout = GetterUtil.getInteger(
509                            PropsUtil.get(
510                                    HttpImpl.class.getName() + ".timeout",
511                                    new Filter(hostConfiguration.getHost())));
512    
513                    if (timeout > 0) {
514                            HostParams hostParams = hostConfiguration.getParams();
515    
516                            hostParams.setIntParameter(
517                                    HttpConnectionParams.CONNECTION_TIMEOUT, timeout);
518                            hostParams.setIntParameter(
519                                    HttpConnectionParams.SO_TIMEOUT, timeout);
520                    }
521    
522                    return hostConfiguration;
523            }
524    
525            @Override
526            public String getIpAddress(String url) {
527                    if (Validator.isNull(url)) {
528                            return url;
529                    }
530    
531                    try {
532                            URL urlObj = new URL(url);
533    
534                            InetAddress address = InetAddress.getByName(urlObj.getHost());
535    
536                            return address.getHostAddress();
537                    }
538                    catch (Exception e) {
539                            return url;
540                    }
541            }
542    
543            @Override
544            public String getParameter(String url, String name) {
545                    return getParameter(url, name, true);
546            }
547    
548            @Override
549            public String getParameter(String url, String name, boolean escaped) {
550                    if (Validator.isNull(url) || Validator.isNull(name)) {
551                            return StringPool.BLANK;
552                    }
553    
554                    String[] parts = StringUtil.split(url, CharPool.QUESTION);
555    
556                    if (parts.length == 2) {
557                            String[] params = null;
558    
559                            if (escaped) {
560                                    params = StringUtil.split(parts[1], "&amp;");
561                            }
562                            else {
563                                    params = StringUtil.split(parts[1], CharPool.AMPERSAND);
564                            }
565    
566                            for (String param : params) {
567                                    String[] kvp = StringUtil.split(param, CharPool.EQUAL);
568    
569                                    if ((kvp.length == 2) && kvp[0].equals(name)) {
570                                            return kvp[1];
571                                    }
572                            }
573                    }
574    
575                    return StringPool.BLANK;
576            }
577    
578            @Override
579            public Map<String, String[]> getParameterMap(String queryString) {
580                    return parameterMapFromString(queryString);
581            }
582    
583            @Override
584            public String getPath(String url) {
585                    if (Validator.isNull(url)) {
586                            return url;
587                    }
588    
589                    if (url.startsWith(Http.HTTP)) {
590                            int pos = url.indexOf(
591                                    CharPool.SLASH, Http.HTTPS_WITH_SLASH.length());
592    
593                            url = url.substring(pos);
594                    }
595    
596                    int pos = url.indexOf(CharPool.QUESTION);
597    
598                    if (pos == -1) {
599                            return url;
600                    }
601    
602                    return url.substring(0, pos);
603            }
604    
605            @Override
606            public String getProtocol(ActionRequest actionRequest) {
607                    return getProtocol(actionRequest.isSecure());
608            }
609    
610            @Override
611            public String getProtocol(boolean secure) {
612                    if (!secure) {
613                            return Http.HTTP;
614                    }
615    
616                    return Http.HTTPS;
617            }
618    
619            @Override
620            public String getProtocol(HttpServletRequest request) {
621                    return getProtocol(request.isSecure());
622            }
623    
624            @Override
625            public String getProtocol(RenderRequest renderRequest) {
626                    return getProtocol(renderRequest.isSecure());
627            }
628    
629            @Override
630            public String getProtocol(String url) {
631                    if (Validator.isNull(url)) {
632                            return url;
633                    }
634    
635                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
636    
637                    if (pos != -1) {
638                            return url.substring(0, pos);
639                    }
640    
641                    return Http.HTTP;
642            }
643    
644            @Override
645            public String getQueryString(String url) {
646                    if (Validator.isNull(url)) {
647                            return url;
648                    }
649    
650                    int pos = url.indexOf(CharPool.QUESTION);
651    
652                    if (pos == -1) {
653                            return StringPool.BLANK;
654                    }
655    
656                    return url.substring(pos + 1);
657            }
658    
659            @Override
660            public String getRequestURL(HttpServletRequest request) {
661                    return String.valueOf(request.getRequestURL());
662            }
663    
664            @Override
665            public boolean hasDomain(String url) {
666                    if (Validator.isNull(url)) {
667                            return false;
668                    }
669    
670                    return Validator.isNotNull(getDomain(url));
671            }
672    
673            @Override
674            public boolean hasProtocol(String url) {
675                    if (Validator.isNull(url)) {
676                            return false;
677                    }
678    
679                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
680    
681                    if (pos != -1) {
682                            return true;
683                    }
684    
685                    return false;
686            }
687    
688            @Override
689            public boolean hasProxyConfig() {
690                    if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
691                            return true;
692                    }
693    
694                    return false;
695            }
696    
697            @Override
698            public boolean isNonProxyHost(String host) {
699                    if (Validator.isNull(host)) {
700                            return false;
701                    }
702    
703                    if (_nonProxyHostsPattern != null) {
704                            Matcher matcher = _nonProxyHostsPattern.matcher(host);
705    
706                            if (matcher.matches()) {
707                                    return true;
708                            }
709                    }
710    
711                    return false;
712            }
713    
714            @Override
715            public boolean isProxyHost(String host) {
716                    if (Validator.isNull(host)) {
717                            return false;
718                    }
719    
720                    if (hasProxyConfig() && !isNonProxyHost(host)) {
721                            return true;
722                    }
723    
724                    return false;
725            }
726    
727            @Override
728            public boolean isSecure(String url) {
729                    String protocol = getProtocol(url);
730    
731                    return StringUtil.equalsIgnoreCase(protocol, Http.HTTPS);
732            }
733    
734            @Override
735            public String normalizePath(String uri) {
736                    if (Validator.isNull(uri)) {
737                            return uri;
738                    }
739    
740                    uri = removePathParameters(uri);
741    
742                    String path = null;
743                    String queryString = null;
744    
745                    int pos = uri.indexOf('?');
746    
747                    if (pos != -1) {
748                            path = uri.substring(0, pos);
749                            queryString = uri.substring(pos + 1);
750                    }
751                    else {
752                            path = uri;
753                    }
754    
755                    String[] uriParts = StringUtil.split(path.substring(1), CharPool.SLASH);
756    
757                    List<String> parts = new ArrayList<>(uriParts.length);
758    
759                    String prevUriPart = null;
760    
761                    for (String uriPart : uriParts) {
762                            String curUriPart = URLCodec.decodeURL(uriPart);
763    
764                            if (curUriPart.equals(StringPool.DOUBLE_PERIOD)) {
765                                    if ((prevUriPart != null) &&
766                                            !prevUriPart.equals(StringPool.PERIOD)) {
767    
768                                            parts.remove(parts.size() - 1);
769                                    }
770                            }
771                            else if ((curUriPart.length() > 0) &&
772                                             !curUriPart.equals(StringPool.PERIOD)) {
773    
774                                    parts.add(URLCodec.encodeURL(curUriPart));
775                            }
776    
777                            prevUriPart = curUriPart;
778                    }
779    
780                    if (parts.isEmpty()) {
781                            return StringPool.SLASH;
782                    }
783    
784                    StringBundler sb = new StringBundler(parts.size() * 2 + 2);
785    
786                    for (String part : parts) {
787                            sb.append(StringPool.SLASH);
788                            sb.append(part);
789                    }
790    
791                    if (Validator.isNotNull(queryString)) {
792                            sb.append(StringPool.QUESTION);
793                            sb.append(queryString);
794                    }
795    
796                    return sb.toString();
797            }
798    
799            @Override
800            public Map<String, String[]> parameterMapFromString(String queryString) {
801                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
802    
803                    if (Validator.isNull(queryString)) {
804                            return parameterMap;
805                    }
806    
807                    Map<String, List<String>> tempParameterMap = new LinkedHashMap<>();
808    
809                    String[] parameters = StringUtil.split(queryString, CharPool.AMPERSAND);
810    
811                    for (String parameter : parameters) {
812                            if (parameter.length() > 0) {
813                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
814    
815                                    if (kvp.length == 0) {
816                                            continue;
817                                    }
818    
819                                    String key = kvp[0];
820    
821                                    String value = StringPool.BLANK;
822    
823                                    if (kvp.length > 1) {
824                                            try {
825                                                    value = decodeURL(kvp[1]);
826                                            }
827                                            catch (IllegalArgumentException iae) {
828                                                    if (_log.isInfoEnabled()) {
829                                                            _log.info(
830                                                                    "Skipping parameter with key " + key +
831                                                                            " because of invalid value " + kvp[1],
832                                                                    iae);
833                                                    }
834    
835                                                    continue;
836                                            }
837                                    }
838    
839                                    List<String> values = tempParameterMap.get(key);
840    
841                                    if (values == null) {
842                                            values = new ArrayList<>();
843    
844                                            tempParameterMap.put(key, values);
845                                    }
846    
847                                    values.add(value);
848                            }
849                    }
850    
851                    for (Map.Entry<String, List<String>> entry :
852                                    tempParameterMap.entrySet()) {
853    
854                            String key = entry.getKey();
855                            List<String> values = entry.getValue();
856    
857                            parameterMap.put(key, values.toArray(new String[values.size()]));
858                    }
859    
860                    return parameterMap;
861            }
862    
863            @Override
864            public String parameterMapToString(Map<String, String[]> parameterMap) {
865                    return parameterMapToString(parameterMap, true);
866            }
867    
868            @Override
869            public String parameterMapToString(
870                    Map<String, String[]> parameterMap, boolean addQuestion) {
871    
872                    if (parameterMap.isEmpty()) {
873                            return StringPool.BLANK;
874                    }
875    
876                    StringBundler sb = new StringBundler();
877    
878                    if (addQuestion) {
879                            sb.append(StringPool.QUESTION);
880                    }
881    
882                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
883                            String name = entry.getKey();
884                            String[] values = entry.getValue();
885    
886                            for (String value : values) {
887                                    sb.append(name);
888                                    sb.append(StringPool.EQUAL);
889                                    sb.append(encodeURL(value));
890                                    sb.append(StringPool.AMPERSAND);
891                            }
892                    }
893    
894                    if (sb.index() > 1) {
895                            sb.setIndex(sb.index() - 1);
896                    }
897    
898                    return sb.toString();
899            }
900    
901            @Override
902            public String protocolize(String url, ActionRequest actionRequest) {
903                    return protocolize(url, actionRequest.isSecure());
904            }
905    
906            @Override
907            public String protocolize(String url, boolean secure) {
908                    return protocolize(url, -1, secure);
909            }
910    
911            @Override
912            public String protocolize(String url, HttpServletRequest request) {
913                    return protocolize(url, request.isSecure());
914            }
915    
916            @Override
917            public String protocolize(String url, int port, boolean secure) {
918                    if (Validator.isNull(url)) {
919                            return url;
920                    }
921    
922                    try {
923                            URL urlObj = new URL(url);
924    
925                            String protocol = Http.HTTP;
926    
927                            if (secure) {
928                                    protocol = Http.HTTPS;
929                            }
930    
931                            if (port == -1) {
932                                    port = urlObj.getPort();
933                            }
934    
935                            urlObj = new URL(
936                                    protocol, urlObj.getHost(), port, urlObj.getFile());
937    
938                            return urlObj.toString();
939                    }
940                    catch (Exception e) {
941                            return url;
942                    }
943            }
944    
945            @Override
946            public String protocolize(String url, RenderRequest renderRequest) {
947                    return protocolize(url, renderRequest.isSecure());
948            }
949    
950            public void proxifyState(
951                    HttpState httpState, HostConfiguration hostConfiguration) {
952    
953                    Credentials proxyCredentials = _proxyCredentials;
954    
955                    String host = hostConfiguration.getHost();
956    
957                    if (isProxyHost(host) && (proxyCredentials != null)) {
958                            AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
959    
960                            httpState.setProxyCredentials(scope, proxyCredentials);
961                    }
962            }
963    
964            @Override
965            public String removeDomain(String url) {
966                    if (Validator.isNull(url)) {
967                            return url;
968                    }
969    
970                    url = removeProtocol(url);
971    
972                    int pos = url.indexOf(CharPool.SLASH);
973    
974                    if (pos > 0) {
975                            return url.substring(pos);
976                    }
977    
978                    return url;
979            }
980    
981            @Override
982            public String removeParameter(String url, String name) {
983                    if (Validator.isNull(url) || Validator.isNull(name)) {
984                            return url;
985                    }
986    
987                    int pos = url.indexOf(CharPool.QUESTION);
988    
989                    if (pos == -1) {
990                            return url;
991                    }
992    
993                    String[] array = PortalUtil.stripURLAnchor(url, StringPool.POUND);
994    
995                    url = array[0];
996    
997                    String anchor = array[1];
998    
999                    StringBundler sb = new StringBundler();
1000    
1001                    sb.append(url.substring(0, pos + 1));
1002    
1003                    String[] parameters = StringUtil.split(
1004                            url.substring(pos + 1, url.length()), CharPool.AMPERSAND);
1005    
1006                    for (String parameter : parameters) {
1007                            if (parameter.length() > 0) {
1008                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
1009    
1010                                    String key = kvp[0];
1011    
1012                                    String value = StringPool.BLANK;
1013    
1014                                    if (kvp.length > 1) {
1015                                            value = kvp[1];
1016                                    }
1017    
1018                                    if (!key.equals(name)) {
1019                                            sb.append(key);
1020                                            sb.append(StringPool.EQUAL);
1021                                            sb.append(value);
1022                                            sb.append(StringPool.AMPERSAND);
1023                                    }
1024                            }
1025                    }
1026    
1027                    url = StringUtil.replace(
1028                            sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
1029                            StringPool.AMPERSAND);
1030    
1031                    if (url.endsWith(StringPool.AMPERSAND)) {
1032                            url = url.substring(0, url.length() - 1);
1033                    }
1034    
1035                    if (url.endsWith(StringPool.QUESTION)) {
1036                            url = url.substring(0, url.length() - 1);
1037                    }
1038    
1039                    return url + anchor;
1040            }
1041    
1042            @Override
1043            public String removePathParameters(String uri) {
1044                    if (Validator.isNull(uri)) {
1045                            return uri;
1046                    }
1047    
1048                    int pos = uri.indexOf(CharPool.SEMICOLON);
1049    
1050                    if (pos == -1) {
1051                            return uri;
1052                    }
1053    
1054                    String[] uriParts = StringUtil.split(uri.substring(1), CharPool.SLASH);
1055    
1056                    StringBundler sb = new StringBundler(uriParts.length * 2);
1057    
1058                    for (String uriPart : uriParts) {
1059                            pos = uriPart.indexOf(CharPool.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 = StringUtil.split(url, CharPool.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(CharPool.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 static 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    }