Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
This commit is contained in:
commit
fdc131db89
|
@ -23,8 +23,8 @@ import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -206,7 +206,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
InetSocketAddress local = endPoint.getLocalAddress();
|
InetSocketAddress local = endPoint.getLocalAddress();
|
||||||
InetSocketAddress remote = endPoint.getRemoteAddress();
|
InetSocketAddress remote = endPoint.getRemoteAddress();
|
||||||
boolean ipv4 = local.getAddress() instanceof Inet4Address;
|
boolean ipv4 = local.getAddress() instanceof Inet4Address;
|
||||||
tag = new Tag(Tag.Command.PROXY, ipv4 ? Tag.Family.INET4 : Tag.Family.INET6, Tag.Protocol.STREAM, local.getAddress().getHostAddress(), local.getPort(), remote.getAddress().getHostAddress(), remote.getPort());
|
tag = new Tag(Tag.Command.PROXY, ipv4 ? Tag.Family.INET4 : Tag.Family.INET6, Tag.Protocol.STREAM, local.getAddress().getHostAddress(), local.getPort(), remote.getAddress().getHostAddress(), remote.getPort(), null);
|
||||||
}
|
}
|
||||||
return new ProxyProtocolConnectionV2(endPoint, executor, getClientConnectionFactory(), context, tag);
|
return new ProxyProtocolConnectionV2(endPoint, executor, getClientConnectionFactory(), context, tag);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
/**
|
/**
|
||||||
* The PROXY V2 Tag typically used to "ping" the server.
|
* The PROXY V2 Tag typically used to "ping" the server.
|
||||||
*/
|
*/
|
||||||
public static final Tag LOCAL = new Tag(Command.LOCAL, Family.UNSPEC, Protocol.UNSPEC, null, 0, null, 0);
|
public static final Tag LOCAL = new Tag(Command.LOCAL, Family.UNSPEC, Protocol.UNSPEC, null, 0, null, 0, null);
|
||||||
|
|
||||||
private Command command;
|
private Command command;
|
||||||
private Family family;
|
private Family family;
|
||||||
|
@ -232,7 +232,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
private int srcPort;
|
private int srcPort;
|
||||||
private String dstIP;
|
private String dstIP;
|
||||||
private int dstPort;
|
private int dstPort;
|
||||||
private Map<Integer, byte[]> vectors;
|
private List<TLV> tlvs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a Tag whose metadata will be derived from the underlying EndPoint.</p>
|
* <p>Creates a Tag whose metadata will be derived from the underlying EndPoint.</p>
|
||||||
|
@ -251,7 +251,20 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
*/
|
*/
|
||||||
public Tag(String srcIP, int srcPort)
|
public Tag(String srcIP, int srcPort)
|
||||||
{
|
{
|
||||||
this(Command.PROXY, null, Protocol.STREAM, srcIP, srcPort, null, 0);
|
this(Command.PROXY, null, Protocol.STREAM, srcIP, srcPort, null, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a Tag with the given source metadata and Type-Length-Value (TLV) objects.</p>
|
||||||
|
* <p>The destination metadata will be derived from the underlying EndPoint.</p>
|
||||||
|
*
|
||||||
|
* @param srcIP the source IP address
|
||||||
|
* @param srcPort the source port
|
||||||
|
* @param tlvs the TLV objects
|
||||||
|
*/
|
||||||
|
public Tag(String srcIP, int srcPort, List<TLV> tlvs)
|
||||||
|
{
|
||||||
|
this(Command.PROXY, null, Protocol.STREAM, srcIP, srcPort, null, 0, tlvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,8 +277,9 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
* @param srcPort the source port
|
* @param srcPort the source port
|
||||||
* @param dstIP the destination IP address
|
* @param dstIP the destination IP address
|
||||||
* @param dstPort the destination port
|
* @param dstPort the destination port
|
||||||
|
* @param tlvs the TLV objects
|
||||||
*/
|
*/
|
||||||
public Tag(Command command, Family family, Protocol protocol, String srcIP, int srcPort, String dstIP, int dstPort)
|
public Tag(Command command, Family family, Protocol protocol, String srcIP, int srcPort, String dstIP, int dstPort, List<TLV> tlvs)
|
||||||
{
|
{
|
||||||
this.command = command;
|
this.command = command;
|
||||||
this.family = family;
|
this.family = family;
|
||||||
|
@ -274,17 +288,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
this.srcPort = srcPort;
|
this.srcPort = srcPort;
|
||||||
this.dstIP = dstIP;
|
this.dstIP = dstIP;
|
||||||
this.dstPort = dstPort;
|
this.dstPort = dstPort;
|
||||||
}
|
this.tlvs = tlvs;
|
||||||
|
|
||||||
public void put(int type, byte[] data)
|
|
||||||
{
|
|
||||||
if (type < 0 || type > 255)
|
|
||||||
throw new IllegalArgumentException("Invalid type: " + type);
|
|
||||||
if (data != null && data.length > 65535)
|
|
||||||
throw new IllegalArgumentException("Invalid data length: " + data.length);
|
|
||||||
if (vectors == null)
|
|
||||||
vectors = new HashMap<>();
|
|
||||||
vectors.put(type, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command getCommand()
|
public Command getCommand()
|
||||||
|
@ -322,9 +326,9 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
return dstPort;
|
return dstPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, byte[]> getVectors()
|
public List<TLV> getTLVs()
|
||||||
{
|
{
|
||||||
return vectors != null ? vectors : Collections.emptyMap();
|
return tlvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -347,13 +351,14 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
Objects.equals(srcIP, that.srcIP) &&
|
Objects.equals(srcIP, that.srcIP) &&
|
||||||
srcPort == that.srcPort &&
|
srcPort == that.srcPort &&
|
||||||
Objects.equals(dstIP, that.dstIP) &&
|
Objects.equals(dstIP, that.dstIP) &&
|
||||||
dstPort == that.dstPort;
|
dstPort == that.dstPort &&
|
||||||
|
Objects.equals(tlvs, that.tlvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
return Objects.hash(command, family, protocol, srcIP, srcPort, dstIP, dstPort);
|
return Objects.hash(command, family, protocol, srcIP, srcPort, dstIP, dstPort, tlvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Command
|
public enum Command
|
||||||
|
@ -370,6 +375,51 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
{
|
{
|
||||||
UNSPEC, STREAM, DGRAM
|
UNSPEC, STREAM, DGRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TLV
|
||||||
|
{
|
||||||
|
private final int type;
|
||||||
|
private final byte[] value;
|
||||||
|
|
||||||
|
public TLV(int type, byte[] value)
|
||||||
|
{
|
||||||
|
if (type < 0 || type > 255)
|
||||||
|
throw new IllegalArgumentException("Invalid type: " + type);
|
||||||
|
if (value != null && value.length > 65535)
|
||||||
|
throw new IllegalArgumentException("Invalid value length: " + value.length);
|
||||||
|
this.type = type;
|
||||||
|
this.value = Objects.requireNonNull(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
TLV that = (TLV)obj;
|
||||||
|
return type == that.type && Arrays.equals(value, that.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
int result = Objects.hash(type);
|
||||||
|
result = 31 * result + Arrays.hashCode(value);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,9 +583,9 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
capacity += 1; // family and protocol
|
capacity += 1; // family and protocol
|
||||||
capacity += 2; // length
|
capacity += 2; // length
|
||||||
capacity += 216; // max address length
|
capacity += 216; // max address length
|
||||||
Map<Integer, byte[]> vectors = tag.getVectors();
|
List<V2.Tag.TLV> tlvs = tag.getTLVs();
|
||||||
int vectorsLength = vectors.values().stream()
|
int vectorsLength = tlvs == null ? 0 : tlvs.stream()
|
||||||
.mapToInt(data -> 1 + 2 + data.length)
|
.mapToInt(tlv -> 1 + 2 + tlv.getValue().length)
|
||||||
.sum();
|
.sum();
|
||||||
capacity += vectorsLength;
|
capacity += vectorsLength;
|
||||||
ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
|
ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
|
||||||
|
@ -602,13 +652,16 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
for (Map.Entry<Integer, byte[]> entry : vectors.entrySet())
|
if (tlvs != null)
|
||||||
{
|
{
|
||||||
buffer.put(entry.getKey().byteValue());
|
for (V2.Tag.TLV tlv : tlvs)
|
||||||
byte[] data = entry.getValue();
|
{
|
||||||
|
buffer.put((byte)tlv.getType());
|
||||||
|
byte[] data = tlv.getValue();
|
||||||
buffer.putShort((short)data.length);
|
buffer.putShort((short)data.length);
|
||||||
buffer.put(data);
|
buffer.put(data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
endPoint.write(callback, buffer);
|
endPoint.write(callback, buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -174,6 +175,7 @@ public class HttpClientProxyProtocolTest
|
||||||
EndPoint endPoint = jettyRequest.getHttpChannel().getEndPoint();
|
EndPoint endPoint = jettyRequest.getHttpChannel().getEndPoint();
|
||||||
assertTrue(endPoint instanceof ProxyConnectionFactory.ProxyEndPoint);
|
assertTrue(endPoint instanceof ProxyConnectionFactory.ProxyEndPoint);
|
||||||
ProxyConnectionFactory.ProxyEndPoint proxyEndPoint = (ProxyConnectionFactory.ProxyEndPoint)endPoint;
|
ProxyConnectionFactory.ProxyEndPoint proxyEndPoint = (ProxyConnectionFactory.ProxyEndPoint)endPoint;
|
||||||
|
if (target.equals("/tls_version"))
|
||||||
assertEquals(tlsVersion, proxyEndPoint.getAttribute(ProxyConnectionFactory.TLS_VERSION));
|
assertEquals(tlsVersion, proxyEndPoint.getAttribute(ProxyConnectionFactory.TLS_VERSION));
|
||||||
response.setContentType(MimeTypes.Type.TEXT_PLAIN.asString());
|
response.setContentType(MimeTypes.Type.TEXT_PLAIN.asString());
|
||||||
response.getOutputStream().print(request.getRemotePort());
|
response.getOutputStream().print(request.getRemotePort());
|
||||||
|
@ -184,7 +186,6 @@ public class HttpClientProxyProtocolTest
|
||||||
int serverPort = connector.getLocalPort();
|
int serverPort = connector.getLocalPort();
|
||||||
|
|
||||||
int clientPort = ThreadLocalRandom.current().nextInt(1024, 65536);
|
int clientPort = ThreadLocalRandom.current().nextInt(1024, 65536);
|
||||||
V2.Tag tag = new V2.Tag("127.0.0.1", clientPort);
|
|
||||||
int typeTLS = 0x20;
|
int typeTLS = 0x20;
|
||||||
byte[] dataTLS = new byte[1 + 4 + (1 + 2 + tlsVersionBytes.length)];
|
byte[] dataTLS = new byte[1 + 4 + (1 + 2 + tlsVersionBytes.length)];
|
||||||
dataTLS[0] = 0x01; // CLIENT_SSL
|
dataTLS[0] = 0x01; // CLIENT_SSL
|
||||||
|
@ -192,13 +193,27 @@ public class HttpClientProxyProtocolTest
|
||||||
dataTLS[6] = 0x00; // Length, hi byte
|
dataTLS[6] = 0x00; // Length, hi byte
|
||||||
dataTLS[7] = (byte)tlsVersionBytes.length; // Length, lo byte
|
dataTLS[7] = (byte)tlsVersionBytes.length; // Length, lo byte
|
||||||
System.arraycopy(tlsVersionBytes, 0, dataTLS, 8, tlsVersionBytes.length);
|
System.arraycopy(tlsVersionBytes, 0, dataTLS, 8, tlsVersionBytes.length);
|
||||||
tag.put(typeTLS, dataTLS);
|
V2.Tag.TLV tlv = new V2.Tag.TLV(typeTLS, dataTLS);
|
||||||
|
V2.Tag tag = new V2.Tag("127.0.0.1", clientPort, Collections.singletonList(tlv));
|
||||||
|
|
||||||
ContentResponse response = client.newRequest("localhost", serverPort)
|
ContentResponse response = client.newRequest("localhost", serverPort)
|
||||||
|
.path("/tls_version")
|
||||||
.tag(tag)
|
.tag(tag)
|
||||||
.send();
|
.send();
|
||||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
assertEquals(String.valueOf(clientPort), response.getContentAsString());
|
assertEquals(String.valueOf(clientPort), response.getContentAsString());
|
||||||
|
|
||||||
|
// Make another request with the same address information, but different TLV.
|
||||||
|
V2.Tag.TLV tlv2 = new V2.Tag.TLV(0x01, "http/1.1".getBytes(StandardCharsets.UTF_8));
|
||||||
|
V2.Tag tag2 = new V2.Tag("127.0.0.1", clientPort, Collections.singletonList(tlv2));
|
||||||
|
response = client.newRequest("localhost", serverPort)
|
||||||
|
.tag(tag2)
|
||||||
|
.send();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
assertEquals(String.valueOf(clientPort), response.getContentAsString());
|
||||||
|
|
||||||
|
// Make sure the two TLVs created two destinations.
|
||||||
|
assertEquals(2, client.getDestinations().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue