View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.bindings.spi.http;
20  
21  import java.io.IOException;
22  import java.net.InetSocketAddress;
23  import java.net.Socket;
24  import java.net.SocketTimeoutException;
25  
26  import javax.net.ssl.HostnameVerifier;
27  import javax.net.ssl.SSLSocket;
28  import javax.net.ssl.SSLSocketFactory;
29  
30  import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
31  import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
32  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
33  import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
34  import org.apache.http.client.params.ClientPNames;
35  import org.apache.http.client.params.CookiePolicy;
36  import org.apache.http.conn.ConnectTimeoutException;
37  import org.apache.http.conn.HttpInetSocketAddress;
38  import org.apache.http.conn.scheme.PlainSocketFactory;
39  import org.apache.http.conn.scheme.Scheme;
40  import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
41  import org.apache.http.conn.scheme.SchemeRegistry;
42  import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
43  import org.apache.http.conn.ssl.X509HostnameVerifier;
44  import org.apache.http.impl.client.DefaultHttpClient;
45  import org.apache.http.impl.conn.PoolingClientConnectionManager;
46  import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
47  import org.apache.http.params.HttpConnectionParams;
48  import org.apache.http.params.HttpParams;
49  
50  /**
51   * A {@link HttpInvoker} that uses The Apache HTTP client.
52   */
53  public class ApacheClientHttpInvoker extends AbstractApacheClientHttpInvoker {
54  
55      @Override
56      protected DefaultHttpClient createHttpClient(UrlBuilder url, BindingSession session) {
57          // set params
58          HttpParams params = createDefaultHttpParams(session);
59          params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
60  
61          // set up scheme registry and connection manager
62          SchemeRegistry registry = new SchemeRegistry();
63          registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
64          registry.register(new Scheme("https", 443, getSSLSocketFactory(url, session)));
65  
66          // set up connection manager
67          PoolingClientConnectionManager connManager = new PoolingClientConnectionManager(registry);
68  
69          // set max connection a
70          String keepAliveStr = System.getProperty("http.keepAlive", "true");
71          if ("true".equalsIgnoreCase(keepAliveStr)) {
72              String maxConnStr = System.getProperty("http.maxConnections", "5");
73              int maxConn = 5;
74              try {
75                  maxConn = Integer.parseInt(maxConnStr);
76              } catch (NumberFormatException nfe) {
77                  // ignore
78              }
79              connManager.setDefaultMaxPerRoute(maxConn);
80              connManager.setMaxTotal(4 * maxConn);
81          }
82  
83          // set up proxy
84          ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(registry, null);
85  
86          // set up client
87          DefaultHttpClient httpclient = new DefaultHttpClient(connManager, params);
88          httpclient.setRoutePlanner(routePlanner);
89  
90          return httpclient;
91      }
92  
93      /**
94       * Builds a SSL Socket Factory for the Apache HTTP Client.
95       */
96      private SchemeLayeredSocketFactory getSSLSocketFactory(final UrlBuilder url, final BindingSession session) {
97          // get authentication provider
98          AuthenticationProvider authProvider = CmisBindingsHelper.getAuthenticationProvider(session);
99  
100         // check SSL Socket Factory
101         final SSLSocketFactory sf = authProvider.getSSLSocketFactory();
102         if (sf == null) {
103             // no custom factory -> return default factory
104             return org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory();
105         }
106 
107         // check hostame verifier and use default if not set
108         final HostnameVerifier hv = (authProvider.getHostnameVerifier() == null ? new BrowserCompatHostnameVerifier()
109                 : authProvider.getHostnameVerifier());
110 
111         if (hv instanceof X509HostnameVerifier) {
112             return new org.apache.http.conn.ssl.SSLSocketFactory(sf, (X509HostnameVerifier) hv);
113         }
114 
115         // build new socket factory
116         return new SchemeLayeredSocketFactory() {
117 
118             @Override
119             public boolean isSecure(Socket sock) {
120                 return true;
121             }
122 
123             @Override
124             public Socket createSocket(HttpParams params) throws IOException {
125                 return sf.createSocket();
126             }
127 
128             @Override
129             public Socket connectSocket(final Socket socket, final InetSocketAddress remoteAddress,
130                     final InetSocketAddress localAddress, final HttpParams params) throws IOException {
131 
132                 Socket sock = socket != null ? socket : createSocket(params);
133                 if (localAddress != null) {
134                     sock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
135                     sock.bind(localAddress);
136                 }
137 
138                 int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
139                 int soTimeout = HttpConnectionParams.getSoTimeout(params);
140 
141                 try {
142                     sock.setSoTimeout(soTimeout);
143                     sock.connect(remoteAddress, connTimeout);
144                 } catch (SocketTimeoutException ex) {
145                     closeSocket(sock);
146                     throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out!");
147                 }
148 
149                 String host;
150                 if (remoteAddress instanceof HttpInetSocketAddress) {
151                     host = ((HttpInetSocketAddress) remoteAddress).getHttpHost().getHostName();
152                 } else {
153                     host = remoteAddress.getHostName();
154                 }
155 
156                 SSLSocket sslSocket;
157                 if (sock instanceof SSLSocket) {
158                     sslSocket = (SSLSocket) sock;
159                 } else {
160                     int port = remoteAddress.getPort();
161                     sslSocket = (SSLSocket) sf.createSocket(sock, host, port, true);
162                 }
163                 verify(hv, host, sslSocket);
164 
165                 return sslSocket;
166             }
167 
168             @Override
169             public Socket createLayeredSocket(final Socket socket, final String host, final int port,
170                     final HttpParams params) throws IOException {
171                 SSLSocket sslSocket = (SSLSocket) sf.createSocket(socket, host, port, true);
172                 verify(hv, host, sslSocket);
173 
174                 return sslSocket;
175             }
176         };
177     }
178 }