001    /**
002     * Copyright (c) 2000-2013 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.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022    import com.liferay.portal.kernel.servlet.HttpHeaders;
023    import com.liferay.portal.kernel.util.CharPool;
024    import com.liferay.portal.kernel.util.ContentTypes;
025    import com.liferay.portal.kernel.util.FileUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.Http;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.SystemProperties;
032    import com.liferay.portal.kernel.util.URLCodec;
033    import com.liferay.portal.kernel.util.Validator;
034    
035    import java.io.IOException;
036    import java.io.InputStream;
037    
038    import java.net.InetAddress;
039    import java.net.InetSocketAddress;
040    import java.net.Socket;
041    import java.net.SocketAddress;
042    import java.net.URL;
043    import java.net.URLConnection;
044    import java.net.UnknownHostException;
045    
046    import java.util.ArrayList;
047    import java.util.Date;
048    import java.util.LinkedHashMap;
049    import java.util.List;
050    import java.util.Map;
051    import java.util.regex.Matcher;
052    import java.util.regex.Pattern;
053    
054    import javax.net.SocketFactory;
055    
056    import javax.portlet.ActionRequest;
057    import javax.portlet.RenderRequest;
058    
059    import javax.servlet.http.Cookie;
060    import javax.servlet.http.HttpServletRequest;
061    import javax.servlet.http.HttpSession;
062    
063    import org.apache.commons.httpclient.ConnectTimeoutException;
064    import org.apache.commons.httpclient.Credentials;
065    import org.apache.commons.httpclient.Header;
066    import org.apache.commons.httpclient.HostConfiguration;
067    import org.apache.commons.httpclient.HttpClient;
068    import org.apache.commons.httpclient.HttpConnectionManager;
069    import org.apache.commons.httpclient.HttpMethod;
070    import org.apache.commons.httpclient.HttpState;
071    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
072    import org.apache.commons.httpclient.NTCredentials;
073    import org.apache.commons.httpclient.URI;
074    import org.apache.commons.httpclient.UsernamePasswordCredentials;
075    import org.apache.commons.httpclient.auth.AuthPolicy;
076    import org.apache.commons.httpclient.auth.AuthScope;
077    import org.apache.commons.httpclient.cookie.CookiePolicy;
078    import org.apache.commons.httpclient.methods.DeleteMethod;
079    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
080    import org.apache.commons.httpclient.methods.GetMethod;
081    import org.apache.commons.httpclient.methods.HeadMethod;
082    import org.apache.commons.httpclient.methods.PostMethod;
083    import org.apache.commons.httpclient.methods.PutMethod;
084    import org.apache.commons.httpclient.methods.RequestEntity;
085    import org.apache.commons.httpclient.methods.StringRequestEntity;
086    import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
087    import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
088    import org.apache.commons.httpclient.methods.multipart.Part;
089    import org.apache.commons.httpclient.methods.multipart.StringPart;
090    import org.apache.commons.httpclient.params.HostParams;
091    import org.apache.commons.httpclient.params.HttpClientParams;
092    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
093    import org.apache.commons.httpclient.params.HttpConnectionParams;
094    import org.apache.commons.httpclient.params.HttpMethodParams;
095    import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
096    import org.apache.commons.httpclient.protocol.Protocol;
097    
098    /**
099     * @author Brian Wing Shun Chan
100     * @author Hugo Huijser
101     */
102    @DoPrivileged
103    public class HttpImpl implements Http {
104    
105            public HttpImpl() {
106    
107                    // Override the default protocol socket factory because it uses
108                    // reflection for JDK 1.4 compatibility, which we do not need. It also
109                    // attemps to create a new socket in a different thread so that we
110                    // cannot track which class loader initiated the call.
111    
112                    Protocol protocol = new Protocol(
113                            "http", new FastProtocolSocketFactory(), 80);
114    
115                    Protocol.registerProtocol("http", protocol);
116    
117                    // Mimic behavior found in
118                    // http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html
119    
120                    if (Validator.isNotNull(_NON_PROXY_HOSTS)) {
121                            String nonProxyHostsRegEx = _NON_PROXY_HOSTS;
122    
123                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\.", "\\\\.");
124                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\*", ".*?");
125                            nonProxyHostsRegEx = nonProxyHostsRegEx.replaceAll("\\|", ")|(");
126    
127                            nonProxyHostsRegEx = "(" + nonProxyHostsRegEx + ")";
128    
129                            _nonProxyHostsPattern = Pattern.compile(nonProxyHostsRegEx);
130                    }
131    
132                    MultiThreadedHttpConnectionManager httpConnectionManager =
133                            new MultiThreadedHttpConnectionManager();
134    
135                    HttpConnectionManagerParams httpConnectionManagerParams =
136                            httpConnectionManager.getParams();
137    
138                    httpConnectionManagerParams.setConnectionTimeout(_TIMEOUT);
139                    httpConnectionManagerParams.setDefaultMaxConnectionsPerHost(
140                            new Integer(_MAX_CONNECTIONS_PER_HOST));
141                    httpConnectionManagerParams.setMaxTotalConnections(
142                            new Integer(_MAX_TOTAL_CONNECTIONS));
143                    httpConnectionManagerParams.setSoTimeout(_TIMEOUT);
144    
145                    _httpClient.setHttpConnectionManager(httpConnectionManager);
146                    _proxyHttpClient.setHttpConnectionManager(httpConnectionManager);
147    
148                    if (hasProxyConfig() && Validator.isNotNull(_PROXY_USERNAME)) {
149                            List<String> authPrefs = new ArrayList<String>();
150    
151                            if (_PROXY_AUTH_TYPE.equals("username-password")) {
152                                    _proxyCredentials = new UsernamePasswordCredentials(
153                                            _PROXY_USERNAME, _PROXY_PASSWORD);
154    
155                                    authPrefs.add(AuthPolicy.BASIC);
156                                    authPrefs.add(AuthPolicy.DIGEST);
157                                    authPrefs.add(AuthPolicy.NTLM);
158                            }
159                            else if (_PROXY_AUTH_TYPE.equals("ntlm")) {
160                                    _proxyCredentials = new NTCredentials(
161                                            _PROXY_USERNAME, _PROXY_PASSWORD, _PROXY_NTLM_HOST,
162                                            _PROXY_NTLM_DOMAIN);
163    
164                                    authPrefs.add(AuthPolicy.NTLM);
165                                    authPrefs.add(AuthPolicy.BASIC);
166                                    authPrefs.add(AuthPolicy.DIGEST);
167                            }
168    
169                            HttpClientParams httpClientParams = _proxyHttpClient.getParams();
170    
171                            httpClientParams.setParameter(
172                                    AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
173                    }
174            }
175    
176            public String addParameter(String url, String name, boolean value) {
177                    return addParameter(url, name, String.valueOf(value));
178            }
179    
180            public String addParameter(String url, String name, double value) {
181                    return addParameter(url, name, String.valueOf(value));
182            }
183    
184            public String addParameter(String url, String name, int value) {
185                    return addParameter(url, name, String.valueOf(value));
186            }
187    
188            public String addParameter(String url, String name, long value) {
189                    return addParameter(url, name, String.valueOf(value));
190            }
191    
192            public String addParameter(String url, String name, short value) {
193                    return addParameter(url, name, String.valueOf(value));
194            }
195    
196            public String addParameter(String url, String name, String value) {
197                    if (url == null) {
198                            return null;
199                    }
200    
201                    String[] urlArray = PortalUtil.stripURLAnchor(url, StringPool.POUND);
202    
203                    url = urlArray[0];
204    
205                    String anchor = urlArray[1];
206    
207                    StringBundler sb = new StringBundler(7);
208    
209                    sb.append(url);
210    
211                    if (url.indexOf(CharPool.QUESTION) == -1) {
212                            sb.append(StringPool.QUESTION);
213                    }
214                    else if (!url.endsWith(StringPool.QUESTION) &&
215                                     !url.endsWith(StringPool.AMPERSAND)) {
216    
217                            sb.append(StringPool.AMPERSAND);
218                    }
219    
220                    sb.append(name);
221                    sb.append(StringPool.EQUAL);
222                    sb.append(encodeURL(value));
223                    sb.append(anchor);
224    
225                    return sb.toString();
226            }
227    
228            public String decodePath(String path) {
229                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
230                    path = decodeURL(path, true);
231                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
232    
233                    return path;
234            }
235    
236            public String decodeURL(String url) {
237                    return decodeURL(url, false);
238            }
239    
240            public String decodeURL(String url, boolean unescapeSpaces) {
241                    return URLCodec.decodeURL(url, StringPool.UTF8, unescapeSpaces);
242            }
243    
244            public void destroy() {
245                    MultiThreadedHttpConnectionManager.shutdownAll();
246            }
247    
248            public String encodePath(String path) {
249                    path = StringUtil.replace(path, StringPool.SLASH, _TEMP_SLASH);
250                    path = encodeURL(path, true);
251                    path = StringUtil.replace(path, _TEMP_SLASH, StringPool.SLASH);
252    
253                    return path;
254            }
255    
256            public String encodeURL(String url) {
257                    return encodeURL(url, false);
258            }
259    
260            public String encodeURL(String url, boolean escapeSpaces) {
261                    return URLCodec.encodeURL(url, StringPool.UTF8, escapeSpaces);
262            }
263    
264            public String fixPath(String path) {
265                    return fixPath(path, true, true);
266            }
267    
268            public String fixPath(String path, boolean leading, boolean trailing) {
269                    if (path == null) {
270                            return StringPool.BLANK;
271                    }
272    
273                    int leadingSlashCount = 0;
274                    int trailingSlashCount = 0;
275    
276                    if (leading) {
277                            for (int i = 0; i < path.length(); i++) {
278                                    if (path.charAt(i) == CharPool.SLASH) {
279                                            leadingSlashCount++;
280                                    }
281                                    else {
282                                            break;
283                                    }
284                            }
285                    }
286    
287                    if (trailing) {
288                            for (int i = path.length() - 1; i >=0; i--) {
289                                    if (path.charAt(i) == CharPool.SLASH) {
290                                            trailingSlashCount++;
291                                    }
292                                    else {
293                                            break;
294                                    }
295                            }
296                    }
297    
298                    int slashCount = leadingSlashCount + trailingSlashCount;
299    
300                    if (slashCount > path.length()) {
301                            return StringPool.BLANK;
302                    }
303    
304                    if (slashCount > 0) {
305                            path = path.substring(
306                                    leadingSlashCount, path.length() - trailingSlashCount);
307                    }
308    
309                    return path;
310            }
311    
312            public HttpClient getClient(HostConfiguration hostConfiguration) {
313                    if (isProxyHost(hostConfiguration.getHost())) {
314                            return _proxyHttpClient;
315                    }
316                    else {
317                            return _httpClient;
318                    }
319            }
320    
321            public String getCompleteURL(HttpServletRequest request) {
322                    StringBuffer sb = request.getRequestURL();
323    
324                    if (sb == null) {
325                            sb = new StringBuffer();
326                    }
327    
328                    if (request.getQueryString() != null) {
329                            sb.append(StringPool.QUESTION);
330                            sb.append(request.getQueryString());
331                    }
332    
333                    String proxyPath = PortalUtil.getPathProxy();
334    
335                    if (Validator.isNotNull(proxyPath)) {
336                            int x =
337                                    sb.indexOf(Http.PROTOCOL_DELIMITER) +
338                                            Http.PROTOCOL_DELIMITER.length();
339                            int y = sb.indexOf(StringPool.SLASH, x);
340    
341                            sb.insert(y, proxyPath);
342                    }
343    
344                    String completeURL = sb.toString();
345    
346                    if (request.isRequestedSessionIdFromURL()) {
347                            HttpSession session = request.getSession();
348    
349                            String sessionId = session.getId();
350    
351                            completeURL = PortalUtil.getURLWithSessionId(
352                                    completeURL, sessionId);
353                    }
354    
355                    if (_log.isWarnEnabled()) {
356                            if (completeURL.contains("?&")) {
357                                    _log.warn("Invalid url " + completeURL);
358                            }
359                    }
360    
361                    return completeURL;
362            }
363    
364            public Cookie[] getCookies() {
365                    return _cookies.get();
366            }
367    
368            public String getDomain(String url) {
369                    url = removeProtocol(url);
370    
371                    int pos = url.indexOf(CharPool.SLASH);
372    
373                    if (pos != -1) {
374                            return url.substring(0, pos);
375                    }
376                    else {
377                            return url;
378                    }
379            }
380    
381            /**
382             * @deprecated As of 6.1.0, replaced by {@link
383             *             #getHostConfiguration(String)}
384             */
385            public HostConfiguration getHostConfig(String location) throws IOException {
386                    return getHostConfiguration(location);
387            }
388    
389            public HostConfiguration getHostConfiguration(String location)
390                    throws IOException {
391    
392                    if (_log.isDebugEnabled()) {
393                            _log.debug("Location is " + location);
394                    }
395    
396                    HostConfiguration hostConfiguration = new HostConfiguration();
397    
398                    hostConfiguration.setHost(new URI(location, false));
399    
400                    if (isProxyHost(hostConfiguration.getHost())) {
401                            hostConfiguration.setProxy(_PROXY_HOST, _PROXY_PORT);
402                    }
403    
404                    HttpConnectionManager httpConnectionManager =
405                            _httpClient.getHttpConnectionManager();
406    
407                    HttpConnectionManagerParams httpConnectionManagerParams =
408                            httpConnectionManager.getParams();
409    
410                    int defaultMaxConnectionsPerHost =
411                            httpConnectionManagerParams.getMaxConnectionsPerHost(
412                                    hostConfiguration);
413    
414                    int maxConnectionsPerHost = GetterUtil.getInteger(
415                            PropsUtil.get(
416                                    HttpImpl.class.getName() + ".max.connections.per.host",
417                                    new Filter(hostConfiguration.getHost())));
418    
419                    if ((maxConnectionsPerHost > 0) &&
420                            (maxConnectionsPerHost != defaultMaxConnectionsPerHost)) {
421    
422                            httpConnectionManagerParams.setMaxConnectionsPerHost(
423                                    hostConfiguration, maxConnectionsPerHost);
424                    }
425    
426                    int timeout = GetterUtil.getInteger(
427                            PropsUtil.get(
428                                    HttpImpl.class.getName() + ".timeout",
429                                    new Filter(hostConfiguration.getHost())));
430    
431                    if (timeout > 0) {
432                            HostParams hostParams = hostConfiguration.getParams();
433    
434                            hostParams.setIntParameter(
435                                    HttpConnectionParams.CONNECTION_TIMEOUT, timeout);
436                            hostParams.setIntParameter(
437                                    HttpConnectionParams.SO_TIMEOUT, timeout);
438                    }
439    
440                    return hostConfiguration;
441            }
442    
443            public String getIpAddress(String url) {
444                    try {
445                            URL urlObj = new URL(url);
446    
447                            InetAddress address = InetAddress.getByName(urlObj.getHost());
448    
449                            return address.getHostAddress();
450                    }
451                    catch (Exception e) {
452                            return url;
453                    }
454            }
455    
456            public String getParameter(String url, String name) {
457                    return getParameter(url, name, true);
458            }
459    
460            public String getParameter(String url, String name, boolean escaped) {
461                    if (Validator.isNull(url) || Validator.isNull(name)) {
462                            return StringPool.BLANK;
463                    }
464    
465                    String[] parts = StringUtil.split(url, CharPool.QUESTION);
466    
467                    if (parts.length == 2) {
468                            String[] params = null;
469    
470                            if (escaped) {
471                                    params = StringUtil.split(parts[1], "&amp;");
472                            }
473                            else {
474                                    params = StringUtil.split(parts[1], CharPool.AMPERSAND);
475                            }
476    
477                            for (String param : params) {
478                                    String[] kvp = StringUtil.split(param, CharPool.EQUAL);
479    
480                                    if ((kvp.length == 2) && kvp[0].equals(name)) {
481                                            return kvp[1];
482                                    }
483                            }
484                    }
485    
486                    return StringPool.BLANK;
487            }
488    
489            public Map<String, String[]> getParameterMap(String queryString) {
490                    return parameterMapFromString(queryString);
491            }
492    
493            public String getPath(String url) {
494                    if (Validator.isNull(url)) {
495                            return url;
496                    }
497    
498                    if (url.startsWith(Http.HTTP)) {
499                            int pos = url.indexOf(
500                                    StringPool.SLASH, Http.HTTPS_WITH_SLASH.length());
501    
502                            url = url.substring(pos);
503                    }
504    
505                    int pos = url.indexOf(CharPool.QUESTION);
506    
507                    if (pos == -1) {
508                            return url;
509                    }
510                    else {
511                            return url.substring(0, pos);
512                    }
513            }
514    
515            public String getProtocol(ActionRequest actionRequest) {
516                    return getProtocol(actionRequest.isSecure());
517            }
518    
519            public String getProtocol(boolean secure) {
520                    if (!secure) {
521                            return Http.HTTP;
522                    }
523                    else {
524                            return Http.HTTPS;
525                    }
526            }
527    
528            public String getProtocol(HttpServletRequest request) {
529                    return getProtocol(request.isSecure());
530            }
531    
532            public String getProtocol(RenderRequest renderRequest) {
533                    return getProtocol(renderRequest.isSecure());
534            }
535    
536            public String getProtocol(String url) {
537                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
538    
539                    if (pos != -1) {
540                            return url.substring(0, pos);
541                    }
542                    else {
543                            return Http.HTTP;
544                    }
545            }
546    
547            public String getQueryString(String url) {
548                    if (Validator.isNull(url)) {
549                            return url;
550                    }
551    
552                    int pos = url.indexOf(CharPool.QUESTION);
553    
554                    if (pos == -1) {
555                            return StringPool.BLANK;
556                    }
557                    else {
558                            return url.substring(pos + 1);
559                    }
560            }
561    
562            public String getRequestURL(HttpServletRequest request) {
563                    return request.getRequestURL().toString();
564            }
565    
566            public boolean hasDomain(String url) {
567                    return Validator.isNotNull(getDomain(url));
568            }
569    
570            public boolean hasProtocol(String url) {
571                    int pos = url.indexOf(Http.PROTOCOL_DELIMITER);
572    
573                    if (pos != -1) {
574                            return true;
575                    }
576                    else {
577                            return false;
578                    }
579            }
580    
581            public boolean hasProxyConfig() {
582                    if (Validator.isNotNull(_PROXY_HOST) && (_PROXY_PORT > 0)) {
583                            return true;
584                    }
585                    else {
586                            return false;
587                    }
588            }
589    
590            public boolean isNonProxyHost(String host) {
591                    if (_nonProxyHostsPattern != null) {
592                            Matcher matcher = _nonProxyHostsPattern.matcher(host);
593    
594                            if (matcher.matches()) {
595                                    return true;
596                            }
597                    }
598    
599                    return false;
600            }
601    
602            public boolean isProxyHost(String host) {
603                    if (hasProxyConfig() && !isNonProxyHost(host)) {
604                            return true;
605                    }
606                    else {
607                            return false;
608                    }
609            }
610    
611            public Map<String, String[]> parameterMapFromString(String queryString) {
612                    Map<String, String[]> parameterMap =
613                            new LinkedHashMap<String, String[]>();
614    
615                    if (Validator.isNull(queryString)) {
616                            return parameterMap;
617                    }
618    
619                    Map<String, List<String>> tempParameterMap =
620                            new LinkedHashMap<String, List<String>>();
621    
622                    String[] parameters = StringUtil.split(queryString, CharPool.AMPERSAND);
623    
624                    for (String parameter : parameters) {
625                            if (parameter.length() > 0) {
626                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
627    
628                                    String key = kvp[0];
629    
630                                    String value = StringPool.BLANK;
631    
632                                    if (kvp.length > 1) {
633                                            value = decodeURL(kvp[1]);
634                                    }
635    
636                                    List<String> values = tempParameterMap.get(key);
637    
638                                    if (values == null) {
639                                            values = new ArrayList<String>();
640    
641                                            tempParameterMap.put(key, values);
642                                    }
643    
644                                    values.add(value);
645                            }
646                    }
647    
648                    for (Map.Entry<String, List<String>> entry :
649                                    tempParameterMap.entrySet()) {
650    
651                            String key = entry.getKey();
652                            List<String> values = entry.getValue();
653    
654                            parameterMap.put(key, values.toArray(new String[values.size()]));
655                    }
656    
657                    return parameterMap;
658            }
659    
660            public String parameterMapToString(Map<String, String[]> parameterMap) {
661                    return parameterMapToString(parameterMap, true);
662            }
663    
664            public String parameterMapToString(
665                    Map<String, String[]> parameterMap, boolean addQuestion) {
666    
667                    if (parameterMap.isEmpty()) {
668                            return StringPool.BLANK;
669                    }
670    
671                    StringBundler sb = new StringBundler();
672    
673                    if (addQuestion) {
674                            sb.append(StringPool.QUESTION);
675                    }
676    
677                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
678                            String name = entry.getKey();
679                            String[] values = entry.getValue();
680    
681                            for (String value : values) {
682                                    sb.append(name);
683                                    sb.append(StringPool.EQUAL);
684                                    sb.append(encodeURL(value));
685                                    sb.append(StringPool.AMPERSAND);
686                            }
687                    }
688    
689                    if (sb.index() > 1) {
690                            sb.setIndex(sb.index() - 1);
691                    }
692    
693                    return sb.toString();
694            }
695    
696            public String protocolize(String url, ActionRequest actionRequest) {
697                    return protocolize(url, actionRequest.isSecure());
698            }
699    
700            public String protocolize(String url, boolean secure) {
701                    if (secure) {
702                            if (url.startsWith(Http.HTTP_WITH_SLASH)) {
703                                    return StringUtil.replace(
704                                            url, Http.HTTP_WITH_SLASH, Http.HTTPS_WITH_SLASH);
705                            }
706                    }
707                    else {
708                            if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
709                                    return StringUtil.replace(
710                                            url, Http.HTTPS_WITH_SLASH, Http.HTTP_WITH_SLASH);
711                            }
712                    }
713    
714                    return url;
715            }
716    
717            public String protocolize(String url, HttpServletRequest request) {
718                    return protocolize(url, request.isSecure());
719            }
720    
721            public String protocolize(String url, RenderRequest renderRequest) {
722                    return protocolize(url, renderRequest.isSecure());
723            }
724    
725            public void proxifyState(
726                    HttpState httpState, HostConfiguration hostConfiguration) {
727    
728                    Credentials proxyCredentials = _proxyCredentials;
729    
730                    String host = hostConfiguration.getHost();
731    
732                    if (isProxyHost(host) && (proxyCredentials != null)) {
733                            AuthScope scope = new AuthScope(_PROXY_HOST, _PROXY_PORT, null);
734    
735                            httpState.setProxyCredentials(scope, proxyCredentials);
736                    }
737            }
738    
739            public String removeDomain(String url) {
740                    url = removeProtocol(url);
741    
742                    int pos = url.indexOf(CharPool.SLASH);
743    
744                    if (pos > 0) {
745                            return url.substring(pos);
746                    }
747                    else {
748                            return url;
749                    }
750            }
751    
752            public String removeParameter(String url, String name) {
753                    int pos = url.indexOf(CharPool.QUESTION);
754    
755                    if (pos == -1) {
756                            return url;
757                    }
758    
759                    String[] array = PortalUtil.stripURLAnchor(url, StringPool.POUND);
760    
761                    url = array[0];
762    
763                    String anchor = array[1];
764    
765                    StringBundler sb = new StringBundler();
766    
767                    sb.append(url.substring(0, pos + 1));
768    
769                    String[] parameters = StringUtil.split(
770                            url.substring(pos + 1, url.length()), CharPool.AMPERSAND);
771    
772                    for (String parameter : parameters) {
773                            if (parameter.length() > 0) {
774                                    String[] kvp = StringUtil.split(parameter, CharPool.EQUAL);
775    
776                                    String key = kvp[0];
777    
778                                    String value = StringPool.BLANK;
779    
780                                    if (kvp.length > 1) {
781                                            value = kvp[1];
782                                    }
783    
784                                    if (!key.equals(name)) {
785                                            sb.append(key);
786                                            sb.append(StringPool.EQUAL);
787                                            sb.append(value);
788                                            sb.append(StringPool.AMPERSAND);
789                                    }
790                            }
791                    }
792    
793                    url = StringUtil.replace(
794                            sb.toString(), StringPool.AMPERSAND + StringPool.AMPERSAND,
795                            StringPool.AMPERSAND);
796    
797                    if (url.endsWith(StringPool.AMPERSAND)) {
798                            url = url.substring(0, url.length() - 1);
799                    }
800    
801                    if (url.endsWith(StringPool.QUESTION)) {
802                            url = url.substring(0, url.length() - 1);
803                    }
804    
805                    return url + anchor;
806            }
807    
808            public String removeProtocol(String url) {
809                    if (url.startsWith(Http.HTTP_WITH_SLASH)) {
810                            return url.substring(Http.HTTP_WITH_SLASH.length());
811                    }
812                    else if (url.startsWith(Http.HTTPS_WITH_SLASH)) {
813                            return url.substring(Http.HTTPS_WITH_SLASH.length());
814                    }
815                    else {
816                            return url;
817                    }
818            }
819    
820            public String setParameter(String url, String name, boolean value) {
821                    return setParameter(url, name, String.valueOf(value));
822            }
823    
824            public String setParameter(String url, String name, double value) {
825                    return setParameter(url, name, String.valueOf(value));
826            }
827    
828            public String setParameter(String url, String name, int value) {
829                    return setParameter(url, name, String.valueOf(value));
830            }
831    
832            public String setParameter(String url, String name, long value) {
833                    return setParameter(url, name, String.valueOf(value));
834            }
835    
836            public String setParameter(String url, String name, short value) {
837                    return setParameter(url, name, String.valueOf(value));
838            }
839    
840            public String setParameter(String url, String name, String value) {
841                    if (url == null) {
842                            return null;
843                    }
844    
845                    url = removeParameter(url, name);
846    
847                    return addParameter(url, name, value);
848            }
849    
850            public byte[] URLtoByteArray(Http.Options options) throws IOException {
851                    return URLtoByteArray(
852                            options.getLocation(), options.getMethod(), options.getHeaders(),
853                            options.getCookies(), options.getAuth(), options.getBody(),
854                            options.getFileParts(), options.getParts(), options.getResponse(),
855                            options.isFollowRedirects());
856            }
857    
858            public byte[] URLtoByteArray(String location) throws IOException {
859                    Http.Options options = new Http.Options();
860    
861                    options.setLocation(location);
862    
863                    return URLtoByteArray(options);
864            }
865    
866            public byte[] URLtoByteArray(String location, boolean post)
867                    throws IOException {
868    
869                    Http.Options options = new Http.Options();
870    
871                    options.setLocation(location);
872                    options.setPost(post);
873    
874                    return URLtoByteArray(options);
875            }
876    
877            public String URLtoString(Http.Options options) throws IOException {
878                    return new String(URLtoByteArray(options));
879            }
880    
881            public String URLtoString(String location) throws IOException {
882                    return new String(URLtoByteArray(location));
883            }
884    
885            public String URLtoString(String location, boolean post)
886                    throws IOException {
887    
888                    return new String(URLtoByteArray(location, post));
889            }
890    
891            /**
892             * This method only uses the default Commons HttpClient implementation when
893             * the URL object represents a HTTP resource. The URL object could also
894             * represent a file or some JNDI resource. In that case, the default Java
895             * implementation is used.
896             *
897             * @param  url the URL
898             * @return A string representation of the resource referenced by the URL
899             *         object
900             * @throws IOException if an IO exception occurred
901             */
902            public String URLtoString(URL url) throws IOException {
903                    String xml = null;
904    
905                    if (url != null) {
906                            String protocol = url.getProtocol().toLowerCase();
907    
908                            if (protocol.startsWith(Http.HTTP) ||
909                                    protocol.startsWith(Http.HTTPS)) {
910    
911                                    return URLtoString(url.toString());
912                            }
913    
914                            URLConnection urlConnection = url.openConnection();
915    
916                            InputStream inputStream = urlConnection.getInputStream();
917    
918                            UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
919                                    new UnsyncByteArrayOutputStream();
920    
921                            byte[] bytes = new byte[512];
922    
923                            for (int i = inputStream.read(bytes, 0, 512); i != -1;
924                                            i = inputStream.read(bytes, 0, 512)) {
925    
926                                    unsyncByteArrayOutputStream.write(bytes, 0, i);
927                            }
928    
929                            xml = new String(
930                                    unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
931                                    unsyncByteArrayOutputStream.size());
932    
933                            inputStream.close();
934    
935                            unsyncByteArrayOutputStream.close();
936                    }
937    
938                    return xml;
939            }
940    
941            protected boolean hasRequestHeader(HttpMethod httpMethod, String name) {
942                    Header[] headers = httpMethod.getRequestHeaders(name);
943    
944                    if (headers.length == 0) {
945                            return false;
946                    }
947                    else {
948                            return true;
949                    }
950            }
951    
952            protected void processPostMethod(
953                    PostMethod postMethod, List<Http.FilePart> fileParts,
954                    Map<String, String> parts) {
955    
956                    if ((fileParts == null) || fileParts.isEmpty()) {
957                            if (parts != null) {
958                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
959                                            String value = entry.getValue();
960    
961                                            if (value != null) {
962                                                    postMethod.addParameter(entry.getKey(), value);
963                                            }
964                                    }
965                            }
966                    }
967                    else {
968                            List<Part> partsList = new ArrayList<Part>();
969    
970                            if (parts != null) {
971                                    for (Map.Entry<String, String> entry : parts.entrySet()) {
972                                            String value = entry.getValue();
973    
974                                            if (value != null) {
975                                                    StringPart stringPart = new StringPart(
976                                                            entry.getKey(), value);
977    
978                                                    partsList.add(stringPart);
979                                            }
980                                    }
981                            }
982    
983                            for (Http.FilePart filePart : fileParts) {
984                                    partsList.add(toCommonsFilePart(filePart));
985                            }
986    
987                            MultipartRequestEntity multipartRequestEntity =
988                                    new MultipartRequestEntity(
989                                            partsList.toArray(new Part[partsList.size()]),
990                                            postMethod.getParams());
991    
992                            postMethod.setRequestEntity(multipartRequestEntity);
993                    }
994            }
995    
996            protected org.apache.commons.httpclient.Cookie toCommonsCookie(
997                    Cookie cookie) {
998    
999                    org.apache.commons.httpclient.Cookie commonsCookie =
1000                            new org.apache.commons.httpclient.Cookie(
1001                                    cookie.getDomain(), cookie.getName(), cookie.getValue(),
1002                                    cookie.getPath(), cookie.getMaxAge(), cookie.getSecure());
1003    
1004                    commonsCookie.setVersion(cookie.getVersion());
1005    
1006                    return commonsCookie;
1007            }
1008    
1009            protected org.apache.commons.httpclient.Cookie[] toCommonsCookies(
1010                    Cookie[] cookies) {
1011    
1012                    if (cookies == null) {
1013                            return null;
1014                    }
1015    
1016                    org.apache.commons.httpclient.Cookie[] commonCookies =
1017                            new org.apache.commons.httpclient.Cookie[cookies.length];
1018    
1019                    for (int i = 0; i < cookies.length; i++) {
1020                            commonCookies[i] = toCommonsCookie(cookies[i]);
1021                    }
1022    
1023                    return commonCookies;
1024            }
1025    
1026            protected org.apache.commons.httpclient.methods.multipart.FilePart
1027                    toCommonsFilePart(Http.FilePart filePart) {
1028    
1029                    return new org.apache.commons.httpclient.methods.multipart.FilePart(
1030                            filePart.getName(),
1031                            new ByteArrayPartSource(
1032                                    filePart.getFileName(), filePart.getValue()),
1033                            filePart.getContentType(), filePart.getCharSet());
1034            }
1035    
1036            protected Cookie toServletCookie(
1037                    org.apache.commons.httpclient.Cookie commonsCookie) {
1038    
1039                    Cookie cookie = new Cookie(
1040                            commonsCookie.getName(), commonsCookie.getValue());
1041    
1042                    String domain = commonsCookie.getDomain();
1043    
1044                    if (Validator.isNotNull(domain)) {
1045                            cookie.setDomain(domain);
1046                    }
1047    
1048                    Date expiryDate = commonsCookie.getExpiryDate();
1049    
1050                    if (expiryDate != null) {
1051                            int maxAge =
1052                                    (int)(expiryDate.getTime() - System.currentTimeMillis());
1053    
1054                            maxAge = maxAge / 1000;
1055    
1056                            if (maxAge > -1) {
1057                                    cookie.setMaxAge(maxAge);
1058                            }
1059                    }
1060    
1061                    String path = commonsCookie.getPath();
1062    
1063                    if (Validator.isNotNull(path)) {
1064                            cookie.setPath(path);
1065                    }
1066    
1067                    cookie.setSecure(commonsCookie.getSecure());
1068                    cookie.setVersion(commonsCookie.getVersion());
1069    
1070                    return cookie;
1071            }
1072    
1073            protected Cookie[] toServletCookies(
1074                    org.apache.commons.httpclient.Cookie[] commonsCookies) {
1075    
1076                    if (commonsCookies == null) {
1077                            return null;
1078                    }
1079    
1080                    Cookie[] cookies = new Cookie[commonsCookies.length];
1081    
1082                    for (int i = 0; i < commonsCookies.length; i++) {
1083                            cookies[i] = toServletCookie(commonsCookies[i]);
1084                    }
1085    
1086                    return cookies;
1087            }
1088    
1089            protected byte[] URLtoByteArray(
1090                            String location, Http.Method method, Map<String, String> headers,
1091                            Cookie[] cookies, Http.Auth auth, Http.Body body,
1092                            List<Http.FilePart> fileParts, Map<String, String> parts,
1093                            Http.Response response, boolean followRedirects)
1094                    throws IOException {
1095    
1096                    byte[] bytes = null;
1097    
1098                    HttpMethod httpMethod = null;
1099                    HttpState httpState = null;
1100    
1101                    try {
1102                            _cookies.set(null);
1103    
1104                            if (location == null) {
1105                                    return null;
1106                            }
1107                            else if (!location.startsWith(Http.HTTP_WITH_SLASH) &&
1108                                             !location.startsWith(Http.HTTPS_WITH_SLASH)) {
1109    
1110                                    location = Http.HTTP_WITH_SLASH + location;
1111                            }
1112    
1113                            HostConfiguration hostConfiguration = getHostConfiguration(
1114                                    location);
1115    
1116                            HttpClient httpClient = getClient(hostConfiguration);
1117    
1118                            if (method.equals(Http.Method.POST) ||
1119                                    method.equals(Http.Method.PUT)) {
1120    
1121                                    if (method.equals(Http.Method.POST)) {
1122                                            httpMethod = new PostMethod(location);
1123                                    }
1124                                    else {
1125                                            httpMethod = new PutMethod(location);
1126                                    }
1127    
1128                                    if (body != null) {
1129                                            RequestEntity requestEntity = new StringRequestEntity(
1130                                                    body.getContent(), body.getContentType(),
1131                                                    body.getCharset());
1132    
1133                                            EntityEnclosingMethod entityEnclosingMethod =
1134                                                    (EntityEnclosingMethod)httpMethod;
1135    
1136                                            entityEnclosingMethod.setRequestEntity(requestEntity);
1137                                    }
1138                                    else if (method.equals(Http.Method.POST)) {
1139                                            PostMethod postMethod = (PostMethod)httpMethod;
1140    
1141                                            if (!hasRequestHeader(
1142                                                            postMethod, HttpHeaders.CONTENT_TYPE)) {
1143    
1144                                                    postMethod.addRequestHeader(
1145                                                            HttpHeaders.CONTENT_TYPE,
1146                                                            ContentTypes.
1147                                                                    APPLICATION_X_WWW_FORM_URLENCODED_UTF8);
1148                                            }
1149    
1150                                            processPostMethod(postMethod, fileParts, parts);
1151                                    }
1152                            }
1153                            else if (method.equals(Http.Method.DELETE)) {
1154                                    httpMethod = new DeleteMethod(location);
1155                            }
1156                            else if (method.equals(Http.Method.HEAD)) {
1157                                    httpMethod = new HeadMethod(location);
1158                            }
1159                            else {
1160                                    httpMethod = new GetMethod(location);
1161                            }
1162    
1163                            if (headers != null) {
1164                                    for (Map.Entry<String, String> header : headers.entrySet()) {
1165                                            httpMethod.addRequestHeader(
1166                                                    header.getKey(), header.getValue());
1167                                    }
1168                            }
1169    
1170                            if ((method.equals(Http.Method.POST) ||
1171                                     method.equals(Http.Method.PUT)) &&
1172                                    ((body != null) ||
1173                                     ((fileParts != null) && !fileParts.isEmpty()) ||
1174                                     ((parts != null) && !parts.isEmpty()))) {
1175                            }
1176                            else if (!hasRequestHeader(httpMethod, HttpHeaders.CONTENT_TYPE)) {
1177                                    httpMethod.addRequestHeader(
1178                                            HttpHeaders.CONTENT_TYPE,
1179                                            ContentTypes.APPLICATION_X_WWW_FORM_URLENCODED_UTF8);
1180                            }
1181    
1182                            if (!hasRequestHeader(httpMethod, HttpHeaders.USER_AGENT)) {
1183                                    httpMethod.addRequestHeader(
1184                                            HttpHeaders.USER_AGENT, _DEFAULT_USER_AGENT);
1185                            }
1186    
1187                            httpState = new HttpState();
1188    
1189                            if ((cookies != null) && (cookies.length > 0)) {
1190                                    org.apache.commons.httpclient.Cookie[] commonsCookies =
1191                                            toCommonsCookies(cookies);
1192    
1193                                    httpState.addCookies(commonsCookies);
1194    
1195                                    HttpMethodParams httpMethodParams = httpMethod.getParams();
1196    
1197                                    httpMethodParams.setCookiePolicy(
1198                                            CookiePolicy.BROWSER_COMPATIBILITY);
1199                            }
1200    
1201                            if (auth != null) {
1202                                    httpMethod.setDoAuthentication(true);
1203    
1204                                    httpState.setCredentials(
1205                                            new AuthScope(
1206                                                    auth.getHost(), auth.getPort(), auth.getRealm()),
1207                                            new UsernamePasswordCredentials(
1208                                                    auth.getUsername(), auth.getPassword()));
1209                            }
1210    
1211                            proxifyState(httpState, hostConfiguration);
1212    
1213                            httpClient.executeMethod(hostConfiguration, httpMethod, httpState);
1214    
1215                            Header locationHeader = httpMethod.getResponseHeader("location");
1216    
1217                            if ((locationHeader != null) && !locationHeader.equals(location)) {
1218                                    String redirect = locationHeader.getValue();
1219    
1220                                    if (followRedirects) {
1221                                            return URLtoByteArray(
1222                                                    redirect, Http.Method.GET, headers, cookies, auth, body,
1223                                                    fileParts, parts, response, followRedirects);
1224                                    }
1225                                    else {
1226                                            response.setRedirect(redirect);
1227                                    }
1228                            }
1229    
1230                            InputStream inputStream = httpMethod.getResponseBodyAsStream();
1231    
1232                            if (inputStream != null) {
1233                                    Header contentLength = httpMethod.getResponseHeader(
1234                                            HttpHeaders.CONTENT_LENGTH);
1235    
1236                                    if (contentLength != null) {
1237                                            response.setContentLength(
1238                                                    GetterUtil.getInteger(contentLength.getValue()));
1239                                    }
1240    
1241                                    Header contentType = httpMethod.getResponseHeader(
1242                                            HttpHeaders.CONTENT_TYPE);
1243    
1244                                    if (contentType != null) {
1245                                            response.setContentType(contentType.getValue());
1246                                    }
1247    
1248                                    bytes = FileUtil.getBytes(inputStream);
1249                            }
1250    
1251                            for (Header header : httpMethod.getResponseHeaders()) {
1252                                    response.addHeader(header.getName(), header.getValue());
1253                            }
1254    
1255                            return bytes;
1256                    }
1257                    finally {
1258                            try {
1259                                    if (httpState != null) {
1260                                            _cookies.set(toServletCookies(httpState.getCookies()));
1261                                    }
1262                            }
1263                            catch (Exception e) {
1264                                    _log.error(e, e);
1265                            }
1266    
1267                            try {
1268                                    if (httpMethod != null) {
1269                                            httpMethod.releaseConnection();
1270                                    }
1271                            }
1272                            catch (Exception e) {
1273                                    _log.error(e, e);
1274                            }
1275                    }
1276            }
1277    
1278            private static final String _DEFAULT_USER_AGENT =
1279                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
1280    
1281            private static final int _MAX_CONNECTIONS_PER_HOST = GetterUtil.getInteger(
1282                    PropsUtil.get(HttpImpl.class.getName() + ".max.connections.per.host"),
1283                    2);
1284    
1285            private static final int _MAX_TOTAL_CONNECTIONS = GetterUtil.getInteger(
1286                    PropsUtil.get(HttpImpl.class.getName() + ".max.total.connections"), 20);
1287    
1288            private static final String _NON_PROXY_HOSTS = SystemProperties.get(
1289                    "http.nonProxyHosts");
1290    
1291            private static final String _PROXY_AUTH_TYPE = GetterUtil.getString(
1292                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.auth.type"));
1293    
1294            private static final String _PROXY_HOST = GetterUtil.getString(
1295                    SystemProperties.get("http.proxyHost"));
1296    
1297            private static final String _PROXY_NTLM_DOMAIN = GetterUtil.getString(
1298                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.domain"));
1299    
1300            private static final String _PROXY_NTLM_HOST = GetterUtil.getString(
1301                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.ntlm.host"));
1302    
1303            private static final String _PROXY_PASSWORD = GetterUtil.getString(
1304                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.password"));
1305    
1306            private static final int _PROXY_PORT = GetterUtil.getInteger(
1307                    SystemProperties.get("http.proxyPort"));
1308    
1309            private static final String _PROXY_USERNAME = GetterUtil.getString(
1310                    PropsUtil.get(HttpImpl.class.getName() + ".proxy.username"));
1311    
1312            private static final String _TEMP_SLASH = "_LIFERAY_TEMP_SLASH_";
1313    
1314            private static final int _TIMEOUT = GetterUtil.getInteger(
1315                    PropsUtil.get(HttpImpl.class.getName() + ".timeout"), 5000);
1316    
1317            private static Log _log = LogFactoryUtil.getLog(HttpImpl.class);
1318    
1319            private static ThreadLocal<Cookie[]> _cookies = new ThreadLocal<Cookie[]>();
1320    
1321            private HttpClient _httpClient = new HttpClient();
1322            private Pattern _nonProxyHostsPattern;
1323            private Credentials _proxyCredentials;
1324            private HttpClient _proxyHttpClient = new HttpClient();
1325    
1326            private class FastProtocolSocketFactory
1327                    extends DefaultProtocolSocketFactory {
1328    
1329                    @Override
1330                    public Socket createSocket(
1331                                    final String host, final int port,
1332                                    final InetAddress localInetAddress, final int localPort,
1333                                    final HttpConnectionParams httpConnectionParams)
1334                            throws ConnectTimeoutException, IOException, UnknownHostException {
1335    
1336                            int connectionTimeout = httpConnectionParams.getConnectionTimeout();
1337    
1338                            if (connectionTimeout == 0) {
1339                                    return createSocket(host, port, localInetAddress, localPort);
1340                            }
1341    
1342                            SocketFactory socketFactory = SocketFactory.getDefault();
1343    
1344                            Socket socket = socketFactory.createSocket();
1345    
1346                            SocketAddress localSocketAddress = new InetSocketAddress(
1347                                    localInetAddress, localPort);
1348    
1349                            SocketAddress remoteSocketAddress = new InetSocketAddress(
1350                                    host, port);
1351    
1352                            socket.bind(localSocketAddress);
1353    
1354                            socket.connect(remoteSocketAddress, connectionTimeout);
1355    
1356                            return socket;
1357                    }
1358    
1359            }
1360    
1361    }