Implemented CONNECT functionalities.
This commit is contained in:
parent
9abc3988fb
commit
3e4b7d7fb4
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.proxy;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
|
||||||
|
public class DownstreamConnection extends ProxyConnection
|
||||||
|
{
|
||||||
|
private final ByteBuffer buffer;
|
||||||
|
|
||||||
|
public DownstreamConnection(EndPoint endPoint, Executor executor, ByteBufferPool bufferPool, ConcurrentMap<String, Object> context, ConnectHandler connectHandler, ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
super(endPoint, executor, bufferPool, context, connectHandler);
|
||||||
|
this.buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen()
|
||||||
|
{
|
||||||
|
super.onOpen();
|
||||||
|
final int remaining = buffer.remaining();
|
||||||
|
write(buffer, new Callback<Void>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void completed(Void context)
|
||||||
|
{
|
||||||
|
LOG.debug("{} wrote initial {} bytes to server", DownstreamConnection.this, remaining);
|
||||||
|
fillInterested();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Void context, Throwable x)
|
||||||
|
{
|
||||||
|
LOG.debug(this + " failed to write initial " + remaining + " bytes to server", x);
|
||||||
|
close();
|
||||||
|
getConnection().close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.proxy;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.io.AbstractConnection;
|
||||||
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
|
import org.eclipse.jetty.io.Connection;
|
||||||
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
import org.eclipse.jetty.util.ForkInvoker;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
public abstract class ProxyConnection extends AbstractConnection
|
||||||
|
{
|
||||||
|
protected static final Logger LOG = ConnectHandler.LOG;
|
||||||
|
private final ForkInvoker<ByteBuffer> invoker = new ProxyForkInvoker();
|
||||||
|
private final ByteBufferPool bufferPool;
|
||||||
|
private final ConcurrentMap<String, Object> context;
|
||||||
|
private final ConnectHandler connectHandler;
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
protected ProxyConnection(EndPoint endp, Executor executor, ByteBufferPool bufferPool, ConcurrentMap<String, Object> context, ConnectHandler connectHandler)
|
||||||
|
{
|
||||||
|
super(endp, executor);
|
||||||
|
this.bufferPool = bufferPool;
|
||||||
|
this.context = context;
|
||||||
|
this.connectHandler = connectHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBufferPool getByteBufferPool()
|
||||||
|
{
|
||||||
|
return bufferPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentMap<String, Object> getContext()
|
||||||
|
{
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectHandler getConnectHandler()
|
||||||
|
{
|
||||||
|
return connectHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection getConnection()
|
||||||
|
{
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnection(Connection connection)
|
||||||
|
{
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFillable()
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = getByteBufferPool().acquire(getInputBufferSize(), true);
|
||||||
|
fill(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fill(final ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final int filled = connectHandler.read(getEndPoint(), buffer, getContext());
|
||||||
|
LOG.debug("{} filled {} bytes", this, filled);
|
||||||
|
if (filled > 0)
|
||||||
|
{
|
||||||
|
write(buffer, new Callback<Void>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void completed(Void context)
|
||||||
|
{
|
||||||
|
LOG.debug("{} wrote {} bytes", this, filled);
|
||||||
|
buffer.clear();
|
||||||
|
invoker.invoke(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Void context, Throwable x)
|
||||||
|
{
|
||||||
|
LOG.debug(this + " failed to write " + filled + " bytes", x);
|
||||||
|
bufferPool.release(buffer);
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (filled == 0)
|
||||||
|
{
|
||||||
|
bufferPool.release(buffer);
|
||||||
|
fillInterested();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bufferPool.release(buffer);
|
||||||
|
connection.getEndPoint().shutdownOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException x)
|
||||||
|
{
|
||||||
|
LOG.debug(this + " could not fill", x);
|
||||||
|
bufferPool.release(buffer);
|
||||||
|
close();
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void write(ByteBuffer buffer, Callback<Void> callback)
|
||||||
|
{
|
||||||
|
LOG.debug("{} writing {} bytes", this, buffer.remaining());
|
||||||
|
connectHandler.write(getConnection().getEndPoint(), buffer, context, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("%s[l:%d<=>r:%d]",
|
||||||
|
super.toString(),
|
||||||
|
getEndPoint().getLocalAddress().getPort(),
|
||||||
|
getEndPoint().getRemoteAddress().getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProxyForkInvoker extends ForkInvoker<ByteBuffer>
|
||||||
|
{
|
||||||
|
private ProxyForkInvoker()
|
||||||
|
{
|
||||||
|
super(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fork(final ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
getExecutor().execute(new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
call(buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
fill(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,11 +124,11 @@ public class ProxyServlet extends HttpServlet
|
||||||
|
|
||||||
String whiteList = config.getInitParameter("whiteList");
|
String whiteList = config.getInitParameter("whiteList");
|
||||||
if (whiteList != null)
|
if (whiteList != null)
|
||||||
getWhitelistHosts().addAll(parseList(whiteList));
|
getWhiteListHosts().addAll(parseList(whiteList));
|
||||||
|
|
||||||
String blackList = config.getInitParameter("blackList");
|
String blackList = config.getInitParameter("blackList");
|
||||||
if (blackList != null)
|
if (blackList != null)
|
||||||
getBlacklistHosts().addAll(parseList(blackList));
|
getBlackListHosts().addAll(parseList(blackList));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -146,12 +146,12 @@ public class ProxyServlet extends HttpServlet
|
||||||
this._timeout = timeout;
|
this._timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getWhitelistHosts()
|
public Set<String> getWhiteListHosts()
|
||||||
{
|
{
|
||||||
return _whiteList;
|
return _whiteList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getBlacklistHosts()
|
public Set<String> getBlackListHosts()
|
||||||
{
|
{
|
||||||
return _blackList;
|
return _blackList;
|
||||||
}
|
}
|
||||||
|
@ -313,12 +313,11 @@ public class ProxyServlet extends HttpServlet
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the request hostname and path against whitelist and blacklist.
|
* Checks the given {@code host} and {@code port} against whitelist and blacklist.
|
||||||
*
|
*
|
||||||
*
|
* @param host the host to check
|
||||||
* @param host host to check
|
|
||||||
* @param port the port to check
|
* @param port the port to check
|
||||||
* @return true if request is allowed to be proxied
|
* @return true if it is allowed to be proxy to the given host and port
|
||||||
*/
|
*/
|
||||||
public boolean validateDestination(String host, int port)
|
public boolean validateDestination(String host, int port)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.proxy;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
|
||||||
|
public class UpstreamConnection extends ProxyConnection
|
||||||
|
{
|
||||||
|
private ConnectHandler.ConnectContext connectContext;
|
||||||
|
|
||||||
|
public UpstreamConnection(EndPoint endPoint, Executor executor, ByteBufferPool bufferPool, ConnectHandler connectHandler, ConnectHandler.ConnectContext connectContext)
|
||||||
|
{
|
||||||
|
super(endPoint, executor, bufferPool, connectContext.getContext(), connectHandler);
|
||||||
|
this.connectContext = connectContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen()
|
||||||
|
{
|
||||||
|
super.onOpen();
|
||||||
|
getConnectHandler().onConnectSuccess(connectContext, this);
|
||||||
|
fillInterested();
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,180 +18,62 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.proxy;
|
package org.eclipse.jetty.proxy;
|
||||||
|
|
||||||
/**
|
import java.io.BufferedReader;
|
||||||
* @version $Revision$ $Date$
|
import java.io.IOException;
|
||||||
*/
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.NetworkConnector;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser;
|
||||||
|
import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse;
|
||||||
|
import org.junit.After;
|
||||||
|
|
||||||
public abstract class AbstractConnectHandlerTest
|
public abstract class AbstractConnectHandlerTest
|
||||||
{
|
{
|
||||||
// protected static Server server;
|
protected Server server;
|
||||||
// protected static Connector.NetConnector serverConnector;
|
protected ServerConnector serverConnector;
|
||||||
// protected static Server proxy;
|
protected Server proxy;
|
||||||
// protected static Connector proxyConnector;
|
protected Connector proxyConnector;
|
||||||
//
|
protected ConnectHandler connectHandler;
|
||||||
// protected static void startServer(Connector.NetConnector connector, Handler handler) throws Exception
|
|
||||||
// {
|
protected void prepareProxy() throws Exception
|
||||||
// server = new Server();
|
{
|
||||||
// serverConnector = connector;
|
proxy = new Server();
|
||||||
// server.addConnector(serverConnector);
|
proxyConnector = new ServerConnector(proxy);
|
||||||
// server.setHandler(handler);
|
proxy.addConnector(proxyConnector);
|
||||||
// server.start();
|
connectHandler = new ConnectHandler();
|
||||||
// }
|
proxy.setHandler(connectHandler);
|
||||||
//
|
proxy.start();
|
||||||
// protected static void startProxy() throws Exception
|
}
|
||||||
// {
|
|
||||||
// proxy = new Server();
|
@After
|
||||||
// proxyConnector = new SelectChannelConnector();
|
public void dispose() throws Exception
|
||||||
// proxy.addConnector(proxyConnector);
|
{
|
||||||
// proxy.setHandler(new ConnectHandler());
|
disposeServer();
|
||||||
// proxy.start();
|
disposeProxy();
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @AfterClass
|
protected void disposeServer() throws Exception
|
||||||
// public static void stop() throws Exception
|
{
|
||||||
// {
|
server.stop();
|
||||||
// stopProxy();
|
}
|
||||||
// stopServer();
|
|
||||||
// }
|
protected void disposeProxy() throws Exception
|
||||||
//
|
{
|
||||||
// protected static void stopServer() throws Exception
|
proxy.stop();
|
||||||
// {
|
}
|
||||||
// server.stop();
|
|
||||||
// server.join();
|
protected SimpleHttpResponse readResponse(BufferedReader reader) throws IOException
|
||||||
// }
|
{
|
||||||
//
|
return new SimpleHttpParser().readResponse(reader);
|
||||||
// protected static void stopProxy() throws Exception
|
}
|
||||||
// {
|
|
||||||
// proxy.stop();
|
protected Socket newSocket() throws IOException
|
||||||
// proxy.join();
|
{
|
||||||
// }
|
Socket socket = new Socket("localhost", ((NetworkConnector)proxyConnector).getLocalPort());
|
||||||
//
|
socket.setSoTimeout(5000);
|
||||||
// protected Response readResponse(BufferedReader reader) throws IOException
|
return socket;
|
||||||
// {
|
}
|
||||||
// // Simplified parser for HTTP responses
|
|
||||||
// String line = reader.readLine();
|
|
||||||
// if (line == null)
|
|
||||||
// throw new EOFException();
|
|
||||||
// Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line);
|
|
||||||
// assertTrue(responseLine.lookingAt());
|
|
||||||
// String code = responseLine.group(1);
|
|
||||||
//
|
|
||||||
// Map<String, String> headers = new LinkedHashMap<String, String>();
|
|
||||||
// while ((line = reader.readLine()) != null)
|
|
||||||
// {
|
|
||||||
// if (line.trim().length() == 0)
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line);
|
|
||||||
// assertTrue(header.lookingAt());
|
|
||||||
// String headerName = header.group(1);
|
|
||||||
// String headerValue = header.group(2);
|
|
||||||
// headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// StringBuilder body;
|
|
||||||
// if (headers.containsKey("content-length"))
|
|
||||||
// {
|
|
||||||
// int readLen = 0;
|
|
||||||
// int length = Integer.parseInt(headers.get("content-length"));
|
|
||||||
// body=new StringBuilder(length);
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// for (int i = 0; i < length; ++i)
|
|
||||||
// {
|
|
||||||
// char c = (char)reader.read();
|
|
||||||
// body.append(c);
|
|
||||||
// readLen++;
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// catch (SocketTimeoutException e)
|
|
||||||
// {
|
|
||||||
// System.err.printf("Read %,d bytes (out of an expected %,d bytes)%n",readLen,length);
|
|
||||||
// throw e;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if ("chunked".equals(headers.get("transfer-encoding")))
|
|
||||||
// {
|
|
||||||
// body = new StringBuilder(64*1024);
|
|
||||||
// while ((line = reader.readLine()) != null)
|
|
||||||
// {
|
|
||||||
// if ("0".equals(line))
|
|
||||||
// {
|
|
||||||
// line = reader.readLine();
|
|
||||||
// assertEquals("", line);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// Thread.sleep(5);
|
|
||||||
// }
|
|
||||||
// catch (InterruptedException e)
|
|
||||||
// {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// int length = Integer.parseInt(line, 16);
|
|
||||||
// for (int i = 0; i < length; ++i)
|
|
||||||
// {
|
|
||||||
// char c = (char)reader.read();
|
|
||||||
// body.append(c);
|
|
||||||
// }
|
|
||||||
// line = reader.readLine();
|
|
||||||
// assertEquals("", line);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else throw new IllegalStateException();
|
|
||||||
//
|
|
||||||
// return new Response(code, headers, body.toString().trim());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// protected Socket newSocket() throws IOException
|
|
||||||
// {
|
|
||||||
// Socket socket = new Socket("localhost", ((Connector.NetConnector)proxyConnector).getLocalPort());
|
|
||||||
// socket.setSoTimeout(10000);
|
|
||||||
// return socket;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// protected class Response
|
|
||||||
// {
|
|
||||||
// private final String code;
|
|
||||||
// private final Map<String, String> headers;
|
|
||||||
// private final String body;
|
|
||||||
//
|
|
||||||
// private Response(String code, Map<String, String> headers, String body)
|
|
||||||
// {
|
|
||||||
// this.code = code;
|
|
||||||
// this.headers = headers;
|
|
||||||
// this.body = body;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public String getCode()
|
|
||||||
// {
|
|
||||||
// return code;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public Map<String, String> getHeaders()
|
|
||||||
// {
|
|
||||||
// return headers;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public String getBody()
|
|
||||||
// {
|
|
||||||
// return body;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public String toString()
|
|
||||||
// {
|
|
||||||
// StringBuilder builder = new StringBuilder();
|
|
||||||
// builder.append(code).append("\r\n");
|
|
||||||
// for (Map.Entry<String, String> entry : headers.entrySet())
|
|
||||||
// builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
|
|
||||||
// builder.append("\r\n");
|
|
||||||
// builder.append(body);
|
|
||||||
// return builder.toString();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,199 +18,184 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.proxy;
|
package org.eclipse.jetty.proxy;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
|
||||||
* @version $Revision$ $Date$
|
|
||||||
*/
|
|
||||||
@Ignore
|
|
||||||
public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest
|
public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest
|
||||||
{
|
{
|
||||||
// @BeforeClass
|
private SslContextFactory sslContextFactory;
|
||||||
// public static void init() throws Exception
|
|
||||||
// {
|
@Before
|
||||||
// SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
public void prepare() throws Exception
|
||||||
// connector.setMaxIdleTime(3600000); // TODO remove
|
{
|
||||||
//
|
sslContextFactory = new SslContextFactory();
|
||||||
// String keyStorePath = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
String keyStorePath = MavenTestingUtils.getTestResourceFile("keystore.jks").getAbsolutePath();
|
||||||
// SslContextFactory cf = connector.getSslContextFactory();
|
sslContextFactory.setKeyStorePath(keyStorePath);
|
||||||
// cf.setKeyStorePath(keyStorePath);
|
sslContextFactory.setKeyStorePassword("storepwd");
|
||||||
// cf.setKeyStorePassword("storepwd");
|
String trustStorePath = MavenTestingUtils.getTestResourceFile("truststore.jks").getAbsolutePath();
|
||||||
// cf.setKeyManagerPassword("keypwd");
|
sslContextFactory.setTrustStorePath(trustStorePath);
|
||||||
//
|
sslContextFactory.setTrustStorePassword("storepwd");
|
||||||
// startServer(connector, new ServerHandler());
|
server = new Server();
|
||||||
// startProxy();
|
serverConnector = new ServerConnector(server, sslContextFactory);
|
||||||
// }
|
server.addConnector(serverConnector);
|
||||||
//
|
server.setHandler(new ServerHandler());
|
||||||
// @Test
|
server.start();
|
||||||
// public void testGETRequest() throws Exception
|
prepareProxy();
|
||||||
// {
|
}
|
||||||
// String hostPort = "localhost:" + ((Connector.NetConnector)serverConnector).getLocalPort();
|
|
||||||
// String request = "" +
|
@Test
|
||||||
// "CONNECT " + hostPort + " HTTP/1.1\r\n" +
|
public void testGETRequest() throws Exception
|
||||||
// "Host: " + hostPort + "\r\n" +
|
{
|
||||||
// "\r\n";
|
String hostPort = "localhost:" + serverConnector.getLocalPort();
|
||||||
// Socket socket = newSocket();
|
String request = "" +
|
||||||
// socket.setSoTimeout(3600000); // TODO remove
|
"CONNECT " + hostPort + " HTTP/1.1\r\n" +
|
||||||
// try
|
"Host: " + hostPort + "\r\n" +
|
||||||
// {
|
"\r\n";
|
||||||
// OutputStream output = socket.getOutputStream();
|
try (Socket socket = newSocket())
|
||||||
// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
{
|
||||||
//
|
OutputStream output = socket.getOutputStream();
|
||||||
// output.write(request.getBytes("UTF-8"));
|
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
// output.flush();
|
|
||||||
//
|
output.write(request.getBytes("UTF-8"));
|
||||||
// // Expect 200 OK from the CONNECT request
|
output.flush();
|
||||||
// Response response = readResponse(input);
|
|
||||||
// System.err.println(response);
|
// Expect 200 OK from the CONNECT request
|
||||||
// assertEquals("200", response.getCode());
|
SimpleHttpResponse response = readResponse(input);
|
||||||
//
|
Assert.assertEquals("200", response.getCode());
|
||||||
// // Be sure the buffered input does not have anything buffered
|
|
||||||
// assertFalse(input.ready());
|
// Be sure the buffered input does not have anything buffered
|
||||||
//
|
Assert.assertFalse(input.ready());
|
||||||
// // Upgrade the socket to SSL
|
|
||||||
// SSLSocket sslSocket = wrapSocket(socket);
|
// Upgrade the socket to SSL
|
||||||
// try
|
try (SSLSocket sslSocket = wrapSocket(socket))
|
||||||
// {
|
{
|
||||||
// output = sslSocket.getOutputStream();
|
output = sslSocket.getOutputStream();
|
||||||
// input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
|
input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
|
||||||
//
|
|
||||||
// request =
|
request =
|
||||||
// "GET /echo HTTP/1.1\r\n" +
|
"GET /echo HTTP/1.1\r\n" +
|
||||||
// "Host: " + hostPort + "\r\n" +
|
"Host: " + hostPort + "\r\n" +
|
||||||
// "\r\n";
|
"\r\n";
|
||||||
// output.write(request.getBytes("UTF-8"));
|
output.write(request.getBytes("UTF-8"));
|
||||||
// output.flush();
|
output.flush();
|
||||||
//
|
|
||||||
// response = readResponse(input);
|
response = readResponse(input);
|
||||||
// assertEquals("200", response.getCode());
|
Assert.assertEquals("200", response.getCode());
|
||||||
// assertEquals("GET /echo", response.getBody());
|
Assert.assertEquals("GET /echo", response.getBody());
|
||||||
// }
|
}
|
||||||
// finally
|
}
|
||||||
// {
|
}
|
||||||
// sslSocket.close();
|
|
||||||
// }
|
@Test
|
||||||
// }
|
public void testPOSTRequests() throws Exception
|
||||||
// finally
|
{
|
||||||
// {
|
String hostPort = "localhost:" + serverConnector.getLocalPort();
|
||||||
// socket.close();
|
String request = "" +
|
||||||
// }
|
"CONNECT " + hostPort + " HTTP/1.1\r\n" +
|
||||||
// }
|
"Host: " + hostPort + "\r\n" +
|
||||||
//
|
"\r\n";
|
||||||
// @Test
|
try (Socket socket = newSocket())
|
||||||
// public void testPOSTRequests() throws Exception
|
{
|
||||||
// {
|
OutputStream output = socket.getOutputStream();
|
||||||
// String hostPort = "localhost:" + ((Connector.NetConnector)serverConnector).getLocalPort();
|
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
// String request = "" +
|
|
||||||
// "CONNECT " + hostPort + " HTTP/1.1\r\n" +
|
output.write(request.getBytes("UTF-8"));
|
||||||
// "Host: " + hostPort + "\r\n" +
|
output.flush();
|
||||||
// "\r\n";
|
|
||||||
// Socket socket = newSocket();
|
// Expect 200 OK from the CONNECT request
|
||||||
// try
|
SimpleHttpResponse response = readResponse(input);
|
||||||
// {
|
Assert.assertEquals("200", response.getCode());
|
||||||
// OutputStream output = socket.getOutputStream();
|
|
||||||
// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
// Be sure the buffered input does not have anything buffered
|
||||||
//
|
Assert.assertFalse(input.ready());
|
||||||
// output.write(request.getBytes("UTF-8"));
|
|
||||||
// output.flush();
|
// Upgrade the socket to SSL
|
||||||
//
|
try (SSLSocket sslSocket = wrapSocket(socket))
|
||||||
// // Expect 200 OK from the CONNECT request
|
{
|
||||||
// Response response = readResponse(input);
|
output = sslSocket.getOutputStream();
|
||||||
// assertEquals("200", response.getCode());
|
input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
|
||||||
//
|
|
||||||
// // Be sure the buffered input does not have anything buffered
|
for (int i = 0; i < 10; ++i)
|
||||||
// assertFalse(input.ready());
|
{
|
||||||
//
|
request = "" +
|
||||||
// // Upgrade the socket to SSL
|
"POST /echo?param=" + i + " HTTP/1.1\r\n" +
|
||||||
// SSLSocket sslSocket = wrapSocket(socket);
|
"Host: " + hostPort + "\r\n" +
|
||||||
// try
|
"Content-Length: 5\r\n" +
|
||||||
// {
|
"\r\n" +
|
||||||
// output = sslSocket.getOutputStream();
|
"HELLO";
|
||||||
// input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
|
output.write(request.getBytes("UTF-8"));
|
||||||
//
|
output.flush();
|
||||||
// for (int i = 0; i < 10; ++i)
|
|
||||||
// {
|
response = readResponse(input);
|
||||||
// request = "" +
|
Assert.assertEquals("200", response.getCode());
|
||||||
// "POST /echo?param=" + i + " HTTP/1.1\r\n" +
|
Assert.assertEquals("POST /echo?param=" + i + "\r\nHELLO", response.getBody());
|
||||||
// "Host: " + hostPort + "\r\n" +
|
}
|
||||||
// "Content-Length: 5\r\n" +
|
}
|
||||||
// "\r\n" +
|
}
|
||||||
// "HELLO";
|
}
|
||||||
// output.write(request.getBytes("UTF-8"));
|
|
||||||
// output.flush();
|
private SSLSocket wrapSocket(Socket socket) throws Exception
|
||||||
//
|
{
|
||||||
// response = readResponse(input);
|
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||||
// assertEquals("200", response.getCode());
|
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
|
||||||
// assertEquals("POST /echo?param=" + i + "\r\nHELLO", response.getBody());
|
SSLSocket sslSocket = (SSLSocket)socketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true);
|
||||||
// }
|
sslSocket.setUseClientMode(true);
|
||||||
// }
|
sslSocket.startHandshake();
|
||||||
// finally
|
return sslSocket;
|
||||||
// {
|
}
|
||||||
// sslSocket.close();
|
|
||||||
// }
|
private static class ServerHandler extends AbstractHandler
|
||||||
// }
|
{
|
||||||
// finally
|
public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||||
// {
|
{
|
||||||
// socket.close();
|
request.setHandled(true);
|
||||||
// }
|
|
||||||
// }
|
String uri = httpRequest.getRequestURI();
|
||||||
//
|
if ("/echo".equals(uri))
|
||||||
// private SSLSocket wrapSocket(Socket socket) throws Exception
|
{
|
||||||
// {
|
StringBuilder builder = new StringBuilder();
|
||||||
// SSLContext sslContext = SSLContext.getInstance("SSLv3");
|
builder.append(httpRequest.getMethod()).append(" ").append(uri);
|
||||||
// sslContext.init(null, new TrustManager[]{new AlwaysTrustManager()}, new SecureRandom());
|
if (httpRequest.getQueryString() != null)
|
||||||
// SSLSocketFactory socketFactory = sslContext.getSocketFactory();
|
builder.append("?").append(httpRequest.getQueryString());
|
||||||
// SSLSocket sslSocket = (SSLSocket)socketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true);
|
|
||||||
// sslSocket.setUseClientMode(true);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
// sslSocket.startHandshake();
|
InputStream input = httpRequest.getInputStream();
|
||||||
// return sslSocket;
|
int read;
|
||||||
// }
|
while ((read = input.read()) >= 0)
|
||||||
//
|
baos.write(read);
|
||||||
// private class AlwaysTrustManager implements X509TrustManager
|
baos.close();
|
||||||
// {
|
|
||||||
// public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
|
ServletOutputStream output = httpResponse.getOutputStream();
|
||||||
// {
|
output.println(builder.toString());
|
||||||
// }
|
output.write(baos.toByteArray());
|
||||||
//
|
}
|
||||||
// public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
|
else
|
||||||
// {
|
{
|
||||||
// }
|
throw new ServletException();
|
||||||
//
|
}
|
||||||
// public X509Certificate[] getAcceptedIssuers()
|
}
|
||||||
// {
|
}
|
||||||
// return new X509Certificate[]{};
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private static class ServerHandler extends AbstractHandler
|
|
||||||
// {
|
|
||||||
// public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
|
||||||
// {
|
|
||||||
// request.setHandled(true);
|
|
||||||
//
|
|
||||||
// String uri = httpRequest.getRequestURI();
|
|
||||||
// if ("/echo".equals(uri))
|
|
||||||
// {
|
|
||||||
// StringBuilder builder = new StringBuilder();
|
|
||||||
// builder.append(httpRequest.getMethod()).append(" ").append(uri);
|
|
||||||
// if (httpRequest.getQueryString() != null)
|
|
||||||
// builder.append("?").append(httpRequest.getQueryString());
|
|
||||||
//
|
|
||||||
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
// InputStream input = httpRequest.getInputStream();
|
|
||||||
// int read = -1;
|
|
||||||
// while ((read = input.read()) >= 0)
|
|
||||||
// baos.write(read);
|
|
||||||
// baos.close();
|
|
||||||
//
|
|
||||||
// ServletOutputStream output = httpResponse.getOutputStream();
|
|
||||||
// output.println(builder.toString());
|
|
||||||
// output.write(baos.toByteArray());
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// throw new ServletException();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// All rights reserved. This program and the accompanying materials
|
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
|
||||||
//
|
|
||||||
// The Eclipse Public License is available at
|
|
||||||
// http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
//
|
|
||||||
// The Apache License v2.0 is available at
|
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
|
||||||
//
|
|
||||||
// You may elect to redistribute this code under either of these licenses.
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.proxy;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
//@RunWith(MockitoJUnitRunner.class)
|
|
||||||
public class ConnectHandlerUnitTest
|
|
||||||
{
|
|
||||||
// @Mock
|
|
||||||
// private EndPoint endPoint;
|
|
||||||
//
|
|
||||||
// // TODO update for jetty-9
|
|
||||||
// @Test
|
|
||||||
// @Ignore
|
|
||||||
// public void testPartialWritesWithNonFullBuffer() throws IOException
|
|
||||||
// {
|
|
||||||
// /*
|
|
||||||
// ConnectHandler connectHandler = new ConnectHandler();
|
|
||||||
// final byte[] bytes = "foo bar".getBytes();
|
|
||||||
// Buffer buffer = new ByteArrayBuffer(bytes.length * 2);
|
|
||||||
// buffer.put(bytes);
|
|
||||||
// when(endPoint.flush(buffer)).thenAnswer(new Answer<Object>()
|
|
||||||
// {
|
|
||||||
// public Object answer(InvocationOnMock invocation)
|
|
||||||
// {
|
|
||||||
// Object[] args = invocation.getArguments();
|
|
||||||
// Buffer buffer = (Buffer)args[0];
|
|
||||||
// int skip = bytes.length/2;
|
|
||||||
// buffer.skip(skip);
|
|
||||||
// return skip;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// when(endPoint.blockWritable(anyInt())).thenReturn(true);
|
|
||||||
//
|
|
||||||
// // method to test
|
|
||||||
// connectHandler.write(endPoint,buffer,null);
|
|
||||||
//
|
|
||||||
// assertThat(buffer.length(),is(0));
|
|
||||||
// */
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
}
|
|
|
@ -536,12 +536,12 @@ public class ProxyServletTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProxyWhitelist() throws Exception
|
public void testProxyWhiteList() throws Exception
|
||||||
{
|
{
|
||||||
prepareProxy(new ProxyServlet());
|
prepareProxy(new ProxyServlet());
|
||||||
prepareServer(new EmptyHttpServlet());
|
prepareServer(new EmptyHttpServlet());
|
||||||
int port = serverConnector.getLocalPort();
|
int port = serverConnector.getLocalPort();
|
||||||
proxyServlet.getWhitelistHosts().add("127.0.0.1:" + port);
|
proxyServlet.getWhiteListHosts().add("127.0.0.1:" + port);
|
||||||
|
|
||||||
// Try with the wrong host
|
// Try with the wrong host
|
||||||
ContentResponse response = client.newRequest("localhost", port)
|
ContentResponse response = client.newRequest("localhost", port)
|
||||||
|
@ -557,12 +557,12 @@ public class ProxyServletTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProxyBlacklist() throws Exception
|
public void testProxyBlackList() throws Exception
|
||||||
{
|
{
|
||||||
prepareProxy(new ProxyServlet());
|
prepareProxy(new ProxyServlet());
|
||||||
prepareServer(new EmptyHttpServlet());
|
prepareServer(new EmptyHttpServlet());
|
||||||
int port = serverConnector.getLocalPort();
|
int port = serverConnector.getLocalPort();
|
||||||
proxyServlet.getBlacklistHosts().add("localhost:" + port);
|
proxyServlet.getBlackListHosts().add("localhost:" + port);
|
||||||
|
|
||||||
// Try with the wrong host
|
// Try with the wrong host
|
||||||
ContentResponse response = client.newRequest("localhost", port)
|
ContentResponse response = client.newRequest("localhost", port)
|
||||||
|
@ -744,6 +744,12 @@ public class ProxyServletTest
|
||||||
Assert.assertTrue(response.getHeaders().containsKey(PROXIED_HEADER));
|
Assert.assertTrue(response.getHeaders().containsKey(PROXIED_HEADER));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProxyAuthentication() throws Exception
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
private static class EmptyHttpServlet extends HttpServlet
|
private static class EmptyHttpServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue