001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.example.proxy; 021 022import java.net.InetSocketAddress; 023import java.net.URL; 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.List; 027 028import org.apache.mina.core.RuntimeIoException; 029import org.apache.mina.core.future.ConnectFuture; 030import org.apache.mina.core.session.IdleStatus; 031import org.apache.mina.core.session.IoSession; 032import org.apache.mina.filter.logging.LoggingFilter; 033import org.apache.mina.proxy.ProxyConnector; 034import org.apache.mina.proxy.handlers.ProxyRequest; 035import org.apache.mina.proxy.handlers.http.HttpAuthenticationMethods; 036import org.apache.mina.proxy.handlers.http.HttpProxyConstants; 037import org.apache.mina.proxy.handlers.http.HttpProxyRequest; 038import org.apache.mina.proxy.handlers.socks.SocksProxyConstants; 039import org.apache.mina.proxy.handlers.socks.SocksProxyRequest; 040import org.apache.mina.proxy.session.ProxyIoSession; 041import org.apache.mina.transport.socket.nio.NioSocketConnector; 042 043/** 044 * ProxyTestClient.java - Base test class for mina proxy 045 * 046 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 047 * @since MINA 2.0.0-M3 048 */ 049public class ProxyTestClient { 050 051 /** 052 * The global variables used when creating the HTTP proxy connection. 053 */ 054 055 /** 056 * The user login. 057 */ 058 public final static String USER = "TED_KODS"; 059 060 /** 061 * The user password. 062 */ 063 public final static String PWD = "EDOUARD"; 064 065 /** 066 * The domain name. (used in NTLM connections) 067 */ 068 public final static String DOMAIN = "MYDOMAIN"; 069 070 /** 071 * The workstation name. (used in NTLM connections) 072 */ 073 public final static String WORKSTATION = "MYWORKSTATION"; 074 075 /** 076 * Set this variable to true in order to generate HTTP/1.1 requests. 077 */ 078 private final static boolean USE_HTTP_1_1 = false; 079 080 /** 081 * Creates a connection to the endpoint through a proxy server using the specified 082 * authentication method. 083 * 084 * Command line arguments: 085 * ProxyTestClient <proxy-hostname> <proxy-port> <url> <proxy-method> 086 * 087 * Note that <proxy-method> is OPTIONNAL a HTTP proxy connection will be used if not 088 * specified. 089 * 090 * Examples: 091 * ProxyTestClient myproxy 8080 http://mina.apache.org SOCKS4 092 * ProxyTestClient squidsrv 3128 http://mina.apache.org:80 093 * 094 * @param args parse arguments to get proxy hostaname, proxy port, the url to connect to 095 * and optionnaly the proxy authentication method 096 * @throws Exception 097 */ 098 public ProxyTestClient(String[] args) throws Exception { 099 if (args.length < 3) { 100 System.out 101 .println(ProxyTestClient.class.getName() 102 + " <proxy-hostname> <proxy-port> <url> <proxy-method> (<proxy-method> is OPTIONNAL)"); 103 return; 104 } 105 106 // Create proxy connector. 107 NioSocketConnector socketConnector = new NioSocketConnector(Runtime 108 .getRuntime().availableProcessors() + 1); 109 110 ProxyConnector connector = new ProxyConnector(socketConnector); 111 112 // Set connect timeout. 113 connector.setConnectTimeoutMillis(5000); 114 115 URL url = new URL(args[2]); 116 int port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort(); 117 118 ProxyRequest req = null; 119 120 if (args.length == 4) { 121 if ("SOCKS4".equals(args[3])) { 122 req = new SocksProxyRequest( 123 SocksProxyConstants.SOCKS_VERSION_4, 124 SocksProxyConstants.ESTABLISH_TCPIP_STREAM, 125 new InetSocketAddress(url.getHost(), port), USER); 126 } else if ("SOCKS4a".equals(args[3])) { 127 req = new SocksProxyRequest( 128 SocksProxyConstants.ESTABLISH_TCPIP_STREAM, url 129 .getHost(), port, USER); 130 } else if ("SOCKS5".equals(args[3])) { 131 req = new SocksProxyRequest( 132 SocksProxyConstants.SOCKS_VERSION_5, 133 SocksProxyConstants.ESTABLISH_TCPIP_STREAM, 134 new InetSocketAddress(url.getHost(), port), USER); 135 ((SocksProxyRequest) req).setPassword(PWD); 136 ((SocksProxyRequest) req) 137 .setServiceKerberosName(Socks5GSSAPITestServer.SERVICE_NAME); 138 } else { 139 req = createHttpProxyRequest(args[2]); 140 } 141 } else { 142 req = createHttpProxyRequest(args[2]); 143 } 144 145 ProxyIoSession proxyIoSession = new ProxyIoSession( 146 new InetSocketAddress(args[0], Integer.parseInt(args[1])), req); 147 148 // Tests modifying authentication order preferences. First algorithm in list available on server 149 // will be used for authentication. 150 List<HttpAuthenticationMethods> l = new ArrayList<HttpAuthenticationMethods>(); 151 l.add(HttpAuthenticationMethods.DIGEST); 152 l.add(HttpAuthenticationMethods.BASIC); 153 proxyIoSession.setPreferedOrder(l); 154 155 connector.setProxyIoSession(proxyIoSession); 156 157 socketConnector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5); 158 159 connector.getFilterChain().addLast("logger", new LoggingFilter()); 160 161 // This command is sent when using a socks proxy to request a page from the web server. 162 String cmd = "GET " + url.toExternalForm() + " HTTP/1.0" 163 + HttpProxyConstants.CRLF + HttpProxyConstants.CRLF; 164 165 connector.setHandler(new ClientSessionHandler(cmd)); 166 167 IoSession session; 168 for (;;) { 169 try { 170 ConnectFuture future = connector.connect(); 171 future.awaitUninterruptibly(); 172 session = future.getSession(); 173 break; 174 } catch (RuntimeIoException e) { 175 System.err.println("Failed to connect. Retrying in 5 secs ..."); 176 Thread.sleep(5000); 177 } 178 } 179 180 // Wait until done 181 if (session != null) { 182 session.getCloseFuture().awaitUninterruptibly(); 183 } 184 connector.dispose(); 185 System.exit(0); 186 } 187 188 /** 189 * Creates a {@link HttpProxyRequest} from the provided <i>uri</i> parameter. 190 * It uses the global variables defined at the top of the class to fill the 191 * connection properties of the request. If the global variable <i>useHttp1_1</i> 192 * is set to true, it will create a HTTP/1.1 request. 193 * 194 * @param uri the requested uri to connect to through the HTTP proxy 195 * @return the fully initialized {@link HttpProxyRequest} object 196 */ 197 private HttpProxyRequest createHttpProxyRequest(String uri) { 198 HttpProxyRequest req = new HttpProxyRequest(uri); 199 HashMap<String, String> props = new HashMap<String, String>(); 200 props.put(HttpProxyConstants.USER_PROPERTY, USER); 201 props.put(HttpProxyConstants.PWD_PROPERTY, PWD); 202 props.put(HttpProxyConstants.DOMAIN_PROPERTY, DOMAIN); 203 props.put(HttpProxyConstants.WORKSTATION_PROPERTY, WORKSTATION); 204 205 req.setProperties(props); 206 if (USE_HTTP_1_1) { 207 req.setHttpVersion(HttpProxyConstants.HTTP_1_1); 208 } 209 210 return req; 211 } 212 213 /** 214 * {@inheritDoc} 215 */ 216 public static void main(String[] args) throws Exception { 217 new ProxyTestClient(args); 218 } 219}