Fixes #298502 (Https exchange through an http proxy).
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2197 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
e23d08749a
commit
fcc0c71d8f
|
@ -1,101 +1,104 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Asynchronous HTTP Client</name>
|
||||
<url>{$jetty.url}</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.bundle.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.net.*,*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--
|
||||
Required for OSGI
|
||||
-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.client.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit4-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Asynchronous HTTP Client</name>
|
||||
<url>{$jetty.url}</url>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.bundle.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.net.*,*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--
|
||||
Required for OSGI
|
||||
-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.client.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit4-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
|
|||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.View;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
@ -209,7 +208,7 @@ public class HttpConnection implements Connection
|
|||
if (_exchange == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
long flushed = _generator.flushBuffer();
|
||||
io += flushed;
|
||||
|
||||
|
@ -236,7 +235,7 @@ public class HttpConnection implements Connection
|
|||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
|
@ -254,7 +253,7 @@ public class HttpConnection implements Connection
|
|||
long filled = _parser.parseAvailable();
|
||||
io += filled;
|
||||
}
|
||||
|
||||
|
||||
if (io > 0)
|
||||
no_progress = 0;
|
||||
else if (no_progress++ >= 2 && !_endp.isBlocking())
|
||||
|
@ -342,12 +341,12 @@ public class HttpConnection implements Connection
|
|||
HttpExchange exchange=_exchange;
|
||||
_exchange.disassociate();
|
||||
_exchange = null;
|
||||
|
||||
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
{
|
||||
{
|
||||
// switched protocol!
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
|
@ -394,13 +393,13 @@ public class HttpConnection implements Connection
|
|||
{
|
||||
_exchange.disassociate();
|
||||
}
|
||||
|
||||
|
||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp instanceof AsyncEndPoint)
|
||||
{
|
||||
{
|
||||
((AsyncEndPoint)_endp).setWritable(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -436,18 +435,27 @@ public class HttpConnection implements Connection
|
|||
_exchange.setStatus(HttpExchange.STATUS_SENDING_REQUEST);
|
||||
_generator.setVersion(_exchange.getVersion());
|
||||
|
||||
String method=_exchange.getMethod();
|
||||
String uri = _exchange.getURI();
|
||||
if (_destination.isProxied() && uri.startsWith("/"))
|
||||
if (_destination.isProxied() && !HttpMethods.CONNECT.equals(method) && uri.startsWith("/"))
|
||||
{
|
||||
// TODO suppress port 80 or 443
|
||||
uri = (_destination.isSecure()?HttpSchemes.HTTPS:HttpSchemes.HTTP) + "://" + _destination.getAddress().getHost() + ":"
|
||||
+ _destination.getAddress().getPort() + uri;
|
||||
boolean secure = _destination.isSecure();
|
||||
String host = _destination.getAddress().getHost();
|
||||
int port = _destination.getAddress().getPort();
|
||||
StringBuilder absoluteURI = new StringBuilder();
|
||||
absoluteURI.append(secure ? HttpSchemes.HTTPS : HttpSchemes.HTTP);
|
||||
absoluteURI.append("://");
|
||||
absoluteURI.append(host);
|
||||
// Avoid adding default ports
|
||||
if (!(secure && port == 443 || !secure && port == 80))
|
||||
absoluteURI.append(":").append(port);
|
||||
absoluteURI.append(uri);
|
||||
uri = absoluteURI.toString();
|
||||
Authentication auth = _destination.getProxyAuthentication();
|
||||
if (auth != null)
|
||||
auth.setCredentials(_exchange);
|
||||
}
|
||||
|
||||
String method=_exchange.getMethod();
|
||||
_generator.setRequest(method, uri);
|
||||
_parser.setHeadResponse(HttpMethods.HEAD.equalsIgnoreCase(method));
|
||||
|
||||
|
@ -594,10 +602,10 @@ public class HttpConnection implements Connection
|
|||
|
||||
public void close() throws IOException
|
||||
{
|
||||
//if there is a live, unfinished exchange, set its status to be
|
||||
//if there is a live, unfinished exchange, set its status to be
|
||||
//excepted and wake up anyone waiting on waitForDone()
|
||||
|
||||
if (_exchange != null && !_exchange.isDone())
|
||||
|
||||
if (_exchange != null && !_exchange.isDone())
|
||||
{
|
||||
switch (_exchange.getStatus())
|
||||
{
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
// ========================================================================
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.ConnectException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -25,9 +25,12 @@ import org.eclipse.jetty.client.security.Authentication;
|
|||
import org.eclipse.jetty.client.security.SecurityListener;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
/**
|
||||
|
@ -307,7 +310,7 @@ public class HttpDestination
|
|||
}
|
||||
}
|
||||
|
||||
public void onNewConnection(HttpConnection connection) throws IOException
|
||||
public void onNewConnection(final HttpConnection connection) throws IOException
|
||||
{
|
||||
HttpConnection q_connection = null;
|
||||
|
||||
|
@ -328,8 +331,20 @@ public class HttpDestination
|
|||
}
|
||||
else
|
||||
{
|
||||
HttpExchange ex = _queue.removeFirst();
|
||||
send(connection, ex);
|
||||
EndPoint endPoint = connection.getEndPoint();
|
||||
if (isProxied() && endPoint instanceof SelectConnector.ProxySelectChannelEndPoint)
|
||||
{
|
||||
SelectConnector.ProxySelectChannelEndPoint proxyEndPoint = (SelectConnector.ProxySelectChannelEndPoint)endPoint;
|
||||
HttpExchange exchange = _queue.peekFirst();
|
||||
ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint, exchange);
|
||||
connect.setAddress(getProxy());
|
||||
send(connection, connect);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpExchange exchange = _queue.removeFirst();
|
||||
send(connection, exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,4 +595,41 @@ public class HttpDestination
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectExchange extends ContentExchange
|
||||
{
|
||||
private final SelectConnector.ProxySelectChannelEndPoint proxyEndPoint;
|
||||
private final HttpExchange exchange;
|
||||
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.ProxySelectChannelEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
{
|
||||
this.proxyEndPoint = proxyEndPoint;
|
||||
this.exchange = exchange;
|
||||
setMethod(HttpMethods.CONNECT);
|
||||
String serverHostAndPort = serverAddress.toString();
|
||||
setURI(serverHostAndPort);
|
||||
addRequestHeader(HttpHeaders.HOST, serverHostAndPort);
|
||||
addRequestHeader(HttpHeaders.PROXY_CONNECTION, "keep-alive");
|
||||
addRequestHeader(HttpHeaders.USER_AGENT, "Jetty-Client");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
if (getResponseStatus() == HttpStatus.OK_200)
|
||||
{
|
||||
proxyEndPoint.upgrade();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionFailed(new ConnectException(exchange.getAddress().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
HttpDestination.this.onConnectionFailed(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,20 +16,18 @@ package org.eclipse.jetty.client;
|
|||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpVersions;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ThreadLocalBuffers;
|
||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
|
||||
|
@ -218,14 +216,14 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector,
|
|||
{
|
||||
if (dest.isProxied())
|
||||
{
|
||||
String connect = HttpMethods.CONNECT+" "+dest.getAddress()+HttpVersions.HTTP_1_0+"\r\n\r\n";
|
||||
// TODO need to send this over channel unencrypted and setup endpoint to ignore the 200 OK response.
|
||||
|
||||
throw new IllegalStateException("Not Implemented");
|
||||
SSLEngine engine=newSslEngine();
|
||||
ep = new ProxySelectChannelEndPoint(channel,selectSet,key,_sslBuffers,engine);
|
||||
}
|
||||
else
|
||||
{
|
||||
SSLEngine engine=newSslEngine();
|
||||
ep = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,engine);
|
||||
}
|
||||
|
||||
SSLEngine engine=newSslEngine();
|
||||
ep = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,engine);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -283,4 +281,204 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that is able to "upgrade" from a normal endpoint to a SSL endpoint.
|
||||
* Since {@link HttpParser} and {@link HttpGenerator} only depend on the {@link EndPoint}
|
||||
* interface, this class overrides all methods of {@link EndPoint} to provide the right
|
||||
* behavior depending on the fact that it has been upgraded or not.
|
||||
*/
|
||||
public static class ProxySelectChannelEndPoint extends SslSelectChannelEndPoint
|
||||
{
|
||||
private final SelectChannelEndPoint plainEndPoint;
|
||||
private volatile boolean upgraded = false;
|
||||
|
||||
public ProxySelectChannelEndPoint(SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, Buffers sslBuffers, SSLEngine engine) throws IOException
|
||||
{
|
||||
super(sslBuffers, channel, selectSet, key, engine);
|
||||
this.plainEndPoint = new SelectChannelEndPoint(channel, selectSet, key);
|
||||
}
|
||||
|
||||
public void upgrade()
|
||||
{
|
||||
upgraded = true;
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.shutdownOutput();
|
||||
else
|
||||
plainEndPoint.shutdownOutput();
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.close();
|
||||
else
|
||||
plainEndPoint.close();
|
||||
}
|
||||
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.fill(buffer);
|
||||
else
|
||||
return plainEndPoint.fill(buffer);
|
||||
}
|
||||
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.flush(buffer);
|
||||
else
|
||||
return plainEndPoint.flush(buffer);
|
||||
}
|
||||
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.flush(header, buffer, trailer);
|
||||
else
|
||||
return plainEndPoint.flush(header, buffer, trailer);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalAddr();
|
||||
else
|
||||
return plainEndPoint.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalHost();
|
||||
else
|
||||
return plainEndPoint.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalPort();
|
||||
else
|
||||
return plainEndPoint.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemoteAddr();
|
||||
else
|
||||
return plainEndPoint.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemoteHost();
|
||||
else
|
||||
return plainEndPoint.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemotePort();
|
||||
else
|
||||
return plainEndPoint.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBlocking();
|
||||
else
|
||||
return plainEndPoint.isBlocking();
|
||||
}
|
||||
|
||||
public boolean isBufferred()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferred();
|
||||
else
|
||||
return plainEndPoint.isBufferred();
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.blockReadable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockReadable(millisecs);
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.blockWritable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isOpen();
|
||||
else
|
||||
return plainEndPoint.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getTransport();
|
||||
else
|
||||
return plainEndPoint.getTransport();
|
||||
}
|
||||
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferingInput();
|
||||
else
|
||||
return plainEndPoint.isBufferingInput();
|
||||
}
|
||||
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferingOutput();
|
||||
else
|
||||
return plainEndPoint.isBufferingOutput();
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.flush();
|
||||
else
|
||||
plainEndPoint.flush();
|
||||
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getMaxIdleTime();
|
||||
else
|
||||
return plainEndPoint.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.setMaxIdleTime(timeMs);
|
||||
else
|
||||
plainEndPoint.setMaxIdleTime(timeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ProxyHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlets.ProxyServlet;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ProxyTunnellingTest
|
||||
{
|
||||
private Server server;
|
||||
private Connector serverConnector;
|
||||
private Server proxy;
|
||||
private Connector proxyConnector;
|
||||
|
||||
private void startSSLServer(Handler handler) throws Exception
|
||||
{
|
||||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
String keyStorePath = System.getProperty("basedir");
|
||||
assertNotNull(keyStorePath);
|
||||
keyStorePath += File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "keystore";
|
||||
connector.setKeystore(keyStorePath);
|
||||
connector.setPassword("storepwd");
|
||||
connector.setKeyPassword("keypwd");
|
||||
startServer(connector, handler);
|
||||
}
|
||||
|
||||
private void startServer(Connector connector, Handler handler) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
serverConnector = connector;
|
||||
server.addConnector(serverConnector);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
}
|
||||
|
||||
private void startProxy() throws Exception
|
||||
{
|
||||
proxy = new Server();
|
||||
proxyConnector = new SelectChannelConnector();
|
||||
proxy.addConnector(proxyConnector);
|
||||
ProxyHandler proxyHandler = new ProxyHandler();
|
||||
proxy.setHandler(proxyHandler);
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
proxyHandler.setHandler(handlers);
|
||||
ServletContextHandler context = new ServletContextHandler(handlers, "/", ServletContextHandler.SESSIONS);
|
||||
ServletHolder proxyServlet = new ServletHolder(ProxyServlet.class);
|
||||
context.addServlet(proxyServlet, "/*");
|
||||
proxy.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stop() throws Exception
|
||||
{
|
||||
stopProxy();
|
||||
stopServer();
|
||||
}
|
||||
|
||||
private void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
private void stopProxy() throws Exception
|
||||
{
|
||||
proxy.stop();
|
||||
proxy.join();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoSSL() throws Exception
|
||||
{
|
||||
startServer(new SelectChannelConnector(), new ServerHandler());
|
||||
startProxy();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setProxy(new Address("localhost", proxyConnector.getLocalPort()));
|
||||
httpClient.start();
|
||||
|
||||
try
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
String body = "BODY";
|
||||
exchange.setURL("http://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8"));
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(body, content);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneMessageSSL() throws Exception
|
||||
{
|
||||
startSSLServer(new ServerHandler());
|
||||
startProxy();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setProxy(new Address("localhost", proxyConnector.getLocalPort()));
|
||||
httpClient.start();
|
||||
|
||||
try
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8"));
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(body, content);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoMessagesSSL() throws Exception
|
||||
{
|
||||
startSSLServer(new ServerHandler());
|
||||
startProxy();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setProxy(new Address("localhost", proxyConnector.getLocalPort()));
|
||||
httpClient.start();
|
||||
|
||||
try
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8"));
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(body, content);
|
||||
|
||||
exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.POST);
|
||||
exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo");
|
||||
exchange.setRequestHeader(HttpHeaders.CONTENT_TYPE, MimeTypes.FORM_ENCODED);
|
||||
content = "body=" + body;
|
||||
exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(content.length()));
|
||||
exchange.setRequestContent(new ByteArrayBuffer(content, "UTF-8"));
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
content = exchange.getResponseContent();
|
||||
assertEquals(body, content);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyDown() throws Exception
|
||||
{
|
||||
startSSLServer(new ServerHandler());
|
||||
startProxy();
|
||||
int proxyPort = proxyConnector.getLocalPort();
|
||||
stopProxy();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setProxy(new Address("localhost", proxyPort));
|
||||
httpClient.start();
|
||||
|
||||
try
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ContentExchange exchange = new ContentExchange(true)
|
||||
{
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8"));
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerDown() throws Exception
|
||||
{
|
||||
startSSLServer(new ServerHandler());
|
||||
int serverPort = serverConnector.getLocalPort();
|
||||
stopServer();
|
||||
startProxy();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setProxy(new Address("localhost", proxyConnector.getLocalPort()));
|
||||
httpClient.start();
|
||||
|
||||
try
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ContentExchange exchange = new ContentExchange(true)
|
||||
{
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
exchange.setURL("https://localhost:" + serverPort + "/echo?body=" + URLEncoder.encode(body, "UTF-8"));
|
||||
|
||||
httpClient.send(exchange);
|
||||
assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
String body = httpRequest.getParameter("body");
|
||||
ServletOutputStream output = httpResponse.getOutputStream();
|
||||
output.print(body);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ServletException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue