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