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   */
20  package org.apache.mina.example.proxy;
21  
22  import java.net.InetSocketAddress;
23  import java.net.URL;
24  import java.security.Security;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  
29  import org.apache.mina.core.RuntimeIoException;
30  import org.apache.mina.core.future.ConnectFuture;
31  import org.apache.mina.core.session.IdleStatus;
32  import org.apache.mina.core.session.IoSession;
33  import org.apache.mina.filter.logging.LoggingFilter;
34  import org.apache.mina.proxy.ProxyConnector;
35  import org.apache.mina.proxy.handlers.ProxyRequest;
36  import org.apache.mina.proxy.handlers.http.HttpAuthenticationMethods;
37  import org.apache.mina.proxy.handlers.http.HttpProxyConstants;
38  import org.apache.mina.proxy.handlers.http.HttpProxyRequest;
39  import org.apache.mina.proxy.handlers.socks.SocksProxyConstants;
40  import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
41  import org.apache.mina.proxy.session.ProxyIoSession;
42  import org.apache.mina.transport.socket.nio.NioSocketConnector;
43  
44  /**
45   * ProxyTestClient.java - Base test class for mina proxy
46   * 
47   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
48   * @since MINA 2.0.0-M3
49   */
50  public class ProxyTestClient {
51      
52      /**
53       * The global variables used when creating the HTTP proxy connection.
54       */
55      
56      /**
57       * The user login.
58       */
59      public final static String USER = "TED_KODS";
60  
61      /**
62       * The user password.
63       */
64      public final static String PWD = "EDOUARD";
65  
66      /**
67       * The domain name. (used in NTLM connections)
68       */
69      public final static String DOMAIN = "MYDOMAIN";
70  
71      /**
72       * The workstation name. (used in NTLM connections)
73       */    
74      public final static String WORKSTATION = "MYWORKSTATION";
75  
76      /**
77       * Set this variable to true in order to generate HTTP/1.1 requests.
78       */
79      private final static boolean USE_HTTP_1_1 = false;
80  
81      /**
82       * Creates a connection to the endpoint through a proxy server using the specified
83       * authentication method.
84       * 
85       * Command line arguments: 
86       *       ProxyTestClient <proxy-hostname> <proxy-port> <url> <proxy-method> 
87       *       
88       * Note that <proxy-method> is OPTIONNAL a HTTP proxy connection will be used if not 
89       * specified.
90       * 
91       * Examples:
92       *          ProxyTestClient myproxy 8080 http://mina.apache.org SOCKS4
93       *          ProxyTestClient squidsrv 3128 http://mina.apache.org:80
94       *       
95       * @param args parse arguments to get proxy hostaname, proxy port, the url to connect to 
96       * and optionnaly the proxy authentication method 
97       * @throws Exception
98       */
99      public ProxyTestClient(String[] args) throws Exception {
100         if (args.length < 3) {
101             System.out
102                     .println(ProxyTestClient.class.getName()
103                             + " <proxy-hostname> <proxy-port> <url> <proxy-method> (<proxy-method> is OPTIONNAL)");
104             return;
105         }
106 
107         // Create proxy connector.
108         NioSocketConnector socketConnector = new NioSocketConnector(Runtime
109                 .getRuntime().availableProcessors() + 1);
110 
111         ProxyConnector connector = new ProxyConnector(socketConnector);
112 
113         // Set connect timeout.
114         connector.setConnectTimeoutMillis(5000);
115 
116         URL url = new URL(args[2]);
117         int port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
118 
119         ProxyRequest req = null;
120 
121         if (args.length == 4) {
122             if ("SOCKS4".equals(args[3])) {
123                 req = new SocksProxyRequest(
124                         SocksProxyConstants.SOCKS_VERSION_4,
125                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
126                         new InetSocketAddress(url.getHost(), port), USER);
127             } else if ("SOCKS4a".equals(args[3])) {
128                 req = new SocksProxyRequest(
129                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM, url
130                                 .getHost(), port, USER);
131             } else if ("SOCKS5".equals(args[3])) {
132                 req = new SocksProxyRequest(
133                         SocksProxyConstants.SOCKS_VERSION_5,
134                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
135                         new InetSocketAddress(url.getHost(), port), USER);
136                 ((SocksProxyRequest) req).setPassword(PWD);
137                 ((SocksProxyRequest) req)
138                         .setServiceKerberosName(Socks5GSSAPITestServer.SERVICE_NAME);
139             } else {
140                 req = createHttpProxyRequest(args[2]);
141             }
142         } else {
143             req = createHttpProxyRequest(args[2]);
144         }
145 
146         ProxyIoSession proxyIoSession = new ProxyIoSession(
147                 new InetSocketAddress(args[0], Integer.parseInt(args[1])), req);
148 
149         // Tests modifying authentication order preferences. First algorithm in list available on server 
150         // will be used for authentication.
151         List<HttpAuthenticationMethods> l = new ArrayList<HttpAuthenticationMethods>();
152         l.add(HttpAuthenticationMethods.DIGEST);
153         l.add(HttpAuthenticationMethods.BASIC);
154         proxyIoSession.setPreferedOrder(l);
155 
156         connector.setProxyIoSession(proxyIoSession);
157 
158         socketConnector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5);
159 
160         connector.getFilterChain().addLast("logger", new LoggingFilter());
161 
162         // This command is sent when using a socks proxy to request a page from the web server.
163         String cmd = "GET " + url.toExternalForm() + " HTTP/1.0"
164                 + HttpProxyConstants.CRLF + HttpProxyConstants.CRLF;
165 
166         connector.setHandler(new ClientSessionHandler(cmd));
167 
168         IoSession session;
169         for (;;) {
170             try {
171                 ConnectFuture future = connector.connect();
172                 future.awaitUninterruptibly();
173                 session = future.getSession();
174                 break;
175             } catch (RuntimeIoException e) {
176                 System.err.println("Failed to connect. Retrying in 5 secs ...");
177                 Thread.sleep(5000);
178             }
179         }
180 
181         // Wait until done
182         if (session != null) {
183             session.getCloseFuture().awaitUninterruptibly();
184         }
185         connector.dispose();
186         System.exit(0);
187     }
188 
189     /**
190      * Creates a {@link HttpProxyRequest} from the provided <i>uri</i> parameter.
191      * It uses the global variables defined at the top of the class to fill the 
192      * connection properties of the request. If the global variable <i>useHttp1_1</i> 
193      * is set to true, it will create a HTTP/1.1 request.
194      * 
195      * @param uri the requested uri to connect to through the HTTP proxy
196      * @return the fully initialized {@link HttpProxyRequest} object
197      */
198     private HttpProxyRequest createHttpProxyRequest(String uri) {
199         HttpProxyRequest req = new HttpProxyRequest(uri);
200         HashMap<String, String> props = new HashMap<String, String>();
201         props.put(HttpProxyConstants.USER_PROPERTY, USER);
202         props.put(HttpProxyConstants.PWD_PROPERTY, PWD);
203         props.put(HttpProxyConstants.DOMAIN_PROPERTY, DOMAIN);
204         props.put(HttpProxyConstants.WORKSTATION_PROPERTY, WORKSTATION);
205 
206         req.setProperties(props);
207         if (USE_HTTP_1_1) {
208             req.setHttpVersion(HttpProxyConstants.HTTP_1_1);
209         }
210 
211         return req;
212     }
213 
214     /**
215      * {@inheritDoc}
216      */
217     public static void main(String[] args) throws Exception {
218         new ProxyTestClient(args);
219     }
220 }