Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-WebSocketServlet

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-05-01 15:46:03 +10:00
commit e5cca92199
170 changed files with 4865 additions and 3791 deletions

View File

@ -74,9 +74,8 @@ public class ConscryptHTTP2ClientTest
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(15, TimeUnit.SECONDS);
HttpFields requestFields = new HttpFields();
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
HttpFields requestFields = HttpFields.build().put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
MetaData.Request metaData = new MetaData.Request("GET", HttpURI.from("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()

View File

@ -63,9 +63,9 @@ public class JDK9HTTP2ClientTest
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(15, TimeUnit.SECONDS);
HttpFields requestFields = new HttpFields();
HttpFields.Mutable requestFields = HttpFields.build();
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
MetaData.Request metaData = new MetaData.Request("GET", HttpURI.from("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()

View File

@ -256,7 +256,7 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
{
HttpField field = oldRequest.getHeaders().getField(header);
if (field != null && !newRequest.getHeaders().contains(header))
newRequest.getHeaders().put(field);
newRequest.put(field);
}
private void forwardSuccessComplete(HttpRequest request, Response response)

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.BytesRequestContent;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion;
@ -151,8 +152,8 @@ public abstract class HttpConnection implements IConnection
HttpFields headers = request.getHeaders();
if (version.getVersion() <= 11)
{
if (!headers.containsKey(HttpHeader.HOST.asString()))
headers.put(getHttpDestination().getHostField());
if (!headers.contains(HttpHeader.HOST))
request.put(getHttpDestination().getHostField());
}
// Add content headers
@ -163,25 +164,25 @@ public abstract class HttpConnection implements IConnection
}
else
{
if (!headers.containsKey(HttpHeader.CONTENT_TYPE.asString()))
if (!headers.contains(HttpHeader.CONTENT_TYPE))
{
String contentType = content.getContentType();
if (contentType != null)
{
headers.put(HttpHeader.CONTENT_TYPE, contentType);
request.put(new HttpField(HttpHeader.CONTENT_TYPE, contentType));
}
else
{
contentType = getHttpClient().getDefaultRequestContentType();
if (contentType != null)
headers.put(HttpHeader.CONTENT_TYPE, contentType);
request.put(new HttpField(HttpHeader.CONTENT_TYPE, contentType));
}
}
long contentLength = content.getLength();
if (contentLength >= 0)
{
if (!headers.containsKey(HttpHeader.CONTENT_LENGTH.asString()))
headers.put(HttpHeader.CONTENT_LENGTH, String.valueOf(contentLength));
if (!headers.contains(HttpHeader.CONTENT_LENGTH))
request.put(new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH, contentLength));
}
}
@ -194,7 +195,7 @@ public abstract class HttpConnection implements IConnection
cookies = convertCookies(HttpCookieStore.matchPath(uri, cookieStore.get(uri)), null);
cookies = convertCookies(request.getCookies(), cookies);
if (cookies != null)
request.header(HttpHeader.COOKIE.asString(), cookies.toString());
request.header(HttpHeader.COOKIE, cookies.toString());
}
// Authentication

View File

@ -242,7 +242,7 @@ public abstract class HttpReceiver
boolean process = notifier.notifyHeader(exchange.getConversation().getResponseListeners(), response, field);
if (process)
{
response.getHeaders().add(field);
response.getHeaderFieldsMutable().add(field);
HttpHeader fieldHeader = field.getHeader();
if (fieldHeader != null)
{

View File

@ -64,18 +64,18 @@ public class HttpRequest implements Request
{
private static final URI NULL_URI = URI.create("null:0");
private final HttpFields headers = new HttpFields();
private final HttpFields.Mutable headers = HttpFields.build();
private final Fields params = new Fields(true);
private final List<Response.ResponseListener> responseListeners = new ArrayList<>();
private final AtomicReference<Throwable> aborted = new AtomicReference<>();
private final HttpClient client;
private final HttpConversation conversation;
private final String host;
private final int port;
private URI uri;
private String scheme;
private String host;
private int port;
private String path;
private String query;
private URI uri;
private String method = HttpMethod.GET.asString();
private HttpVersion version = HttpVersion.HTTP_1_1;
private boolean versionExplicit;
@ -138,12 +138,28 @@ public class HttpRequest implements Request
return host;
}
@Override
public Request host(String host)
{
this.host = host;
this.uri = null;
return this;
}
@Override
public int getPort()
{
return port;
}
@Override
public Request port(int port)
{
this.port = port;
this.uri = null;
return this;
}
@Override
public String getMethod()
{
@ -289,6 +305,34 @@ public class HttpRequest implements Request
return this;
}
@Override
public Request set(HttpFields fields)
{
headers.clear().add(fields);
return this;
}
@Override
public Request remove(HttpHeader header)
{
headers.remove(header);
return this;
}
@Override
public Request put(HttpField field)
{
headers.put(field);
return this;
}
@Override
public Request add(HttpField field)
{
headers.add(field);
return this;
}
@Override
public Request header(String name, String value)
{
@ -353,7 +397,7 @@ public class HttpRequest implements Request
}
@Override
public HttpFields getHeaders()
public HttpFields.Mutable getHeaders()
{
return headers;
}

View File

@ -29,13 +29,13 @@ import org.eclipse.jetty.http.HttpVersion;
public class HttpResponse implements Response
{
private final HttpFields headers = new HttpFields();
private final HttpFields.Mutable headers = HttpFields.build();
private final Request request;
private final List<ResponseListener> listeners;
private HttpVersion version;
private int status;
private String reason;
private HttpFields trailers;
private HttpFields.Mutable trailers;
public HttpResponse(Request request, List<ResponseListener> listeners)
{
@ -87,6 +87,11 @@ public class HttpResponse implements Response
@Override
public HttpFields getHeaders()
{
return headers.asImmutable();
}
public HttpFields.Mutable getHeaderFieldsMutable()
{
return headers;
}
@ -111,7 +116,7 @@ public class HttpResponse implements Response
public HttpResponse trailer(HttpField trailer)
{
if (trailers == null)
trailers = new HttpFields();
trailers = HttpFields.build();
trailers.add(trailer);
return this;
}

View File

@ -34,6 +34,7 @@ import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
@ -53,26 +54,39 @@ import org.eclipse.jetty.util.Fields;
public interface Request
{
/**
* @return the scheme of this request, such as "http" or "https"
* @return the URI scheme of this request, such as "http" or "https"
*/
String getScheme();
/**
* @param scheme the scheme of this request, such as "http" or "https"
* @param scheme the URI scheme of this request, such as "http" or "https"
* @return this request object
*/
Request scheme(String scheme);
/**
* @return the host of this request, such as "127.0.0.1" or "google.com"
* @return the URI host of this request, such as "127.0.0.1" or "google.com"
*/
String getHost();
/**
* @return the port of this request such as 80 or 443
* @param host the URI host of this request, such as "127.0.0.1" or "google.com"
* @return this request object
*/
Request host(String host);
/**
* @return the URI port of this request such as 80 or 443
*/
int getPort();
/**
*
* @param port the URI port of this request such as 80 or 443
* @return this request object
*/
Request port(int port);
/**
* @return the method of this request, such as GET or POST, as a String
*/
@ -91,26 +105,26 @@ public interface Request
Request method(String method);
/**
* @return the path of this request, such as "/" or "/path" - without the query
* @return the URI path of this request, such as "/" or "/path" - without the query
* @see #getQuery()
*/
String getPath();
/**
* Specifies the path - and possibly the query - of this request.
* Specifies the URI path - and possibly the query - of this request.
* If the query part is specified, parameter values must be properly
* {@link URLEncoder#encode(String, String) UTF-8 URL encoded}.
* For example, if the value for parameter "currency" is the euro symbol &euro; then the
* query string for this parameter must be "currency=%E2%82%AC".
* For transparent encoding of parameter values, use {@link #param(String, String)}.
*
* @param path the path of this request, such as "/" or "/path?param=1"
* @param path the URI path of this request, such as "/" or "/path?param=1"
* @return this request object
*/
Request path(String path);
/**
* @return the query string of this request such as "param=1"
* @return the URI query string of this request such as "param=1"
* @see #getPath()
* @see #getParams()
*/
@ -133,12 +147,12 @@ public interface Request
Request version(HttpVersion version);
/**
* @return the query parameters of this request
* @return the URI query parameters of this request
*/
Fields getParams();
/**
* Adds a query parameter with the given name and value.
* Adds a URI query parameter with the given name and value.
* The value is {@link URLEncoder#encode(String, String) UTF-8 URL encoded}.
*
* @param name the name of the query parameter
@ -152,6 +166,32 @@ public interface Request
*/
HttpFields getHeaders();
/** Set the headers, clearing any existing headers
* @param fields The fields to set
* @return this request object
*/
Request set(HttpFields fields);
/**
* @param header the header to remove
* @return this request object
*/
Request remove(HttpHeader header);
/**
* @param field the field to add
* @return this request object
* @see #header(HttpHeader, String)
*/
Request add(HttpField field);
/**
* @param field the field to put
* @return this request object
* @see #header(HttpHeader, String)
*/
Request put(HttpField field);
/**
* @param name the name of the header
* @param value the value of the header

View File

@ -78,8 +78,7 @@ public class HttpSenderOverHTTP extends HttpSender
String query = request.getQuery();
if (query != null)
path += "?" + query;
metaData = new MetaData.Request(request.getMethod(), new HttpURI(path), request.getVersion(), request.getHeaders(), contentLength);
metaData.setTrailerSupplier(request.getTrailers());
metaData = new MetaData.Request(request.getMethod(), HttpURI.from(path), request.getVersion(), request.getHeaders(), contentLength, request.getTrailers());
if (LOG.isDebugEnabled())
LOG.debug("Sending headers with content {} last={} for {}", BufferUtil.toDetailString(contentBuffer), lastContent, exchange.getRequest());
headersCallback.iterate();

View File

@ -75,7 +75,7 @@ public abstract class BufferingResponseListener extends Listener.Adapter
Request request = response.getRequest();
HttpFields headers = response.getHeaders();
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH);
if (HttpMethod.HEAD.is(request.getMethod()))
length = 0;
if (length > maxLength)

View File

@ -250,7 +250,10 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next();
assertFalse(connection.getEndPoint().isOutputShutdown());
})
.onResponseHeaders(r -> r.getHeaders().remove(HttpHeader.CONNECTION));
.onResponseHeaders(r ->
{
((HttpResponse)r).getHeaderFieldsMutable().remove(HttpHeader.CONNECTION);
});
ContentResponse response = request.send();
assertEquals(HttpStatus.OK_200, response.getStatus());

View File

@ -70,7 +70,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -86,7 +86,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -102,7 +102,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -119,7 +119,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -139,7 +139,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
Response response = xx.getResponse();
assertNotNull(response);
assertEquals(301, response.getStatus());
assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertTrue(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -158,7 +158,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
assertArrayEquals(data, response.getContent());
}
@ -179,7 +179,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
Response response = xx.getResponse();
assertNotNull(response);
assertEquals(302, response.getStatus());
assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertTrue(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -195,7 +195,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -212,7 +212,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(303, response.getStatus());
assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertTrue(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -228,7 +228,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -244,7 +244,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest
@ -260,7 +260,7 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
.send();
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString()));
assertFalse(response.getHeaders().contains(HttpHeader.LOCATION));
}
@ParameterizedTest

View File

@ -771,7 +771,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
assertNotNull(response);
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey(headerName));
assertFalse(response.getHeaders().contains(headerName));
}
@ParameterizedTest

View File

@ -131,6 +131,26 @@ public class HttpClientURITest extends AbstractHttpClientServerTest
}
}
@ParameterizedTest
@ArgumentsSource(ScenarioProvider.class)
public void testHostPort(Scenario scenario) throws Exception
{
start(scenario, new EmptyServerHandler());
Request request = client.newRequest("domain.com", 80)
.scheme(scenario.getScheme())
.host("localhost")
.port(connector.getLocalPort())
.timeout(1, TimeUnit.SECONDS);
assertEquals("localhost", request.getHost());
assertEquals(connector.getLocalPort(), request.getPort());
ContentResponse response = request.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
}
@ParameterizedTest
@ArgumentsSource(ScenarioProvider.class)
public void testPath(Scenario scenario) throws Exception

View File

@ -144,7 +144,7 @@ public class MultiPartContentTest extends AbstractHttpClientServerTest
});
MultiPartRequestContent multiPart = new MultiPartRequestContent();
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put(HttpHeader.CONTENT_TYPE, "text/plain;charset=" + encoding.name());
BytesRequestContent content = new BytesRequestContent(value.getBytes(encoding));
multiPart.addFieldPart(name, content, fields);
@ -240,7 +240,7 @@ public class MultiPartContentTest extends AbstractHttpClientServerTest
closeLatch.countDown();
}
});
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put(HttpHeader.CONTENT_TYPE, contentType);
multiPart.addFilePart(name, fileName, content, fields);
multiPart.close();
@ -354,7 +354,7 @@ public class MultiPartContentTest extends AbstractHttpClientServerTest
});
MultiPartRequestContent multiPart = new MultiPartRequestContent();
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put(headerName, headerValue);
multiPart.addFieldPart(field, new StringRequestContent(value, encoding), fields);
multiPart.addFilePart(fileField, tmpPath.getFileName().toString(), new PathRequestContent(tmpPath), null);

View File

@ -211,12 +211,10 @@ If you are using the Jetty distribution, and you want to change the JSP settings
[source, xml, subs="{sub-order}"]
----
<Configure class=>"org.eclipse.jetty.webapp.WebAppContext">
<Set name=>"contextPath">/foo</Set>
<Set name=>"war"><SystemProperty name=>"jetty.home" >default=>"."/>/webapps/foobar.war</Set>
<Set name=>"defaultsDescriptor">/home/smith/dev/webdefault.xml</Set>
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/foo</Set>
<Set name="war"><Property name="jetty.home" default="."/>/webapps/foobar.war</Set>
<Set name="defaultsDescriptor">/home/smith/dev/webdefault.xml</Set>
</Configure>
----
@ -329,7 +327,6 @@ For example:
<webApp>
<contextPath>/${artifactId}</contextPath>
</webApp>
<scanIntervalSeconds>5</scanIntervalSeconds>
</configuration>
<dependencies>
<dependency>

View File

@ -362,6 +362,9 @@ When a request arrives to `ServletContextHandler` the request URI will be matche
IMPORTANT: `ServletContextHandler` is a terminal `Handler`, that is it always calls `Request.setHandled(true)` when invoked.
Server applications must be careful when creating the `Handler` tree to put ``ServletContextHandler``s as last ``Handler``s in a `HandlerList` or as children of `ContextHandlerCollection`.
// TODO: revise what above, as ServletContextHandler is not a terminal handler.
// TODO: introduce the fact that ServletContextHandler can have a class loader that may be used to "isolate" web application classes.
[[eg-server-http-handler-use-webapp-context]]
===== WebAppContext
@ -369,16 +372,42 @@ Server applications must be careful when creating the `Handler` tree to put ``Se
Server applications can specify a `+*.war+` file or a directory with the structure of a `+*.war+` file to `WebAppContext` to deploy a standard Servlet web application packaged as a `war` (as defined by the Servlet specification).
Where server applications using `ServletContextHandler` must manually invoke methods to add ``Servlet``s and ``Filter``s, `WebAppContext` reads `WEB-INF/web.xml` to add ``Servlet``s and ``Filter``s.
Where server applications using `ServletContextHandler` must manually invoke methods to add ``Servlet``s and ``Filter``s, `WebAppContext` reads `WEB-INF/web.xml` to add ``Servlet``s and ``Filter``s, and also enforces a number of restrictions defined by the Servlet specification, in particular related to class loading.
[source,java,indent=0]
----
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=webAppContextHandler]
----
[[eg-server-http-handler-use-webapp-context-class-loading]]
====== WebAppContext Class Loading
The Servlet specification requires that a web application class loader must load the web application classes from `WEB-INF/classes` and `WEB_INF/lib`.
The web application class loader is special because it behaves differently from typical class loaders: where typical class loaders first delegate to their parent class loader and then try to find the class locally, the web application class loader first tries to find the class locally and then delegates to the parent class loader.
The typical class loading model, parent-first, is _inverted_ for web application class loaders, as they use a child-first model.
Furthermore, the Servlet specification requires that web applications cannot load or otherwise access the Servlet container implementation classes, also called _server classes_.
In the Jetty case, the Servlet specification class `javax.servlet.http.HttpServletRequest` is implemented by `org.eclipse.jetty.server.Request`.
Web applications cannot downcast Servlet's `HttpServletRequest` to Jetty's `Request` to access Jetty specific features -- this ensures maximum web application portability across Servlet container implementations.
Lastly, the Servlet specification requires that other classes, also called _system classes_, such as `javax.servlet.http.HttpServletRequest` or JDK classes such as `java.lang.String` or `java.sql.Connection` cannot be modified by web applications by putting, for example, modified versions of those classes in `WEB-INF/classes` so that they are loaded first by the web application class loader (instead of the class-path class loader where they are normally loaded from).
`WebAppContext` implements this class loader logic using a single class loader, `org.eclipse.jetty.webapp.WebAppClassLoader`, with filtering capabilities: when it loads a class, it checks whether the class is a _system class_ or a _server class_ and acts according to the Servlet specification.
When `WebAppClassLoader` is asked to load a class, it first tries to find the class locally (since it must use the inverted child-first model); if the class is found, and it is not a _system class_, the class is loaded; otherwise the class is not found locally.
If the class is not found locally, the parent class loader is asked to load the class; the parent class loader uses the standard parent-first model, so it delegates the class loading to its parent, and so on.
If the class is found, and it is not a _server class_, the class is loaded; otherwise the class is not found and a `ClassNotFoundException` is thrown.
Unfortunately, the Servlet specification does not define exactly which classes are _system classes_ and which classes are _server classes_.
However, Jetty picks good defaults and allows server applications to customize _system classes_ and _server classes_ in `WebAppContext`.
// TODO: add a section on parentLoaderPriority.
// TODO: add a code example about how to set system/server classes.
// TODO: add a code example about how to configure extra classpath
// TODO: add a section on ClassLoading (see old docs)
// TODO: add a section on Configuration (system/server classes)
// TODO: add a section about how to setup JSP support
// TODO: add a section on ClassLoading (see old docs)
[[eg-server-http-handler-use-default-servlet]]
===== DefaultServlet -- Static Content for Servlets

View File

@ -48,9 +48,9 @@ public class HTTP2Docs
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter());
Session session = sessionCF.get();
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// tag::dataDemanded[]

View File

@ -147,11 +147,11 @@ public class HTTP2ClientDocs
Session session = sessionCF.get();
// Configure the request headers.
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
// The request metadata with method, URI and headers.
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
// The HTTP/2 HEADERS frame, with endStream=true
// to signal that this request has no content.
@ -172,11 +172,11 @@ public class HTTP2ClientDocs
Session session = sessionCF.get();
// Configure the request headers.
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.CONTENT_TYPE, "application/json");
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.CONTENT_TYPE, "application/json");
// The request metadata with method, URI and headers.
MetaData.Request request = new MetaData.Request("POST", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
MetaData.Request request = new MetaData.Request("POST", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
// The HTTP/2 HEADERS frame, with endStream=false to
// signal that there will be more frames in this stream.
@ -213,9 +213,9 @@ public class HTTP2ClientDocs
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter());
Session session = sessionCF.get();
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// tag::responseListener[]
@ -266,9 +266,9 @@ public class HTTP2ClientDocs
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter());
Session session = sessionCF.get();
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// tag::reset[]
@ -296,9 +296,9 @@ public class HTTP2ClientDocs
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter());
Session session = sessionCF.get();
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// tag::push[]
@ -358,9 +358,9 @@ public class HTTP2ClientDocs
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter());
Session session = sessionCF.get();
HttpFields requestHeaders = new HttpFields();
requestHeaders.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", new HttpURI("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:8080/path"), HttpVersion.HTTP_2, requestHeaders);
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// tag::pushReset[]

View File

@ -464,9 +464,8 @@ public class HTTPServerDocs
{
// Rewrite old paths to new paths.
HttpURI uri = jettyRequest.getHttpURI();
HttpURI newURI = new HttpURI(uri);
String newPath = "/new_path/" + path.substring("/old_path/".length());
newURI.setPath(newPath);
HttpURI newURI = HttpURI.build(uri).path(newPath);
// Modify the request object.
jettyRequest.setHttpURI(newURI);
}

View File

@ -202,7 +202,7 @@ public class HTTP2ServerDocs
// Prepare the response HEADERS frame.
// The response HTTP status and HTTP headers.
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
if (HttpMethod.GET.is(request.getMethod()))
{
@ -294,15 +294,14 @@ public class HTTP2ServerDocs
if (pushEnabled && request.getURIString().endsWith("/index.html"))
{
// Push the favicon.
HttpURI pushedURI = new HttpURI(request.getURI());
pushedURI.setPath("/favicon.ico");
MetaData.Request pushedRequest = new MetaData.Request("GET", pushedURI, HttpVersion.HTTP_2, new HttpFields());
HttpURI pushedURI = HttpURI.build(request.getURI()).path("/favicon.ico");
MetaData.Request pushedRequest = new MetaData.Request("GET", pushedURI, HttpVersion.HTTP_2, HttpFields.EMPTY);
PushPromiseFrame promiseFrame = new PushPromiseFrame(stream.getId(), 0, pushedRequest);
stream.push(promiseFrame, new Stream.Listener.Adapter())
.thenCompose(pushedStream ->
{
// Send the favicon "response".
MetaData.Response pushedResponse = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response pushedResponse = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
return pushedStream.headers(new HeadersFrame(pushedStream.getId(), pushedResponse, null, false))
.thenCompose(pushed -> pushed.data(new DataFrame(pushed.getId(), faviconBuffer, true)));
});

View File

@ -103,7 +103,7 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran
return new HttpConnectionOverFCGI(endPoint, destination, promise);
}
protected void customize(Request request, HttpFields fastCGIHeaders)
protected void customize(Request request, HttpFields.Mutable fastCGIHeaders)
{
fastCGIHeaders.put(FCGI.Headers.DOCUMENT_ROOT, getScriptRoot());
}

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.client.http;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.EnumSet;
import java.util.Locale;
import org.eclipse.jetty.client.HttpChannel;
@ -59,12 +60,8 @@ public class HttpSenderOverFCGI extends HttpSender
{
Request request = exchange.getRequest();
// Copy the request headers to be able to convert them properly
HttpFields headers = new HttpFields();
for (HttpField field : request.getHeaders())
{
headers.put(field);
}
HttpFields fcgiHeaders = new HttpFields();
HttpFields headers = request.getHeaders();
HttpFields.Mutable fcgiHeaders = HttpFields.build();
// FastCGI headers based on the URI
URI uri = request.getURI();
@ -74,12 +71,15 @@ public class HttpSenderOverFCGI extends HttpSender
fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query);
// FastCGI headers based on HTTP headers
HttpField httpField = headers.remove(HttpHeader.AUTHORIZATION);
HttpField httpField = headers.getField(HttpHeader.AUTHORIZATION);
EnumSet<HttpHeader> toRemove = EnumSet.of(HttpHeader.AUTHORIZATION);
if (httpField != null)
fcgiHeaders.put(FCGI.Headers.AUTH_TYPE, httpField.getValue());
httpField = headers.remove(HttpHeader.CONTENT_LENGTH);
httpField = headers.getField(HttpHeader.CONTENT_LENGTH);
toRemove.add(HttpHeader.CONTENT_LENGTH);
fcgiHeaders.put(FCGI.Headers.CONTENT_LENGTH, httpField == null ? "" : httpField.getValue());
httpField = headers.remove(HttpHeader.CONTENT_TYPE);
httpField = headers.getField(HttpHeader.CONTENT_TYPE);
toRemove.add(HttpHeader.CONTENT_TYPE);
fcgiHeaders.put(FCGI.Headers.CONTENT_TYPE, httpField == null ? "" : httpField.getValue());
// FastCGI headers that are not based on HTTP headers nor URI
@ -91,6 +91,8 @@ public class HttpSenderOverFCGI extends HttpSender
// Translate remaining HTTP header into the HTTP_* format
for (HttpField field : headers)
{
if (toRemove.contains(field.getHeader()))
continue;
String name = field.getName();
String fcgiName = "HTTP_" + StringUtil.replace(name, '-', '_').toUpperCase(Locale.ENGLISH);
fcgiHeaders.add(fcgiName, field.getValue());

View File

@ -84,7 +84,7 @@ public class ResponseContentParser extends StreamContentParser
private static class ResponseParser implements HttpParser.ResponseHandler
{
private final HttpFields fields = new HttpFields();
private final HttpFields.Mutable fields = HttpFields.build();
private ClientParser.Listener listener;
private final int request;
private final FCGIHttpParser httpParser;

View File

@ -38,7 +38,7 @@ public class ClientGeneratorTest
@Test
public void testGenerateRequestHeaders() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
// Short name, short value
final String shortShortName = "REQUEST_METHOD";

View File

@ -42,7 +42,7 @@ public class ClientParserTest
public void testParseResponseHeaders() throws Exception
{
final int id = 13;
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
final int statusCode = 200;
final String statusMessage = "OK";
@ -112,8 +112,8 @@ public class ClientParserTest
public void testParseNoResponseContent() throws Exception
{
final int id = 13;
HttpFields fields = new HttpFields();
fields.put("Content-Length", "0");
HttpFields fields = HttpFields.build()
.put("Content-Length", "0");
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool);
@ -157,7 +157,7 @@ public class ClientParserTest
public void testParseSmallResponseContent() throws Exception
{
final int id = 13;
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
ByteBuffer content = ByteBuffer.wrap(new byte[1024]);
final int contentLength = content.remaining();
@ -210,7 +210,7 @@ public class ClientParserTest
public void testParseLargeResponseContent() throws Exception
{
final int id = 13;
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
ByteBuffer content = ByteBuffer.wrap(new byte[128 * 1024]);
final int contentLength = content.remaining();

View File

@ -43,7 +43,7 @@ public class HttpChannelOverFCGI extends HttpChannel
{
private static final Logger LOG = LoggerFactory.getLogger(HttpChannelOverFCGI.class);
private final HttpFields fields = new HttpFields();
private final HttpFields.Mutable fields = HttpFields.build();
private final Dispatcher dispatcher;
private String method;
private String path;

View File

@ -180,7 +180,7 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
proxyRequest.attribute(REQUEST_QUERY_ATTRIBUTE, originalQuery);
// If the Host header is missing, add it.
if (!proxyRequest.getHeaders().containsKey(HttpHeader.HOST.asString()))
if (!proxyRequest.getHeaders().contains(HttpHeader.HOST))
{
String host = request.getServerName();
int port = request.getServerPort();
@ -209,7 +209,7 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
super.sendProxyRequest(request, proxyResponse, proxyRequest);
}
protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders)
protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields.Mutable fastCGIHeaders)
{
for (String envName : fcgiEnvNames)
{
@ -271,7 +271,7 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
}
@Override
protected void customize(Request request, HttpFields fastCGIHeaders)
protected void customize(Request request, HttpFields.Mutable fastCGIHeaders)
{
super.customize(request, fastCGIHeaders);
customizeFastCGIHeaders(request, fastCGIHeaders);

View File

@ -59,18 +59,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-util-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>

View File

@ -58,6 +58,12 @@ public class HostPortHttpField extends HttpField
_hostPort = hostport;
}
public HostPortHttpField(HttpHeader header, String headerString, HostPort hostport)
{
super(header, headerString, hostport.toString());
_hostPort = hostport;
}
/**
* Get the host.
*

View File

@ -18,8 +18,11 @@
package org.eclipse.jetty.http;
import java.util.Map;
import java.util.Objects;
import java.util.StringTokenizer;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
/**
@ -59,43 +62,76 @@ public class HttpField
this(HttpHeader.CACHE.get(name), name, value);
}
public HttpHeader getHeader()
/**
* Get field value parameters. Some field values can have parameters. This method separates the
* value from the parameters and optionally populates a map with the parameters. For example:
*
* <PRE>
*
* FieldName : Value ; param1=val1 ; param2=val2
*
* </PRE>
*
* @param value The Field value, possibly with parameters.
* @param parameters A map to populate with the parameters, or null
* @return The value.
*/
public static String getValueParameters(String value, Map<String, String> parameters)
{
return _header;
}
public String getName()
{
return _name;
}
public String getLowerCaseName()
{
return _header != null ? _header.lowerCaseName() : StringUtil.asciiToLowerCase(_name);
}
public String getValue()
{
return _value;
}
public int getIntValue()
{
return Integer.parseInt(_value);
}
public long getLongValue()
{
return Long.parseLong(_value);
}
public String[] getValues()
{
if (_value == null)
if (value == null)
return null;
QuotedCSV list = new QuotedCSV(false, _value);
return list.getValues().toArray(new String[list.size()]);
int i = value.indexOf(';');
if (i < 0)
return value;
if (parameters == null)
return value.substring(0, i).trim();
StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
while (tok1.hasMoreTokens())
{
String token = tok1.nextToken();
StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
if (tok2.hasMoreTokens())
{
String paramName = tok2.nextToken();
String paramVal = null;
if (tok2.hasMoreTokens())
paramVal = tok2.nextToken();
parameters.put(paramName, paramVal);
}
}
return value.substring(0, i).trim();
}
/**
* Get field value without parameters. Some field values can have parameters. This method separates the
* value from the parameters and optionally populates a map with the parameters. For example:
*
* <PRE>
*
* FieldName : Value ; param1=val1 ; param2=val2
*
* </PRE>
*
* @param value The Field value, possibly with parameters.
* @return The value.
*/
public static String stripParameters(String value)
{
if (value == null)
return null;
int i = value.indexOf(';');
if (i < 0)
return value;
return value.substring(0, i).trim();
}
public static String valueParameters(String value, Map<String, String> parameters)
{
return getValueParameters(value, parameters);
}
/**
@ -275,10 +311,66 @@ public class HttpField
}
@Override
public String toString()
public boolean equals(Object o)
{
String v = getValue();
return getName() + ": " + (v == null ? "" : v);
if (o == this)
return true;
if (!(o instanceof HttpField))
return false;
HttpField field = (HttpField)o;
if (_header != field.getHeader())
return false;
if (!_name.equalsIgnoreCase(field.getName()))
return false;
return Objects.equals(_value, field.getValue());
}
public HttpHeader getHeader()
{
return _header;
}
public int getIntValue()
{
return Integer.parseInt(_value);
}
public long getLongValue()
{
return Long.parseLong(_value);
}
public String getLowerCaseName()
{
return _header != null ? _header.lowerCaseName() : StringUtil.asciiToLowerCase(_name);
}
public String getName()
{
return _name;
}
public String getValue()
{
return _value;
}
public String[] getValues()
{
if (_value == null)
return null;
QuotedCSV list = new QuotedCSV(false, _value);
return list.getValues().toArray(new String[list.size()]);
}
@Override
public int hashCode()
{
int vhc = Objects.hashCode(_value);
if (_header == null)
return vhc ^ nameHashCode();
return vhc ^ _header.hashCode();
}
public boolean isSameName(HttpField field)
@ -289,9 +381,14 @@ public class HttpField
return true;
if (_header != null && _header == field.getHeader())
return true;
if (_name.equalsIgnoreCase(field.getName()))
return true;
return false;
return _name.equalsIgnoreCase(field.getName());
}
@Override
public String toString()
{
String v = getValue();
return getName() + ": " + (v == null ? "" : v);
}
private int nameHashCode()
@ -314,30 +411,6 @@ public class HttpField
return h;
}
@Override
public int hashCode()
{
int vhc = Objects.hashCode(_value);
if (_header == null)
return vhc ^ nameHashCode();
return vhc ^ _header.hashCode();
}
@Override
public boolean equals(Object o)
{
if (o == this)
return true;
if (!(o instanceof HttpField))
return false;
HttpField field = (HttpField)o;
if (_header != field.getHeader())
return false;
if (!_name.equalsIgnoreCase(field.getName()))
return false;
return Objects.equals(_value, field.getValue());
}
public static class IntValueHttpField extends HttpField
{
private final int _int;

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@ import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.function.Supplier;
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTrie;
@ -52,12 +51,7 @@ public class HttpGenerator
public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1, 100, null, null, -1);
public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1, 102, null, null, -1);
public static final MetaData.Response RESPONSE_500_INFO =
new MetaData.Response(HttpVersion.HTTP_1_1, INTERNAL_SERVER_ERROR_500, null, new HttpFields()
{
{
put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
}
}, 0);
new MetaData.Response(HttpVersion.HTTP_1_1, INTERNAL_SERVER_ERROR_500, null, HttpFields.build().put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE), 0);
// states
public enum State
@ -87,11 +81,11 @@ public class HttpGenerator
private State _state = State.START;
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
private MetaData _info;
private long _contentPrepared = 0;
private boolean _noContentResponse = false;
private Boolean _persistent = null;
private Supplier<HttpFields> _trailers = null;
private final int _send;
private static final int SEND_SERVER = 0x01;
@ -127,12 +121,12 @@ public class HttpGenerator
public void reset()
{
_state = State.START;
_info = null;
_endOfContent = EndOfContent.UNKNOWN_CONTENT;
_noContentResponse = false;
_persistent = null;
_contentPrepared = 0;
_needCRLF = false;
_trailers = null;
}
public State getState()
@ -208,6 +202,7 @@ public class HttpGenerator
{
if (info == null)
return Result.NEED_INFO;
_info = info;
if (header == null)
return Result.NEED_HEADER;
@ -222,7 +217,7 @@ public class HttpGenerator
if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "HTTP/0.9 not supported");
generateHeaders(info, header, content, last);
generateHeaders(header, content, last);
boolean expect100 = info.getFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
@ -325,13 +320,13 @@ public class HttpGenerator
if (isChunking())
{
if (_trailers != null)
if (_info.getTrailerSupplier() != null)
{
// Do we need a chunk buffer?
if (chunk == null || chunk.capacity() <= CHUNK_SIZE)
return Result.NEED_CHUNK_TRAILER;
HttpFields trailers = _trailers.get();
HttpFields trailers = _info.getTrailerSupplier().get();
if (trailers != null)
{
@ -368,6 +363,8 @@ public class HttpGenerator
{
if (info == null)
return Result.NEED_INFO;
_info = info;
HttpVersion version = info.getHttpVersion();
if (version == null)
throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "No version");
@ -411,7 +408,7 @@ public class HttpGenerator
_noContentResponse = true;
}
generateHeaders(info, header, content, last);
generateHeaders(header, content, last);
// handle the content.
int len = BufferUtil.length(content);
@ -573,30 +570,29 @@ public class HttpGenerator
return bytes;
}
private void generateHeaders(MetaData info, ByteBuffer header, ByteBuffer content, boolean last)
private void generateHeaders(ByteBuffer header, ByteBuffer content, boolean last)
{
final MetaData.Request request = (info instanceof MetaData.Request) ? (MetaData.Request)info : null;
final MetaData.Response response = (info instanceof MetaData.Response) ? (MetaData.Response)info : null;
final MetaData.Request request = (_info instanceof MetaData.Request) ? (MetaData.Request)_info : null;
final MetaData.Response response = (_info instanceof MetaData.Response) ? (MetaData.Response)_info : null;
if (LOG.isDebugEnabled())
{
LOG.debug("generateHeaders {} last={} content={}", info, last, BufferUtil.toDetailString(content));
LOG.debug(info.getFields().toString());
LOG.debug("generateHeaders {} last={} content={}", _info, last, BufferUtil.toDetailString(content));
LOG.debug(_info.getFields().toString());
}
// default field values
int send = _send;
HttpField transferEncoding = null;
boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1;
boolean http11 = _info.getHttpVersion() == HttpVersion.HTTP_1_1;
boolean close = false;
_trailers = http11 ? info.getTrailerSupplier() : null;
boolean chunkedHint = _trailers != null;
boolean chunkedHint = _info.getTrailerSupplier() != null;
boolean contentType = false;
long contentLength = info.getContentLength();
long contentLength = _info.getContentLength();
boolean contentLengthField = false;
// Generate fields
HttpFields fields = info.getFields();
HttpFields fields = _info.getFields();
if (fields != null)
{
int n = fields.size();
@ -647,7 +643,7 @@ public class HttpGenerator
_persistent = false;
}
if (info.getHttpVersion() == HttpVersion.HTTP_1_0 && _persistent == null && field.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
if (_info.getHttpVersion() == HttpVersion.HTTP_1_0 && _persistent == null && field.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
{
_persistent = true;
}
@ -669,7 +665,7 @@ public class HttpGenerator
}
// Can we work out the content length?
if (last && contentLength < 0 && _trailers == null)
if (last && contentLength < 0 && _info.getTrailerSupplier() == null)
contentLength = _contentPrepared + BufferUtil.length(content);
// Calculate how to end _content and connection, _content length and transfer encoding
@ -677,13 +673,13 @@ public class HttpGenerator
boolean assumedContentRequest = request != null && Boolean.TRUE.equals(ASSUMED_CONTENT_METHODS.get(request.getMethod()));
boolean assumedContent = assumedContentRequest || contentType || chunkedHint;
boolean nocontentRequest = request != null && contentLength <= 0 && !assumedContent;
boolean noContentRequest = request != null && contentLength <= 0 && !assumedContent;
if (_persistent == null)
_persistent = http11 || (request != null && HttpMethod.CONNECT.is(request.getMethod()));
// If the message is known not to have content
if (_noContentResponse || nocontentRequest)
if (_noContentResponse || noContentRequest)
{
// We don't need to indicate a body length
_endOfContent = EndOfContent.NO_CONTENT;
@ -923,7 +919,7 @@ public class HttpGenerator
}
}
public static void putTo(HttpFields fields, ByteBuffer bufferInFillMode)
public static void putTo(HttpFields.Mutable fields, ByteBuffer bufferInFillMode)
{
for (HttpField field : fields)
{

File diff suppressed because it is too large Load Diff

View File

@ -24,29 +24,28 @@ import java.util.function.Supplier;
public class MetaData implements Iterable<HttpField>
{
private HttpVersion _httpVersion;
private final HttpVersion _httpVersion;
private final HttpFields _fields;
private long _contentLength;
private Supplier<HttpFields> _trailers;
private final long _contentLength;
private final Supplier<HttpFields> _trailerSupplier;
public MetaData(HttpVersion version, HttpFields fields)
{
this(version, fields, Long.MIN_VALUE);
this(version, fields, -1);
}
public MetaData(HttpVersion version, HttpFields fields, long contentLength)
{
_httpVersion = version;
_fields = fields;
_contentLength = contentLength;
this(version, fields, contentLength, null);
}
protected void recycle()
public MetaData(HttpVersion version, HttpFields fields, long contentLength, Supplier<HttpFields> trailerSupplier)
{
_httpVersion = null;
if (_fields != null)
_fields.clear();
_contentLength = Long.MIN_VALUE;
_httpVersion = version;
_fields = fields == null ? null : fields.asImmutable();
_contentLength = contentLength >= 0 ? contentLength : _fields == null ? -1 : _fields.getLongField(HttpHeader.CONTENT_LENGTH);
_trailerSupplier = trailerSupplier;
}
public boolean isRequest()
@ -67,14 +66,6 @@ public class MetaData implements Iterable<HttpField>
return _httpVersion;
}
/**
* @param httpVersion the HTTP version to set
*/
public void setHttpVersion(HttpVersion httpVersion)
{
_httpVersion = httpVersion;
}
/**
* @return the HTTP fields of this MetaData object
*/
@ -85,40 +76,20 @@ public class MetaData implements Iterable<HttpField>
public Supplier<HttpFields> getTrailerSupplier()
{
return _trailers;
return _trailerSupplier;
}
public void setTrailerSupplier(Supplier<HttpFields> trailers)
{
_trailers = trailers;
}
/**
* @return the content length if available, otherwise {@link Long#MIN_VALUE}
*/
public long getContentLength()
{
if (_contentLength == Long.MIN_VALUE)
{
if (_fields != null)
{
HttpField field = _fields.getField(HttpHeader.CONTENT_LENGTH);
_contentLength = field == null ? -1 : field.getLongValue();
}
}
return _contentLength;
}
public void setContentLength(long contentLength)
{
_contentLength = contentLength;
}
@Override
public Iterator<HttpField> iterator()
{
HttpFields fields = getFields();
return fields == null ? Collections.emptyIterator() : fields.iterator();
if (_fields == null)
return Collections.emptyIterator();
return _fields.iterator();
}
@Override
@ -134,8 +105,8 @@ public class MetaData implements Iterable<HttpField>
public static class Request extends MetaData
{
private String _method;
private HttpURI _uri;
private final String _method;
private final HttpURI _uri;
public Request(HttpFields fields)
{
@ -151,41 +122,23 @@ public class MetaData implements Iterable<HttpField>
{
super(version, fields, contentLength);
_method = method;
_uri = uri.asImmutable();
}
public Request(String method, String scheme, HostPortHttpField authority, String uri, HttpVersion version, HttpFields fields, long contentLength)
{
this(method,
HttpURI.build().scheme(scheme).host(authority == null ? null : authority.getHost()).port(authority == null ? -1 : authority.getPort()).pathQuery(uri),
version, fields, contentLength);
}
public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength, Supplier<HttpFields> trailers)
{
super(version, fields, contentLength, trailers);
_method = method;
_uri = uri;
}
public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields)
{
this(method, scheme, hostPort, uri, version, fields, Long.MIN_VALUE);
}
public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
{
this(method, scheme == null ? null : scheme.asString(), hostPort, uri, version, fields, contentLength);
}
public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
{
this(method, new HttpURI(scheme,
hostPort == null ? null : hostPort.getHost(),
hostPort == null ? -1 : hostPort.getPort(),
uri), version, fields, contentLength);
}
public Request(Request request)
{
this(request.getMethod(), new HttpURI(request.getURI()), request.getHttpVersion(), new HttpFields(request.getFields()), request.getContentLength());
}
@Override
public void recycle()
{
super.recycle();
_method = null;
if (_uri != null)
_uri.clear();
}
@Override
public boolean isRequest()
{
@ -200,14 +153,6 @@ public class MetaData implements Iterable<HttpField>
return _method;
}
/**
* @param method the HTTP method to set
*/
public void setMethod(String method)
{
_method = method;
}
/**
* @return the HTTP URI
*/
@ -216,14 +161,6 @@ public class MetaData implements Iterable<HttpField>
return _uri;
}
/**
* @param uri the HTTP URI to set
*/
public void setURI(HttpURI uri)
{
_uri = uri;
}
/**
* @return the HTTP URI in string form
*/
@ -248,7 +185,7 @@ public class MetaData implements Iterable<HttpField>
public static class ConnectRequest extends Request
{
private String _protocol;
private final String _protocol;
public ConnectRequest(HttpScheme scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol)
{
@ -257,7 +194,9 @@ public class MetaData implements Iterable<HttpField>
public ConnectRequest(String scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol)
{
super(HttpMethod.CONNECT.asString(), scheme, authority, path, HttpVersion.HTTP_2, fields, Long.MIN_VALUE);
super(HttpMethod.CONNECT.asString(),
HttpURI.build().scheme(scheme).host(authority == null ? null : authority.getHost()).port(authority == null ? -1 : authority.getPort()).pathQuery(path),
HttpVersion.HTTP_2, fields, Long.MIN_VALUE, null);
_protocol = protocol;
}
@ -266,24 +205,12 @@ public class MetaData implements Iterable<HttpField>
{
return _protocol;
}
@Override
public void recycle()
{
super.recycle();
_protocol = null;
}
}
public static class Response extends MetaData
{
private int _status;
private String _reason;
public Response()
{
this(null, 0, null);
}
private final int _status;
private final String _reason;
public Response(HttpVersion version, int status, HttpFields fields)
{
@ -292,13 +219,17 @@ public class MetaData implements Iterable<HttpField>
public Response(HttpVersion version, int status, HttpFields fields, long contentLength)
{
super(version, fields, contentLength);
_status = status;
this(version, status, null, fields, contentLength);
}
public Response(HttpVersion version, int status, String reason, HttpFields fields, long contentLength)
{
super(version, fields, contentLength);
this(version, status, reason, fields, contentLength, null);
}
public Response(HttpVersion version, int status, String reason, HttpFields fields, long contentLength, Supplier<HttpFields> trailers)
{
super(version, fields, contentLength, trailers);
_reason = reason;
_status = status;
}
@ -325,22 +256,6 @@ public class MetaData implements Iterable<HttpField>
return _reason;
}
/**
* @param status the HTTP status to set
*/
public void setStatus(int status)
{
_status = status;
}
/**
* @param reason the HTTP reason to set
*/
public void setReason(String reason)
{
_reason = reason;
}
@Override
public String toString()
{

View File

@ -365,11 +365,11 @@ public class GZIPContentDecoderTest
static final long UINT_MAX = 0xFFFFFFFFL;
@ParameterizedTest
@ValueSource(longs = {INT_MAX, INT_MAX + 1, UINT_MAX, UINT_MAX + 1})
@ValueSource(longs = {INT_MAX, INT_MAX + 1 /* TODO too slow , UINT_MAX, UINT_MAX + 1 */ })
public void testLargeGzipStream(long origSize) throws IOException
{
// Size chosen for trade off between speed of I/O vs speed of Gzip
final int BUFSIZE = 1024 * 1024;
final int BUFSIZE = 64 * 1024 * 1024;
// Create a buffer to use over and over again to produce the uncompressed input
byte[] cbuf = "0123456789ABCDEFGHIJKLMOPQRSTUVWXYZ".getBytes(StandardCharsets.UTF_8);

View File

@ -20,11 +20,14 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import org.eclipse.jetty.util.BufferUtil;
@ -36,6 +39,7 @@ import org.junit.jupiter.params.provider.ValueSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -47,10 +51,9 @@ public class HttpFieldsTest
@Test
public void testPut() throws Exception
{
HttpFields header = new HttpFields();
header.put("name0", "value:0");
header.put("name1", "value1");
HttpFields.Mutable header = HttpFields.build()
.put("name0", "value:0")
.put("name1", "value1");
assertEquals(2, header.size());
assertEquals("value:0", header.get("name0"));
@ -78,12 +81,11 @@ public class HttpFieldsTest
@Test
public void testPutTo() throws Exception
{
HttpFields header = new HttpFields();
header.put("name0", "value0");
header.put("name1", "value:A");
header.add("name1", "value:B");
header.add("name2", "");
HttpFields.Mutable header = HttpFields.build()
.put("name0", "value0")
.put("name1", "value:A")
.add("name1", "value:B")
.add("name2", "");
ByteBuffer buffer = BufferUtil.allocate(1024);
BufferUtil.flipToFill(buffer);
@ -96,13 +98,73 @@ public class HttpFieldsTest
assertThat(result, Matchers.containsString("name1: value:B"));
}
@Test
public void testImmutable() throws Exception
{
HttpFields header = HttpFields.build()
.put("name0", "value0")
.put("name1", "value1").asImmutable();
assertEquals("value0", header.get("name0"));
assertEquals("value0", header.get("Name0"));
assertEquals("value1", header.get("name1"));
assertEquals("value1", header.get("Name1"));
assertEquals(null, header.get("Name2"));
assertEquals("value0", header.getField("name0").getValue());
assertEquals("value0", header.getField("Name0").getValue());
assertEquals("value1", header.getField("name1").getValue());
assertEquals("value1", header.getField("Name1").getValue());
assertEquals(null, header.getField("Name2"));
assertEquals("value0", header.getField(0).getValue());
assertEquals("value1", header.getField(1).getValue());
assertThrows(NoSuchElementException.class, () ->
{
header.getField(2);
});
}
@Test
public void testMutable() throws Exception
{
HttpFields headers = HttpFields.build()
.add(HttpHeader.ETAG, "tag")
.add("name0", "value0")
.add("name1", "value1").asImmutable();
headers = HttpFields.build(headers, EnumSet.of(HttpHeader.ETAG, HttpHeader.CONTENT_RANGE))
.add(new PreEncodedHttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()))
.addDateField("name2", System.currentTimeMillis()).asImmutable();
headers = HttpFields.build(headers, new HttpField(HttpHeader.CONNECTION, "open"));
assertThat(headers.size(), is(4));
assertThat(headers.getField(0).getValue(), is("value0"));
assertThat(headers.getField(1).getValue(), is("value1"));
assertThat(headers.getField(2).getValue(), is("open"));
assertThat(headers.getField(3).getName(), is("name2"));
}
@Test
public void testMap() throws Exception
{
Map<HttpFields.Immutable,String> map = new HashMap<>();
map.put(HttpFields.build().add("X","1").add(HttpHeader.ETAG,"tag").asImmutable(),"1");
map.put(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"other").asImmutable(),"2");
assertThat(map.get(HttpFields.build().add("X","1").add(HttpHeader.ETAG,"tag").asImmutable()), is("1"));
assertThat(map.get(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"other").asImmutable()), is("2"));
assertThat(map.get(HttpFields.build().add("X","2").asImmutable()), nullValue());
assertThat(map.get(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"tag").asImmutable()), nullValue());
}
@Test
public void testGet() throws Exception
{
HttpFields header = new HttpFields();
header.put("name0", "value0");
header.put("name1", "value1");
HttpFields header = HttpFields.build()
.put("name0", "value0")
.put("name1", "value1");
assertEquals("value0", header.get("name0"));
assertEquals("value0", header.get("Name0"));
@ -127,7 +189,7 @@ public class HttpFieldsTest
@Test
public void testGetKnown() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.put("Connection", "value0");
header.put(HttpHeader.ACCEPT, "value1");
@ -145,7 +207,7 @@ public class HttpFieldsTest
@Test
public void testCRLF() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.put("name0", "value\r\n0");
header.put("name\r\n1", "value1");
@ -164,7 +226,7 @@ public class HttpFieldsTest
@Test
public void testCachedPut() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.put("Connection", "Keep-Alive");
header.put("tRansfer-EncOding", "CHUNKED");
@ -184,7 +246,7 @@ public class HttpFieldsTest
@Test
public void testRePut() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.put("name0", "value0");
header.put("name1", "xxxxxx");
@ -222,19 +284,27 @@ public class HttpFieldsTest
}
@Test
public void testRemovePut() throws Exception
public void testRemove() throws Exception
{
HttpFields header = new HttpFields(1);
header.put("name0", "value0");
header.put("name1", "value1");
header.put("name2", "value2");
HttpFields.Mutable header = HttpFields.build(1)
.put("name0", "value0")
.add(HttpHeader.CONTENT_TYPE, "text")
.add("name1", "WRONG")
.add(HttpHeader.EXPECT, "spanish inquisition")
.put("name1", "value1")
.add(HttpHeader.ETAG, "tag")
.put("name2", "value2");
assertEquals("value0", header.get("name0"));
assertEquals("text", header.get(HttpHeader.CONTENT_TYPE));
assertEquals("value1", header.get("name1"));
assertEquals("spanish inquisition", header.get(HttpHeader.EXPECT));
assertEquals("tag", header.get(HttpHeader.ETAG));
assertEquals("value2", header.get("name2"));
header.remove("name1");
header.remove(HttpHeader.ETAG);
header.remove(EnumSet.of(HttpHeader.CONTENT_TYPE, HttpHeader.EXPECT, HttpHeader.EXPIRES));
assertEquals("value0", header.get("name0"));
assertNull(header.get("name1"));
@ -262,7 +332,7 @@ public class HttpFieldsTest
@Test
public void testAdd() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.add("name0", "value0");
fields.add("name1", "valueA");
@ -324,7 +394,7 @@ public class HttpFieldsTest
{
final PreEncodedHttpField X_XSS_PROTECTION_FIELD = new PreEncodedHttpField("X-XSS-Protection", "1; mode=block");
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.add(X_XSS_PROTECTION_FIELD);
assertThat("Fields output", fields.toString(), containsString("X-XSS-Protection: 1; mode=block"));
@ -335,7 +405,7 @@ public class HttpFieldsTest
{
final HttpField X_XSS_PROTECTION_FIELD = new HttpField("X-XSS-Protection", "1; mode=block");
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.add(X_XSS_PROTECTION_FIELD);
assertThat("Fields output", fields.toString(), containsString("X-XSS-Protection: 1; mode=block"));
@ -344,7 +414,7 @@ public class HttpFieldsTest
@Test
public void testGetValues() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("name0", "value0A,value0B");
fields.add("name0", "value0C,value0D");
@ -384,7 +454,7 @@ public class HttpFieldsTest
@Test
public void testGetCSV() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("name0", "value0A,value0B");
fields.add("name0", "value0C,value0D");
@ -424,7 +494,7 @@ public class HttpFieldsTest
@Test
public void testAddQuotedCSV() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("some", "value");
fields.add("name", "\"zero\"");
@ -434,39 +504,45 @@ public class HttpFieldsTest
fields.add("name", "four, I V");
List<String> list = fields.getCSV("name", false);
assertEquals(HttpFields.valueParameters(list.get(0), null), "zero");
assertEquals(HttpFields.valueParameters(list.get(1), null), "one");
assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpFields.valueParameters(list.get(3), null), "three");
assertEquals(HttpFields.valueParameters(list.get(4), null), "four");
assertEquals(HttpFields.valueParameters(list.get(5), null), "I V");
assertEquals(HttpField.valueParameters(list.get(0), null), "zero");
assertEquals(HttpField.valueParameters(list.get(1), null), "one");
assertEquals(HttpField.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpField.valueParameters(list.get(3), null), "three");
assertEquals(HttpField.valueParameters(list.get(4), null), "four");
assertEquals(HttpField.valueParameters(list.get(5), null), "I V");
fields.addCSV("name", "six");
list = fields.getCSV("name", false);
assertEquals(HttpFields.valueParameters(list.get(0), null), "zero");
assertEquals(HttpFields.valueParameters(list.get(1), null), "one");
assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpFields.valueParameters(list.get(3), null), "three");
assertEquals(HttpFields.valueParameters(list.get(4), null), "four");
assertEquals(HttpFields.valueParameters(list.get(5), null), "I V");
assertEquals(HttpFields.valueParameters(list.get(6), null), "six");
assertEquals(HttpField.valueParameters(list.get(0), null), "zero");
assertEquals(HttpField.valueParameters(list.get(1), null), "one");
assertEquals(HttpField.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpField.valueParameters(list.get(3), null), "three");
assertEquals(HttpField.valueParameters(list.get(4), null), "four");
assertEquals(HttpField.valueParameters(list.get(5), null), "I V");
assertEquals(HttpField.valueParameters(list.get(6), null), "six");
fields.addCSV("name", "1 + 1", "7", "zero");
list = fields.getCSV("name", false);
assertEquals(HttpFields.valueParameters(list.get(0), null), "zero");
assertEquals(HttpFields.valueParameters(list.get(1), null), "one");
assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpFields.valueParameters(list.get(3), null), "three");
assertEquals(HttpFields.valueParameters(list.get(4), null), "four");
assertEquals(HttpFields.valueParameters(list.get(5), null), "I V");
assertEquals(HttpFields.valueParameters(list.get(6), null), "six");
assertEquals(HttpFields.valueParameters(list.get(7), null), "7");
assertEquals(HttpField.valueParameters(list.get(0), null), "zero");
assertEquals(HttpField.valueParameters(list.get(1), null), "one");
assertEquals(HttpField.valueParameters(list.get(2), null), "1 + 1");
assertEquals(HttpField.valueParameters(list.get(3), null), "three");
assertEquals(HttpField.valueParameters(list.get(4), null), "four");
assertEquals(HttpField.valueParameters(list.get(5), null), "I V");
assertEquals(HttpField.valueParameters(list.get(6), null), "six");
assertEquals(HttpField.valueParameters(list.get(7), null), "7");
fields.addCSV(HttpHeader.ACCEPT, "en", "it");
list = fields.getCSV(HttpHeader.ACCEPT, false);
assertEquals(HttpField.valueParameters(list.get(0), null), "en");
assertEquals(HttpField.valueParameters(list.get(1), null), "it");
fields.addCSV(HttpHeader.ACCEPT, "en", "it");
}
@Test
public void testGetQualityCSV() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("some", "value");
fields.add("name", "zero;q=0.9,four;q=0.1");
@ -477,18 +553,18 @@ public class HttpFieldsTest
fields.add("name", "first;");
List<String> list = fields.getQualityCSV("name");
assertEquals(HttpFields.valueParameters(list.get(0), null), "first");
assertEquals(HttpFields.valueParameters(list.get(1), null), "zero");
assertEquals(HttpFields.valueParameters(list.get(2), null), "one");
assertEquals(HttpFields.valueParameters(list.get(3), null), "two");
assertEquals(HttpFields.valueParameters(list.get(4), null), "three");
assertEquals(HttpFields.valueParameters(list.get(5), null), "four");
assertEquals(HttpField.valueParameters(list.get(0), null), "first");
assertEquals(HttpField.valueParameters(list.get(1), null), "zero");
assertEquals(HttpField.valueParameters(list.get(2), null), "one");
assertEquals(HttpField.valueParameters(list.get(3), null), "two");
assertEquals(HttpField.valueParameters(list.get(4), null), "three");
assertEquals(HttpField.valueParameters(list.get(5), null), "four");
}
@Test
public void testGetQualityCSVHeader() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("some", "value");
fields.add("Accept", "zero;q=0.9,four;q=0.1");
@ -499,18 +575,18 @@ public class HttpFieldsTest
fields.add("Accept", "first;");
List<String> list = fields.getQualityCSV(HttpHeader.ACCEPT);
assertEquals(HttpFields.valueParameters(list.get(0), null), "first");
assertEquals(HttpFields.valueParameters(list.get(1), null), "zero");
assertEquals(HttpFields.valueParameters(list.get(2), null), "one");
assertEquals(HttpFields.valueParameters(list.get(3), null), "two");
assertEquals(HttpFields.valueParameters(list.get(4), null), "three");
assertEquals(HttpFields.valueParameters(list.get(5), null), "four");
assertEquals(HttpField.valueParameters(list.get(0), null), "first");
assertEquals(HttpField.valueParameters(list.get(1), null), "zero");
assertEquals(HttpField.valueParameters(list.get(2), null), "one");
assertEquals(HttpField.valueParameters(list.get(3), null), "two");
assertEquals(HttpField.valueParameters(list.get(4), null), "three");
assertEquals(HttpField.valueParameters(list.get(5), null), "four");
}
@Test
public void testDateFields() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("D0", "Wed, 31 Dec 1969 23:59:59 GMT");
fields.put("D1", "Fri, 31 Dec 1999 23:59:59 GMT");
@ -552,7 +628,7 @@ public class HttpFieldsTest
@Test
public void testNegDateFields() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.putDateField("Dzero", 0);
assertEquals("Thu, 01 Jan 1970 00:00:00 GMT", fields.get("Dzero"));
@ -570,7 +646,7 @@ public class HttpFieldsTest
@Test
public void testLongFields() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.put("I1", "42");
header.put("I2", " 43 99");
@ -634,7 +710,7 @@ public class HttpFieldsTest
@Test
public void testContains() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
header.add("n0", "");
header.add("n1", ",");
@ -651,8 +727,8 @@ public class HttpFieldsTest
for (int i = 0; i < 8; i++)
{
assertTrue(header.containsKey("n" + i));
assertTrue(header.containsKey("N" + i));
assertTrue(header.contains("n" + i));
assertTrue(header.contains("N" + i));
assertFalse(header.contains("n" + i, "xyz"), "" + i);
assertEquals(i >= 4, header.contains("n" + i, "def"), "" + i);
}
@ -665,37 +741,37 @@ public class HttpFieldsTest
assertFalse(header.contains(HttpHeader.ACCEPT, "def"));
assertFalse(header.contains(HttpHeader.AGE, "abc"));
assertFalse(header.containsKey("n11"));
assertFalse(header.contains("n11"));
}
@ParameterizedTest
@ValueSource(strings = {"Host", "host", "HOST", "HoSt", "Connection", "CONNECTION", "connection", "CoNnEcTiOn"})
public void testContainsKeyTrue(String keyName)
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put("Host", "localhost");
HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus");
fields.put(namelessField);
assertTrue(fields.containsKey(keyName), "containsKey('" + keyName + "')");
assertTrue(fields.contains(keyName), "containsKey('" + keyName + "')");
}
@ParameterizedTest
@ValueSource(strings = {"Content-Type", "Content-Length", "X-Bogus", ""})
public void testContainsKeyFalse(String keyName)
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "localhost");
HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus");
fields.put(namelessField);
assertFalse(fields.containsKey(keyName), "containsKey('" + keyName + "')");
assertFalse(fields.contains(keyName), "containsKey('" + keyName + "')");
}
@Test
public void testPreventNullField()
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
assertThrows(NullPointerException.class, () ->
{
HttpField nullNullField = new HttpField(null, null, "bogus");
@ -706,15 +782,21 @@ public class HttpFieldsTest
@Test
public void testIteration() throws Exception
{
HttpFields header = new HttpFields();
HttpFields.Mutable header = HttpFields.build();
Iterator<HttpField> i = header.iterator();
assertThat(i.hasNext(), is(false));
header.put("name1", "valueA");
header.put("name2", "valueB");
header.add("name3", "valueC");
header.add("REMOVE", "ME")
.add("name1", "valueA")
.add("name2", "valueB")
.add("name3", "valueC");
i = header.iterator();
assertThat(i.hasNext(), is(true));
assertThat(i.next().getName(), is("REMOVE"));
i.remove();
assertThat(i.hasNext(), is(true));
assertThat(i.next().getName(), is("name1"));
assertThat(i.next().getName(), is("name2"));
@ -728,6 +810,7 @@ public class HttpFieldsTest
assertThat(i.next().getName(), is("name3"));
assertThat(i.hasNext(), is(false));
header.add("REMOVE", "ME");
ListIterator<HttpField> l = header.listIterator();
assertThat(l.hasNext(), is(true));
l.add(new HttpField("name0", "value"));
@ -748,6 +831,11 @@ public class HttpFieldsTest
assertThat(l.next().getName(), is("NAME1"));
l.add(new HttpField("name2", "value"));
assertThat(l.next().getName(), is("name3"));
assertThat(l.hasNext(), is(true));
assertThat(l.next().getName(), is("REMOVE"));
l.remove();
assertThat(l.hasNext(), is(false));
assertThat(l.hasPrevious(), is(true));
l.add(new HttpField("name4", "value"));

View File

@ -33,16 +33,21 @@ public class HttpGeneratorClientTest
{
public static final String[] connect = {null, "keep-alive", "close"};
class Info extends MetaData.Request
class RequestInfo extends MetaData.Request
{
Info(String method, String uri)
RequestInfo(String method, String uri, HttpFields fields)
{
super(method, new HttpURI(uri), HttpVersion.HTTP_1_1, new HttpFields(), -1);
super(method, HttpURI.from(method,uri), HttpVersion.HTTP_1_1, fields, -1);
}
public Info(String method, String uri, int contentLength)
RequestInfo(String method, String uri, HttpVersion version, HttpFields fields)
{
super(method, new HttpURI(uri), HttpVersion.HTTP_1_1, new HttpFields(), contentLength);
super(method, HttpURI.from(method,uri), version, fields, -1);
}
RequestInfo(String method, String uri, int contentLength, HttpFields fields)
{
super(method, HttpURI.from(method,uri), HttpVersion.HTTP_1_1, fields, contentLength);
}
}
@ -57,9 +62,10 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("GET", "/index.html");
info.getFields().add("Host", "something");
info.getFields().add("User-Agent", "test");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("User-Agent", "test");
RequestInfo info = new RequestInfo("GET", "/index.html", fields);
assertTrue(!gen.isChunking());
result = gen.generateRequest(info, null, null, null, true);
@ -94,27 +100,29 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("GET", "/index.html");
info.getFields().add("Host", "something");
info.getFields().add("Null", null);
info.getFields().add("Empty", "");
assertTrue(!gen.isChunking());
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("Null", null);
fields.add("Empty", "");
RequestInfo info = new RequestInfo("GET", "/index.html", fields);
assertFalse(gen.isChunking());
result = gen.generateRequest(info, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
assertFalse(gen.isChunking());
result = gen.generateRequest(info, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
assertTrue(!gen.isChunking());
assertFalse(gen.isChunking());
String out = BufferUtil.toString(header);
BufferUtil.clear(header);
result = gen.generateResponse(null, false, null, null, null, false);
assertEquals(HttpGenerator.Result.DONE, result);
assertEquals(HttpGenerator.State.END, gen.getState());
assertTrue(!gen.isChunking());
assertFalse(gen.isChunking());
assertEquals(0, gen.getContentPrepared());
assertThat(out, Matchers.containsString("GET /index.html HTTP/1.1"));
@ -128,10 +136,10 @@ public class HttpGeneratorClientTest
{
HttpGenerator gen = new HttpGenerator();
Info info = new Info("GET", "/index.html");
info.getFields().add("Host", "localhost");
info.getFields().add("Field", "SomeWhatLongValue");
info.setHttpVersion(HttpVersion.HTTP_1_0);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "localhost");
fields.add("Field", "SomeWhatLongValue");
RequestInfo info = new RequestInfo("GET", "/index.html", HttpVersion.HTTP_1_0, fields);
HttpGenerator.Result result = gen.generateRequest(info, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -170,9 +178,10 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("POST", "/index.html");
info.getFields().add("Host", "something");
info.getFields().add("User-Agent", "test");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("User-Agent", "test");
RequestInfo info = new RequestInfo("POST", "/index.html", fields);
assertTrue(!gen.isChunking());
result = gen.generateRequest(info, null, null, null, true);
@ -209,9 +218,10 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("POST", "/index.html");
info.getFields().add("Host", "something");
info.getFields().add("User-Agent", "test");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("User-Agent", "test");
RequestInfo info = new RequestInfo("POST", "/index.html", fields);
result = gen.generateRequest(info, null, null, content0, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -254,9 +264,10 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("POST", "/index.html");
info.getFields().add("Host", "something");
info.getFields().add("User-Agent", "test");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("User-Agent", "test");
RequestInfo info = new RequestInfo("POST", "/index.html", fields);
result = gen.generateRequest(info, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -325,9 +336,10 @@ public class HttpGeneratorClientTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
Info info = new Info("POST", "/index.html", 58);
info.getFields().add("Host", "something");
info.getFields().add("User-Agent", "test");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Host", "something");
fields.add("User-Agent", "test");
RequestInfo info = new RequestInfo("POST", "/index.html", 58, fields);
result = gen.generateRequest(info, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);

View File

@ -78,7 +78,7 @@ public class HttpGeneratorServerHTTPTest
private static class Result
{
private HttpFields _fields = new HttpFields();
private HttpFields.Mutable _fields = HttpFields.build();
private final String _body;
private final int _code;
private String _connection;
@ -207,7 +207,7 @@ public class HttpGeneratorServerHTTPTest
return "[" + _code + "," + _contentType + "," + _contentLength + "," + (_body == null ? "null" : "content") + "]";
}
public HttpFields getHttpFields()
public HttpFields.Mutable getHttpFields()
{
return _fields;
}

View File

@ -19,7 +19,6 @@
package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
import org.eclipse.jetty.util.BufferUtil;
import org.junit.jupiter.api.Test;
@ -47,9 +46,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_0_9, 200, null, new HttpFields(), 10);
info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Content-Type", "test/data");
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_0_9, 200, null, fields, 10);
result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
@ -83,9 +83,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Content-Type", "test/data");
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, 10);
result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -115,8 +116,9 @@ public class HttpGeneratorServerTest
{
HttpGenerator gen = new HttpGenerator();
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 302, null, new HttpFields(), 0);
info.getFields().add("Location", "http://somewhere/else");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Location", "http://somewhere/else");
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 302, null, fields, 0);
HttpGenerator.Result result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -150,9 +152,10 @@ public class HttpGeneratorServerTest
HttpGenerator gen = new HttpGenerator();
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 204, "Foo", new HttpFields(), 10);
info.getFields().add("Content-Type", "test/data");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Content-Type", "test/data");
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 204, "Foo", fields, 10);
HttpGenerator.Result result = gen.generateResponse(info, false, header, null, content, true);
@ -186,9 +189,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, "ØÆ", new HttpFields(), 10);
info.getFields().add("Content-Type", "test/data;\r\nextra=value");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Content-Type", "test/data;\r\nextra=value");
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, "ØÆ", fields, 10);
result = gen.generateResponse(info, false, null, null, content, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -218,11 +222,12 @@ public class HttpGeneratorServerTest
public void testSendServerXPoweredBy() throws Exception
{
ByteBuffer header = BufferUtil.allocate(8096);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
HttpFields fields = new HttpFields();
fields.add(HttpHeader.SERVER, "SomeServer");
fields.add(HttpHeader.X_POWERED_BY, "SomePower");
MetaData.Response infoF = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1);
HttpFields.Mutable fields1 = HttpFields.build();
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields1, -1);
HttpFields.Mutable fields2 = HttpFields.build();
fields2.add(HttpHeader.SERVER, "SomeServer");
fields2.add(HttpHeader.X_POWERED_BY, "SomePower");
MetaData.Response infoF = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields2, -1);
String head;
HttpGenerator gen = new HttpGenerator(true, true);
@ -273,9 +278,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Content-Length", "11");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add("Content-Length", "11");
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, 10);
result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -298,8 +304,9 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 0);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, 0);
result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -331,9 +338,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 0);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Connection", "close");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add("Connection", "close");
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, 0);
result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -365,10 +373,11 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 101, null, new HttpFields(), -1);
info.getFields().add("Upgrade", "WebSocket");
info.getFields().add("Connection", "Upgrade");
info.getFields().add("Sec-WebSocket-Accept", "123456789==");
HttpFields.Mutable fields = HttpFields.build();
fields.add("Upgrade", "WebSocket");
fields.add("Connection", "Upgrade");
fields.add("Sec-WebSocket-Accept", "123456789==");
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 101, null, fields, -1);
result = gen.generateResponse(info, false, header, null, null, true);
assertEquals(HttpGenerator.Result.FLUSH, result);
@ -400,8 +409,9 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1);
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
@ -465,9 +475,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1);
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
@ -535,21 +546,18 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
info.setTrailerSupplier(new Supplier<HttpFields>()
{
@Override
public HttpFields get()
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1,
() ->
{
HttpFields trailer = new HttpFields();
trailer.add("T-Name0", "T-ValueA");
trailer.add("T-Name0", "T-ValueB");
trailer.add("T-Name1", "T-ValueC");
return trailer;
}
});
HttpFields.Mutable trailer1 = HttpFields.build();
trailer1.add("T-Name0", "T-ValueA");
trailer1.add("T-Name0", "T-ValueB");
trailer1.add("T-Name1", "T-ValueC");
return trailer1.asImmutable();
});
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -625,21 +633,18 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
info.setTrailerSupplier(new Supplier<HttpFields>()
{
@Override
public HttpFields get()
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1,
() ->
{
HttpFields trailer = new HttpFields();
trailer.add("T-Name0", "T-ValueA");
trailer.add("T-Name0", "T-ValueB");
trailer.add("T-Name1", "T-ValueC");
return trailer;
}
});
HttpFields.Mutable trailer1 = HttpFields.build();
trailer1.add("T-Name0", "T-ValueA");
trailer1.add("T-Name0", "T-ValueB");
trailer1.add("T-Name1", "T-ValueC");
return trailer1;
});
result = gen.generateResponse(info, false, null, null, null, true);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@ -697,8 +702,9 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 59);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, 59);
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
@ -745,9 +751,10 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
info.getFields().add("Content-Length", "" + (content0.remaining() + content1.remaining()));
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
fields.add("Content-Length", "" + (content0.remaining() + content1.remaining()));
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1);
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
@ -809,8 +816,9 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0) + BufferUtil.length(content1));
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
HttpFields.Mutable fields = HttpFields.build();
fields.add("Last-Modified", DateGenerator.__01Jan1970);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, BufferUtil.length(content0) + BufferUtil.length(content1));
result = gen.generateResponse(info, false, null, null, content0, false);
assertEquals(HttpGenerator.Result.NEED_HEADER, result);
assertEquals(HttpGenerator.State.START, gen.getState());
@ -850,7 +858,7 @@ public class HttpGeneratorServerTest
{
HttpGenerator generator = new HttpGenerator();
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
fields.put(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
String customValue = "test";
fields.add(HttpHeader.CONNECTION, customValue);

View File

@ -162,7 +162,7 @@ public class HttpURIParseTest
@MethodSource("data")
public void testParseString(String input, String scheme, String host, Integer port, String path, String param, String query, String fragment) throws Exception
{
HttpURI httpUri = new HttpURI(input);
HttpURI httpUri = HttpURI.from(input);
try
{
@ -210,7 +210,7 @@ public class HttpURIParseTest
}
assumeTrue(javaUri != null, "Skipping, not a valid input URI: " + input);
HttpURI httpUri = new HttpURI(javaUri);
HttpURI httpUri = HttpURI.from(javaUri);
assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(scheme));
assertThat("[" + input + "] .host", httpUri.getHost(), is(host));
@ -238,7 +238,7 @@ public class HttpURIParseTest
}
assumeTrue(javaUri != null, "Skipping, not a valid input URI");
HttpURI httpUri = new HttpURI(javaUri);
HttpURI httpUri = HttpURI.from(javaUri);
assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(javaUri.getScheme()));
assertThat("[" + input + "] .host", httpUri.getHost(), is(javaUri.getHost()));

View File

@ -18,10 +18,6 @@
package org.eclipse.jetty.http;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.util.MultiMap;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -33,10 +29,55 @@ import static org.junit.jupiter.api.Assertions.fail;
public class HttpURITest
{
@Test
public void testBuilder() throws Exception
{
HttpURI uri = HttpURI.build()
.scheme("http")
.user("user:password")
.host("host")
.port(8888)
.path("/ignored/../p%61th;ignored/info")
.param("param")
.query("query=value")
.asImmutable();
assertThat(uri.getScheme(), is("http"));
assertThat(uri.getUser(), is("user:password"));
assertThat(uri.getHost(), is("host"));
assertThat(uri.getPort(), is(8888));
assertThat(uri.getPath(), is("/ignored/../p%61th;ignored/info;param"));
assertThat(uri.getDecodedPath(), is("/path/info"));
assertThat(uri.getParam(), is("param"));
assertThat(uri.getQuery(), is("query=value"));
assertThat(uri.getAuthority(), is("host:8888"));
assertThat(uri.toString(), is("http://user:password@host:8888/ignored/../p%61th;ignored/info;param?query=value"));
uri = HttpURI.build(uri)
.scheme("https")
.user(null)
.authority("[::1]:8080")
.decodedPath("/some encoded/evening")
.param("id=12345")
.query(null)
.asImmutable();
assertThat(uri.getScheme(), is("https"));
assertThat(uri.getUser(), nullValue());
assertThat(uri.getHost(), is("[::1]"));
assertThat(uri.getPort(), is(8080));
assertThat(uri.getPath(), is("/some%20encoded/evening;id=12345"));
assertThat(uri.getDecodedPath(), is("/some encoded/evening"));
assertThat(uri.getParam(), is("id=12345"));
assertThat(uri.getQuery(), nullValue());
assertThat(uri.getAuthority(), is("[::1]:8080"));
assertThat(uri.toString(), is("https://[::1]:8080/some%20encoded/evening;id=12345"));
}
@Test
public void testExample() throws Exception
{
HttpURI uri = new HttpURI("http://user:password@host:8888/ignored/../p%61th;ignored/info;param?query=value#fragment");
HttpURI uri = HttpURI.from("http://user:password@host:8888/ignored/../p%61th;ignored/info;param?query=value#fragment");
assertThat(uri.getScheme(), is("http"));
assertThat(uri.getUser(), is("user:password"));
@ -60,10 +101,9 @@ public class HttpURITest
private void assertInvalidURI(String invalidURI, String message)
{
HttpURI uri = new HttpURI();
try
{
uri.parse(invalidURI);
HttpURI.build(invalidURI);
fail(message);
}
catch (IllegalArgumentException e)
@ -75,21 +115,26 @@ public class HttpURITest
@Test
public void testParse()
{
HttpURI uri = new HttpURI();
HttpURI.Mutable builder = HttpURI.build();
HttpURI uri;
uri.parse("*");
builder.uri("*");
uri = builder.asImmutable();
assertThat(uri.getHost(), nullValue());
assertThat(uri.getPath(), is("*"));
uri.parse("/foo/bar");
builder.uri("/foo/bar");
uri = builder.asImmutable();
assertThat(uri.getHost(), nullValue());
assertThat(uri.getPath(), is("/foo/bar"));
uri.parse("//foo/bar");
builder.uri("//foo/bar");
uri = builder.asImmutable();
assertThat(uri.getHost(), is("foo"));
assertThat(uri.getPath(), is("/bar"));
uri.parse("http://foo/bar");
builder.uri("http://foo/bar");
uri = builder.asImmutable();
assertThat(uri.getHost(), is("foo"));
assertThat(uri.getPath(), is("/bar"));
}
@ -97,113 +142,100 @@ public class HttpURITest
@Test
public void testParseRequestTarget()
{
HttpURI uri = new HttpURI();
HttpURI uri;
uri.parseRequestTarget("GET", "*");
uri = HttpURI.from("GET", "*");
assertThat(uri.getHost(), nullValue());
assertThat(uri.getPath(), is("*"));
uri.parseRequestTarget("GET", "/foo/bar");
uri = HttpURI.from("GET", "/foo/bar");
assertThat(uri.getHost(), nullValue());
assertThat(uri.getPath(), is("/foo/bar"));
uri.parseRequestTarget("GET", "//foo/bar");
uri = HttpURI.from("GET", "//foo/bar");
assertThat(uri.getHost(), nullValue());
assertThat(uri.getPath(), is("//foo/bar"));
uri.parseRequestTarget("GET", "http://foo/bar");
uri = HttpURI.from("GET", "http://foo/bar");
assertThat(uri.getHost(), is("foo"));
assertThat(uri.getPath(), is("/bar"));
}
@Test
public void testExtB() throws Exception
{
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
for (String value : new String[]{"a", "abcdABCD", "\u00C0", "\u697C", "\uD869\uDED5", "\uD840\uDC08"})
{
HttpURI uri = new HttpURI("/path?value=" + URLEncoder.encode(value, "UTF-8"));
MultiMap<String> parameters = new MultiMap<>();
uri.decodeQueryTo(parameters, StandardCharsets.UTF_8);
assertEquals(value, parameters.getString("value"));
}
}
@Test
public void testAt() throws Exception
{
HttpURI uri = new HttpURI("/@foo/bar");
HttpURI uri = HttpURI.from("/@foo/bar");
assertEquals("/@foo/bar", uri.getPath());
}
@Test
public void testParams() throws Exception
{
HttpURI uri = new HttpURI("/foo/bar");
HttpURI uri = HttpURI.from("/foo/bar");
assertEquals("/foo/bar", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
assertEquals(null, uri.getParam());
uri = new HttpURI("/foo/bar;jsessionid=12345");
uri = HttpURI.from("/foo/bar;jsessionid=12345");
assertEquals("/foo/bar;jsessionid=12345", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
assertEquals("jsessionid=12345", uri.getParam());
uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345");
uri = HttpURI.from("/foo;abc=123/bar;jsessionid=12345");
assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
assertEquals("jsessionid=12345", uri.getParam());
uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345?name=value");
uri = HttpURI.from("/foo;abc=123/bar;jsessionid=12345?name=value");
assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
assertEquals("jsessionid=12345", uri.getParam());
uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345#target");
uri = HttpURI.from("/foo;abc=123/bar;jsessionid=12345#target");
assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
assertEquals("jsessionid=12345", uri.getParam());
}
@Test
public void testMutableURI()
public void testMutableURIBuilder()
{
HttpURI uri = new HttpURI("/foo/bar");
HttpURI.Mutable builder = HttpURI.build("/foo/bar");
HttpURI uri = builder.asImmutable();
assertEquals("/foo/bar", uri.toString());
assertEquals("/foo/bar", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
uri.setScheme("http");
uri = builder.scheme("http").asImmutable();
assertEquals("http:/foo/bar", uri.toString());
assertEquals("/foo/bar", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
uri.setAuthority("host", 0);
uri = builder.authority("host", 0).asImmutable();
assertEquals("http://host/foo/bar", uri.toString());
assertEquals("/foo/bar", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
uri.setAuthority("host", 8888);
uri = builder.authority("host", 8888).asImmutable();
assertEquals("http://host:8888/foo/bar", uri.toString());
assertEquals("/foo/bar", uri.getPath());
assertEquals("/foo/bar", uri.getDecodedPath());
uri.setPathQuery("/f%30%30;p0/bar;p1;p2");
uri = builder.pathQuery("/f%30%30;p0/bar;p1;p2").asImmutable();
assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2", uri.toString());
assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
assertEquals("/f00/bar", uri.getDecodedPath());
assertEquals("p2", uri.getParam());
assertEquals(null, uri.getQuery());
uri.setPathQuery("/f%30%30;p0/bar;p1;p2?name=value");
uri = builder.pathQuery("/f%30%30;p0/bar;p1;p2?name=value").asImmutable();
assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?name=value", uri.toString());
assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
assertEquals("/f00/bar", uri.getDecodedPath());
assertEquals("p2", uri.getParam());
assertEquals("name=value", uri.getQuery());
uri.setQuery("other=123456");
uri = builder.query("other=123456").asImmutable();
assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?other=123456", uri.toString());
assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
assertEquals("/f00/bar", uri.getDecodedPath());
@ -214,26 +246,27 @@ public class HttpURITest
@Test
public void testSchemeAndOrAuthority() throws Exception
{
HttpURI uri = new HttpURI("/path/info");
HttpURI.Mutable builder = HttpURI.build("/path/info");
HttpURI uri = builder.asImmutable();
assertEquals("/path/info", uri.toString());
uri.setAuthority("host", 0);
uri = builder.authority("host", 0).asImmutable();
assertEquals("//host/path/info", uri.toString());
uri.setAuthority("host", 8888);
uri = builder.authority("host", 8888).asImmutable();
assertEquals("//host:8888/path/info", uri.toString());
uri.setScheme("http");
uri = builder.scheme("http").asImmutable();
assertEquals("http://host:8888/path/info", uri.toString());
uri.setAuthority(null, 0);
uri = builder.authority(null, 0).asImmutable();
assertEquals("http:/path/info", uri.toString());
}
@Test
public void testBasicAuthCredentials() throws Exception
{
HttpURI uri = new HttpURI("http://user:password@example.com:8888/blah");
HttpURI uri = HttpURI.from("http://user:password@example.com:8888/blah");
assertEquals("http://user:password@example.com:8888/blah", uri.toString());
assertEquals(uri.getAuthority(), "example.com:8888");
assertEquals(uri.getUser(), "user:password");
@ -242,34 +275,34 @@ public class HttpURITest
@Test
public void testCanonicalDecoded() throws Exception
{
HttpURI uri = new HttpURI("/path/.info");
HttpURI uri = HttpURI.from("/path/.info");
assertEquals("/path/.info", uri.getDecodedPath());
uri = new HttpURI("/path/./info");
uri = HttpURI.from("/path/./info");
assertEquals("/path/info", uri.getDecodedPath());
uri = new HttpURI("/path/../info");
uri = HttpURI.from("/path/../info");
assertEquals("/info", uri.getDecodedPath());
uri = new HttpURI("/./path/info.");
uri = HttpURI.from("/./path/info.");
assertEquals("/path/info.", uri.getDecodedPath());
uri = new HttpURI("./path/info/.");
uri = HttpURI.from("./path/info/.");
assertEquals("path/info/", uri.getDecodedPath());
uri = new HttpURI("http://host/path/.info");
uri = HttpURI.from("http://host/path/.info");
assertEquals("/path/.info", uri.getDecodedPath());
uri = new HttpURI("http://host/path/./info");
uri = HttpURI.from("http://host/path/./info");
assertEquals("/path/info", uri.getDecodedPath());
uri = new HttpURI("http://host/path/../info");
uri = HttpURI.from("http://host/path/../info");
assertEquals("/info", uri.getDecodedPath());
uri = new HttpURI("http://host/./path/info.");
uri = HttpURI.from("http://host/./path/info.");
assertEquals("/path/info.", uri.getDecodedPath());
uri = new HttpURI("http:./path/info/.");
uri = HttpURI.from("http:./path/info/.");
assertEquals("path/info/", uri.getDecodedPath());
}
}

View File

@ -68,7 +68,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
* HttpFields requestFields = new HttpFields();
* requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
* // Prepare the HTTP request object.
* MetaData.Request request = new MetaData.Request("PUT", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
* MetaData.Request request = new MetaData.Request("PUT", HttpURI.from("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
* // Create the HTTP/2 HEADERS frame representing the HTTP request.
* HeadersFrame headersFrame = new HeadersFrame(request, null, false);
*

View File

@ -20,6 +20,8 @@ package org.eclipse.jetty.http2.client;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.http.HostPortHttpField;
@ -30,6 +32,7 @@ import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.ConnectionFactory;
@ -69,10 +72,16 @@ public class AbstractTest
}
protected void start(ServerSessionListener listener) throws Exception
{
start(listener, x -> {});
}
protected void start(ServerSessionListener listener, Consumer<AbstractHTTP2ServerConnectionFactory> configurator) throws Exception
{
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
connectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
configurator.accept(connectionFactory);
prepareServer(connectionFactory);
server.start();
@ -119,7 +128,7 @@ public class AbstractTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), servletPath + pathInfo, HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField(authority), servletPath + pathInfo, HttpVersion.HTTP_2, fields, -1);
}
@AfterEach

View File

@ -86,8 +86,7 @@ public class AsyncIOTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
final CountDownLatch latch = new CountDownLatch(1);
FuturePromise<Stream> promise = new FuturePromise<>();
@ -137,8 +136,7 @@ public class AsyncIOTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
final CountDownLatch latch = new CountDownLatch(1);
FuturePromise<Stream> promise = new FuturePromise<>();
@ -193,8 +191,7 @@ public class AsyncIOTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
final CountDownLatch latch = new CountDownLatch(1);
FuturePromise<Stream> promise = new FuturePromise<>();
@ -266,8 +263,7 @@ public class AsyncIOTest extends AbstractTest
}
});
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
FuturePromise<Stream> promise = new FuturePromise<>();

View File

@ -94,8 +94,7 @@ public class AsyncServletTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
CountDownLatch latch = new CountDownLatch(1);
@ -131,8 +130,7 @@ public class AsyncServletTest extends AbstractTest
client.setIdleTimeout(idleTimeout);
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch responseLatch = new CountDownLatch(1);
@ -168,8 +166,7 @@ public class AsyncServletTest extends AbstractTest
client.setIdleTimeout(10 * idleTimeout);
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch clientLatch = new CountDownLatch(1);
@ -217,8 +214,7 @@ public class AsyncServletTest extends AbstractTest
prepareClient();
client.start();
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(frame, promise, new Stream.Listener.Adapter());
@ -328,8 +324,7 @@ public class AsyncServletTest extends AbstractTest
client.start();
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
CountDownLatch clientLatch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()

View File

@ -0,0 +1,107 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http2.client;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ConcurrentStreamCreationTest extends AbstractTest
{
@Test
public void testConcurrentStreamCreation() throws Exception
{
int threads = 64;
int runs = 1;
int iterations = 1024;
int total = threads * runs * iterations;
CountDownLatch serverLatch = new CountDownLatch(total);
start(new ServerSessionListener.Adapter()
{
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
stream.headers(responseFrame, Callback.NOOP);
serverLatch.countDown();
return null;
}
}, h2 -> h2.setMaxConcurrentStreams(total));
Session session = newClient(new Session.Listener.Adapter());
CyclicBarrier barrier = new CyclicBarrier(threads);
CountDownLatch clientLatch = new CountDownLatch(total);
CountDownLatch responseLatch = new CountDownLatch(runs);
Promise<Stream> promise = new Promise.Adapter<Stream>()
{
@Override
public void succeeded(Stream stream)
{
clientLatch.countDown();
}
};
IntStream.range(0, threads).forEach(i -> new Thread(() ->
{
try
{
barrier.await();
IntStream.range(0, runs).forEach(j ->
IntStream.range(0, iterations).forEach(k ->
{
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, true);
session.newStream(requestFrame, promise, new Stream.Listener.Adapter()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
int status = ((MetaData.Response)frame.getMetaData()).getStatus();
if (status == HttpStatus.OK_200 && frame.isEndStream())
responseLatch.countDown();
}
});
}));
}
catch (Throwable x)
{
x.printStackTrace();
}
}).start());
assertTrue(clientLatch.await(total, TimeUnit.MILLISECONDS), String.format("Missing streams on client: %d/%d", clientLatch.getCount(), total));
assertTrue(serverLatch.await(total, TimeUnit.MILLISECONDS), String.format("Missing streams on server: %d/%d", serverLatch.getCount(), total));
assertTrue(responseLatch.await(total, TimeUnit.MILLISECONDS), String.format("Missing response on client: %d/%d", clientLatch.getCount(), total));
}
}

View File

@ -79,7 +79,7 @@ public class ConnectTunnelTest extends AbstractTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
MetaData.Request request = new MetaData.Request(HttpMethod.CONNECT.asString(), null, new HostPortHttpField(authority), null, HttpVersion.HTTP_2, new HttpFields());
MetaData.Request request = new MetaData.Request(HttpMethod.CONNECT.asString(), null, new HostPortHttpField(authority), null, HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
client.newStream(new HeadersFrame(request, null, false), streamPromise, new Stream.Listener.Adapter()
{
@ -131,7 +131,7 @@ public class ConnectTunnelTest extends AbstractTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
MetaData.Request request = new MetaData.ConnectRequest(HttpScheme.HTTP, new HostPortHttpField(authority), "/", new HttpFields(), "websocket");
MetaData.Request request = new MetaData.ConnectRequest(HttpScheme.HTTP, new HostPortHttpField(authority), "/", HttpFields.EMPTY, "websocket");
FuturePromise<Stream> streamPromise = new FuturePromise<>();
client.newStream(new HeadersFrame(request, null, false), streamPromise, new Stream.Listener.Adapter()
{

View File

@ -79,7 +79,7 @@ public class DataDemandTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request post = newRequest("POST", new HttpFields());
MetaData.Request post = newRequest("POST", HttpFields.EMPTY);
FuturePromise<Stream> promise = new FuturePromise<>();
Queue<DataFrame> clientQueue = new ConcurrentLinkedQueue<>();
client.newStream(new HeadersFrame(post, null, false), promise, new Stream.Listener.Adapter()
@ -177,7 +177,7 @@ public class DataDemandTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, false), Callback.from(() -> sendData(stream), x -> {}));
return null;
}
@ -189,7 +189,7 @@ public class DataDemandTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request post = newRequest("GET", new HttpFields());
MetaData.Request post = newRequest("GET", HttpFields.EMPTY);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch responseLatch = new CountDownLatch(1);
CountDownLatch beforeDataLatch = new CountDownLatch(1);
@ -237,7 +237,7 @@ public class DataDemandTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, false), Callback.from(() -> sendData(stream), x -> {}));
return null;
}
@ -249,7 +249,7 @@ public class DataDemandTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request post = newRequest("GET", new HttpFields());
MetaData.Request post = newRequest("GET", HttpFields.EMPTY);
CountDownLatch latch = new CountDownLatch(1);
client.newStream(new HeadersFrame(post, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -284,7 +284,7 @@ public class DataDemandTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, false), Callback.from(() -> sendData(stream), x -> {}));
return null;
}
@ -296,7 +296,7 @@ public class DataDemandTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request post = newRequest("GET", new HttpFields());
MetaData.Request post = newRequest("GET", HttpFields.EMPTY);
CountDownLatch latch = new CountDownLatch(1);
client.newStream(new HeadersFrame(post, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -339,7 +339,7 @@ public class DataDemandTest extends AbstractTest
stream.demand(1);
if (frame.isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
}
@ -348,7 +348,7 @@ public class DataDemandTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request post = newRequest("POST", new HttpFields());
MetaData.Request post = newRequest("POST", HttpFields.EMPTY);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch latch = new CountDownLatch(1);
client.newStream(new HeadersFrame(post, null, false), promise, new Stream.Listener.Adapter()

View File

@ -102,7 +102,7 @@ public class FlowControlStalledTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), target, HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField(authority), target, HttpVersion.HTTP_2, fields, -1);
}
@AfterEach
@ -140,7 +140,7 @@ public class FlowControlStalledTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Request request = (MetaData.Request)frame.getMetaData();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
if (request.getURIString().endsWith("/stall"))
{
@ -170,7 +170,7 @@ public class FlowControlStalledTest
CountDownLatch latch = new CountDownLatch(1);
Queue<Callback> callbacks = new ArrayDeque<>();
MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
MetaData.Request request = newRequest("GET", "/stall", HttpFields.EMPTY);
client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -188,7 +188,7 @@ public class FlowControlStalledTest
// does not result in the first be notified again of being stalled.
stallLatch.set(new CountDownLatch(1));
request = newRequest("GET", "/", new HttpFields());
request = newRequest("GET", "/", HttpFields.EMPTY);
client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter());
assertFalse(stallLatch.get().await(1, TimeUnit.SECONDS));
@ -231,7 +231,7 @@ public class FlowControlStalledTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Request request = (MetaData.Request)frame.getMetaData();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
if (request.getURIString().endsWith("/stall"))
{
@ -270,7 +270,7 @@ public class FlowControlStalledTest
CountDownLatch latch = new CountDownLatch(1);
Queue<Callback> callbacks = new ArrayDeque<>();
MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
MetaData.Request request = newRequest("GET", "/stall", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -288,7 +288,7 @@ public class FlowControlStalledTest
// does not result in the session be notified again of being stalled.
stallLatch.set(new CountDownLatch(1));
request = newRequest("GET", "/", new HttpFields());
request = newRequest("GET", "/", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter());
assertFalse(stallLatch.get().await(1, TimeUnit.SECONDS));

View File

@ -122,7 +122,7 @@ public abstract class FlowControlStrategyTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), "/", HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField(authority), "/", HttpVersion.HTTP_2, fields, -1);
}
@AfterEach
@ -192,7 +192,7 @@ public abstract class FlowControlStrategyTest
assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientSession.getRecvWindow());
assertTrue(prefaceLatch.await(5, TimeUnit.SECONDS));
MetaData.Request request1 = newRequest("GET", new HttpFields());
MetaData.Request request1 = newRequest("GET", HttpFields.EMPTY);
FuturePromise<Stream> promise1 = new FuturePromise<>();
clientSession.newStream(new HeadersFrame(request1, null, true), promise1, new Stream.Listener.Adapter());
HTTP2Stream clientStream1 = (HTTP2Stream)promise1.get(5, TimeUnit.SECONDS);
@ -216,7 +216,7 @@ public abstract class FlowControlStrategyTest
settingsLatch.await(5, TimeUnit.SECONDS);
// Now create a new stream, it must pick up the new value.
MetaData.Request request2 = newRequest("POST", new HttpFields());
MetaData.Request request2 = newRequest("POST", HttpFields.EMPTY);
FuturePromise<Stream> promise2 = new FuturePromise<>();
clientSession.newStream(new HeadersFrame(request2, null, true), promise2, new Stream.Listener.Adapter());
HTTP2Stream clientStream2 = (HTTP2Stream)promise2.get(5, TimeUnit.SECONDS);
@ -243,8 +243,7 @@ public abstract class FlowControlStrategyTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
HttpFields fields = new HttpFields();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
stream.headers(responseFrame, Callback.NOOP);
@ -286,7 +285,7 @@ public abstract class FlowControlStrategyTest
}
});
MetaData.Request request = newRequest("POST", new HttpFields());
MetaData.Request request = newRequest("POST", HttpFields.EMPTY);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(new HeadersFrame(request, null, false), promise, new Stream.Listener.Adapter());
Stream stream = promise.get(5, TimeUnit.SECONDS);
@ -327,7 +326,7 @@ public abstract class FlowControlStrategyTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
CompletableFuture<Void> completable = new CompletableFuture<>();
stream.headers(responseFrame, Callback.from(completable));
@ -352,7 +351,7 @@ public abstract class FlowControlStrategyTest
final CountDownLatch dataLatch = new CountDownLatch(1);
final Exchanger<Callback> exchanger = new Exchanger<>();
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -424,7 +423,7 @@ public abstract class FlowControlStrategyTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return new Stream.Listener.Adapter()
@ -475,7 +474,7 @@ public abstract class FlowControlStrategyTest
assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
session.newStream(requestFrame, streamPromise, null);
@ -527,7 +526,7 @@ public abstract class FlowControlStrategyTest
else
{
// For every stream, send down half the window size of data.
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
@ -546,7 +545,7 @@ public abstract class FlowControlStrategyTest
// First request is just to consume most of the session window.
final List<Callback> callbacks1 = new ArrayList<>();
final CountDownLatch prepareLatch = new CountDownLatch(1);
MetaData.Request request1 = newRequest("POST", new HttpFields());
MetaData.Request request1 = newRequest("POST", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request1, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -561,7 +560,7 @@ public abstract class FlowControlStrategyTest
assertTrue(prepareLatch.await(5, TimeUnit.SECONDS));
// Second request will consume half of the remaining the session window.
MetaData.Request request2 = newRequest("GET", new HttpFields());
MetaData.Request request2 = newRequest("GET", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request2, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -573,7 +572,7 @@ public abstract class FlowControlStrategyTest
// Third request will consume the whole session window, which is now stalled.
// A fourth request will not be able to receive data.
MetaData.Request request3 = newRequest("GET", new HttpFields());
MetaData.Request request3 = newRequest("GET", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request3, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -585,7 +584,7 @@ public abstract class FlowControlStrategyTest
// Fourth request is now stalled.
final CountDownLatch latch = new CountDownLatch(1);
MetaData.Request request4 = newRequest("GET", new HttpFields());
MetaData.Request request4 = newRequest("GET", HttpFields.EMPTY);
session.newStream(new HeadersFrame(request4, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -621,7 +620,7 @@ public abstract class FlowControlStrategyTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
@ -635,7 +634,7 @@ public abstract class FlowControlStrategyTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
final byte[] bytes = new byte[data.length];
final CountDownLatch latch = new CountDownLatch(1);
@ -667,7 +666,7 @@ public abstract class FlowControlStrategyTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
@ -699,7 +698,7 @@ public abstract class FlowControlStrategyTest
byte[] responseData = new byte[requestData.length];
final ByteBuffer responseContent = ByteBuffer.wrap(responseData);
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
Promise.Completable<Stream> completable = new Promise.Completable<>();
final CountDownLatch latch = new CountDownLatch(1);
@ -759,7 +758,7 @@ public abstract class FlowControlStrategyTest
});
// Consume the whole session and stream window.
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
CompletableFuture<Stream> completable = new CompletableFuture<>();
session.newStream(requestFrame, Promise.from(completable), new Stream.Listener.Adapter());
@ -843,7 +842,7 @@ public abstract class FlowControlStrategyTest
});
// Consume the whole stream window.
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter());
@ -914,7 +913,7 @@ public abstract class FlowControlStrategyTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
final CountDownLatch resetLatch = new CountDownLatch(1);
@ -969,7 +968,7 @@ public abstract class FlowControlStrategyTest
{
// Succeed the callbacks when the stream is already remotely closed.
callbacks.forEach(Callback::succeeded);
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
}
@ -993,7 +992,7 @@ public abstract class FlowControlStrategyTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
CountDownLatch latch = new CountDownLatch(1);

View File

@ -113,7 +113,7 @@ public class FlowControlWindowsTest
assertEquals(clientSessionRecvWindow, sessionRecvWindow);
HostPortHttpField hostPort = new HostPortHttpField("localhost:" + connector.getLocalPort());
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, hostPort, "/", HttpVersion.HTTP_2, new HttpFields());
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP.asString(), hostPort, "/", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
HeadersFrame frame = new HeadersFrame(request, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
clientSession.newStream(frame, promise, new Stream.Listener.Adapter());
@ -163,7 +163,7 @@ public class FlowControlWindowsTest
assertEquals(serverSessionRecvWindow, sessionRecvWindow);
HostPortHttpField hostPort = new HostPortHttpField("localhost:" + connector.getLocalPort());
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, hostPort, "/", HttpVersion.HTTP_2, new HttpFields());
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP.asString(), hostPort, "/", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
HeadersFrame frame = new HeadersFrame(request, null, true);
clientSession.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter());

View File

@ -83,8 +83,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -115,7 +114,7 @@ public class HTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, false), new Callback()
{
@Override
@ -130,8 +129,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -172,8 +170,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(2);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -221,7 +218,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
CountDownLatch latch = new CountDownLatch(1);
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
Promise.Completable<Stream> streamCompletable = new Promise.Completable<>();
session.newStream(frame, streamCompletable, new Stream.Listener.Adapter()
@ -269,9 +266,9 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
Random random = new Random();
HttpFields fields = new HttpFields();
fields.putLongField(downloadBytes, random.nextInt(128 * 1024));
fields.put("User-Agent", "HTTP2Client/" + Jetty.VERSION);
HttpFields fields = HttpFields.build()
.putLongField(downloadBytes, random.nextInt(128 * 1024))
.put("User-Agent", "HTTP2Client/" + Jetty.VERSION);
MetaData.Request metaData = newRequest("GET", fields);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(requests);
@ -306,8 +303,7 @@ public class HTTP2Test extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -338,13 +334,12 @@ public class HTTP2Test extends AbstractTest
{
assertEquals(host, request.getServerName());
assertEquals(port, request.getServerPort());
assertEquals(authority, request.getHeader("Host"));
}
});
Session session = newClient(new Session.Listener.Adapter());
HostPortHttpField hostHeader = new HostPortHttpField(authority);
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, hostHeader, servletPath, HttpVersion.HTTP_2, new HttpFields());
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), hostHeader, servletPath, HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -423,7 +418,7 @@ public class HTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields(), 0);
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY, 0);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
return null;
}
@ -440,7 +435,7 @@ public class HTTP2Test extends AbstractTest
});
assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
MetaData.Request request1 = newRequest("GET", new HttpFields());
MetaData.Request request1 = newRequest("GET", HttpFields.EMPTY);
FuturePromise<Stream> promise1 = new FuturePromise<>();
CountDownLatch exchangeLatch1 = new CountDownLatch(2);
session.newStream(new HeadersFrame(request1, null, false), promise1, new Stream.Listener.Adapter()
@ -454,7 +449,7 @@ public class HTTP2Test extends AbstractTest
});
Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
MetaData.Request request2 = newRequest("GET", new HttpFields());
MetaData.Request request2 = newRequest("GET", HttpFields.EMPTY);
FuturePromise<Stream> promise2 = new FuturePromise<>();
CountDownLatch exchangeLatch2 = new CountDownLatch(2);
session.newStream(new HeadersFrame(request2, null, false), promise2, new Stream.Listener.Adapter()
@ -469,7 +464,7 @@ public class HTTP2Test extends AbstractTest
Stream stream2 = promise2.get(5, TimeUnit.SECONDS);
// The third stream must not be created.
MetaData.Request request3 = newRequest("GET", new HttpFields());
MetaData.Request request3 = newRequest("GET", HttpFields.EMPTY);
CountDownLatch maxStreamsLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(request3, null, false), new Promise.Adapter<>()
{
@ -497,7 +492,7 @@ public class HTTP2Test extends AbstractTest
assertEquals(1, session.getStreams().size());
// Create a fourth stream.
MetaData.Request request4 = newRequest("GET", new HttpFields());
MetaData.Request request4 = newRequest("GET", HttpFields.EMPTY);
CountDownLatch exchangeLatch4 = new CountDownLatch(2);
session.newStream(new HeadersFrame(request4, null, true), new Promise.Adapter<>()
{
@ -540,7 +535,7 @@ public class HTTP2Test extends AbstractTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
Callback.Completable completable = new Callback.Completable();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, false), completable);
return new Stream.Listener.Adapter()
{
@ -563,7 +558,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, false);
Promise.Completable<Stream> completable = new Promise.Completable<>();
CountDownLatch completeLatch = new CountDownLatch(2);
@ -635,7 +630,7 @@ public class HTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
DataFrame dataFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
// The call to headers() is legal, but slow.
new Thread(() ->
@ -682,7 +677,7 @@ public class HTTP2Test extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -706,7 +701,7 @@ public class HTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(response, Callback.NOOP);
// Close cleanly.
@ -731,7 +726,7 @@ public class HTTP2Test extends AbstractTest
failureLatch.countDown();
}
});
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame request = new HeadersFrame(metaData, null, true);
session.newStream(request, new Promise.Adapter<>(), new Stream.Listener.Adapter());
@ -748,7 +743,7 @@ public class HTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(response, Callback.NOOP);
stream.getSession().close(ErrorCode.NO_ERROR.code, null, Callback.NOOP);
@ -787,7 +782,7 @@ public class HTTP2Test extends AbstractTest
closeLatch.countDown();
}
});
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame request = new HeadersFrame(metaData, null, true);
CountDownLatch responseLatch = new CountDownLatch(1);
session.newStream(request, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -811,8 +806,8 @@ public class HTTP2Test extends AbstractTest
// A bad header in the request should fail on the client.
Session session = newClient(new Session.Listener.Adapter());
HttpFields requestFields = new HttpFields();
requestFields.put(":custom", "special");
HttpFields requestFields = HttpFields.build()
.put(":custom", "special");
MetaData.Request metaData = newRequest("GET", requestFields);
HeadersFrame request = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
@ -835,7 +830,7 @@ public class HTTP2Test extends AbstractTest
// Good request with bad header in the response.
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame request = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch resetLatch = new CountDownLatch(1);
@ -878,7 +873,7 @@ public class HTTP2Test extends AbstractTest
// Good request with bad header in the response.
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", "/flush", new HttpFields());
MetaData.Request metaData = newRequest("GET", "/flush", HttpFields.EMPTY);
HeadersFrame request = new HeadersFrame(metaData, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch resetLatch = new CountDownLatch(1);
@ -925,7 +920,7 @@ public class HTTP2Test extends AbstractTest
dataLatch.countDown();
if (frame.isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
}
@ -949,7 +944,7 @@ public class HTTP2Test extends AbstractTest
// Start 2 requests without completing them yet.
CountDownLatch responseLatch = new CountDownLatch(2);
MetaData.Request metaData1 = newRequest("GET", new HttpFields());
MetaData.Request metaData1 = newRequest("GET", HttpFields.EMPTY);
HeadersFrame request1 = new HeadersFrame(metaData1, null, false);
FuturePromise<Stream> promise1 = new FuturePromise<>();
Stream.Listener.Adapter listener = new Stream.Listener.Adapter()
@ -969,7 +964,7 @@ public class HTTP2Test extends AbstractTest
Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
stream1.data(new DataFrame(stream1.getId(), ByteBuffer.allocate(1), false), Callback.NOOP);
MetaData.Request metaData2 = newRequest("GET", new HttpFields());
MetaData.Request metaData2 = newRequest("GET", HttpFields.EMPTY);
HeadersFrame request2 = new HeadersFrame(metaData2, null, false);
FuturePromise<Stream> promise2 = new FuturePromise<>();
clientSession.newStream(request2, promise2, listener);
@ -987,7 +982,7 @@ public class HTTP2Test extends AbstractTest
// New requests should be immediately rejected.
HostPortHttpField authority3 = new HostPortHttpField("localhost" + ":" + port);
MetaData.Request metaData3 = new MetaData.Request("GET", HttpScheme.HTTP, authority3, servletPath, HttpVersion.HTTP_2, new HttpFields());
MetaData.Request metaData3 = new MetaData.Request("GET", HttpScheme.HTTP.asString(), authority3, servletPath, HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
HeadersFrame request3 = new HeadersFrame(metaData3, null, false);
FuturePromise<Stream> promise3 = new FuturePromise<>();
CountDownLatch resetLatch = new CountDownLatch(1);

View File

@ -76,7 +76,7 @@ public class IdleTimeoutTest extends AbstractTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
stream.setIdleTimeout(10 * idleTimeout);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -94,7 +94,7 @@ public class IdleTimeoutTest extends AbstractTest
}
});
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -133,7 +133,7 @@ public class IdleTimeoutTest extends AbstractTest
});
// The request is not replied, and the server should idle timeout.
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -161,7 +161,7 @@ public class IdleTimeoutTest extends AbstractTest
// to avoid a race where the idle timeout fires
// again before we can send the headers to the client.
sleep(idleTimeout + idleTimeout / 2);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -180,7 +180,7 @@ public class IdleTimeoutTest extends AbstractTest
});
final CountDownLatch replyLatch = new CountDownLatch(1);
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -214,7 +214,7 @@ public class IdleTimeoutTest extends AbstractTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
stream.setIdleTimeout(10 * idleTimeout);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -229,7 +229,7 @@ public class IdleTimeoutTest extends AbstractTest
client.setIdleTimeout(idleTimeout);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -266,7 +266,7 @@ public class IdleTimeoutTest extends AbstractTest
client.setIdleTimeout(idleTimeout);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -290,7 +290,7 @@ public class IdleTimeoutTest extends AbstractTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
stream.setIdleTimeout(10 * idleTimeout);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -307,7 +307,7 @@ public class IdleTimeoutTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
final CountDownLatch replyLatch = new CountDownLatch(1);
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -350,7 +350,7 @@ public class IdleTimeoutTest extends AbstractTest
final CountDownLatch dataLatch = new CountDownLatch(1);
final CountDownLatch timeoutLatch = new CountDownLatch(1);
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<Stream>()
{
@ -411,7 +411,7 @@ public class IdleTimeoutTest extends AbstractTest
final CountDownLatch resetLatch = new CountDownLatch(1);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
// Stream does not end here, but we won't send any DATA frame.
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -455,7 +455,7 @@ public class IdleTimeoutTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(requestFrame, promise, new Stream.Listener.Adapter());
@ -505,7 +505,7 @@ public class IdleTimeoutTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
return null;
}
@ -518,7 +518,7 @@ public class IdleTimeoutTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> promise = new FuturePromise<Stream>()
{
@ -575,7 +575,7 @@ public class IdleTimeoutTest extends AbstractTest
connector.setIdleTimeout(2 * delay);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("POST", new HttpFields());
MetaData.Request metaData = newRequest("POST", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch latch = new CountDownLatch(1);
@ -641,7 +641,7 @@ public class IdleTimeoutTest extends AbstractTest
{
phaser.set(new CountDownLatch(1));
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter());
@ -655,7 +655,7 @@ public class IdleTimeoutTest extends AbstractTest
// Send one more request to consume the whole session flow control window.
CountDownLatch resetLatch = new CountDownLatch(1);
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter()

View File

@ -95,12 +95,12 @@ public class InterleavingTest extends AbstractTest
}
};
HeadersFrame headersFrame1 = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame headersFrame1 = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
session.newStream(headersFrame1, streamPromise1, streamListener);
streamPromise1.get(5, TimeUnit.SECONDS);
HeadersFrame headersFrame2 = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame headersFrame2 = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
FuturePromise<Stream> streamPromise2 = new FuturePromise<>();
session.newStream(headersFrame2, streamPromise2, streamListener);
streamPromise2.get(5, TimeUnit.SECONDS);
@ -111,7 +111,7 @@ public class InterleavingTest extends AbstractTest
Stream serverStream1 = serverStreams.get(0);
Stream serverStream2 = serverStreams.get(1);
MetaData.Response response1 = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response1 = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
serverStream1.headers(new HeadersFrame(serverStream1.getId(), response1, null, false), Callback.NOOP);
Random random = new Random();
@ -120,7 +120,7 @@ public class InterleavingTest extends AbstractTest
byte[] content2 = new byte[2 * ((ISession)serverStream2.getSession()).updateSendWindow(0)];
random.nextBytes(content2);
MetaData.Response response2 = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response2 = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
serverStream2.headers(new HeadersFrame(serverStream2.getId(), response2, null, false), new Callback()
{
@Override

View File

@ -78,7 +78,7 @@ public class MaxPushedStreamsTest extends AbstractTest
CompletableFuture<List<Stream>> result = CompletableFuture.completedFuture(new ArrayList<>());
// Push maxPushed resources...
IntStream.range(0, maxPushed)
.mapToObj(i -> new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_" + i, new HttpFields())))
.mapToObj(i -> new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_" + i, HttpFields.EMPTY)))
.map(pushFrame ->
{
Promise.Completable<Stream> promise = new Promise.Completable<>();
@ -91,7 +91,7 @@ public class MaxPushedStreamsTest extends AbstractTest
// ... then push one extra stream, the client must reject it...
.thenApply(streams ->
{
PushPromiseFrame extraPushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_extra", new HttpFields()));
PushPromiseFrame extraPushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_extra", HttpFields.EMPTY));
FuturePromise<Stream> extraPromise = new FuturePromise<>();
stream.push(extraPushFrame, extraPromise, new Stream.Listener.Adapter()
{
@ -113,7 +113,7 @@ public class MaxPushedStreamsTest extends AbstractTest
// ... then send the response.
.thenRun(() ->
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
});
return null;
@ -122,7 +122,7 @@ public class MaxPushedStreamsTest extends AbstractTest
client.setMaxConcurrentPushedStreams(maxPushed);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
CountDownLatch responseLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{

View File

@ -82,7 +82,7 @@ public class PrefaceTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -110,7 +110,7 @@ public class PrefaceTest extends AbstractTest
});
CountDownLatch latch = new CountDownLatch(1);
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -224,7 +224,7 @@ public class PrefaceTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
return null;
}

View File

@ -48,7 +48,7 @@ public class PriorityTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -60,7 +60,7 @@ public class PriorityTest extends AbstractTest
assertTrue(streamId > 0);
CountDownLatch latch = new CountDownLatch(2);
MetaData metaData = newRequest("GET", new HttpFields());
MetaData metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame headersFrame = new HeadersFrame(streamId, metaData, null, true);
session.newStream(headersFrame, new Promise.Adapter<Stream>()
{
@ -96,7 +96,7 @@ public class PriorityTest extends AbstractTest
try
{
beforeRequests.await(5, TimeUnit.SECONDS);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
afterRequests.countDown();
@ -122,13 +122,13 @@ public class PriorityTest extends AbstractTest
};
Session session = newClient(new Session.Listener.Adapter());
MetaData metaData1 = newRequest("GET", "/one", new HttpFields());
MetaData metaData1 = newRequest("GET", "/one", HttpFields.EMPTY);
HeadersFrame headersFrame1 = new HeadersFrame(metaData1, null, true);
FuturePromise<Stream> promise1 = new FuturePromise<>();
session.newStream(headersFrame1, promise1, listener);
Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
MetaData metaData2 = newRequest("GET", "/two", new HttpFields());
MetaData metaData2 = newRequest("GET", "/two", HttpFields.EMPTY);
HeadersFrame headersFrame2 = new HeadersFrame(metaData2, null, true);
FuturePromise<Stream> promise2 = new FuturePromise<>();
session.newStream(headersFrame2, promise2, listener);
@ -162,7 +162,7 @@ public class PriorityTest extends AbstractTest
assertEquals(priorityFrame.isExclusive(), priority.isExclusive());
latch.countDown();
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;
@ -170,7 +170,7 @@ public class PriorityTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData metaData = newRequest("GET", "/one", new HttpFields());
MetaData metaData = newRequest("GET", "/one", HttpFields.EMPTY);
HeadersFrame headersFrame = new HeadersFrame(metaData, priorityFrame, true);
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{

View File

@ -119,9 +119,8 @@ public class ProxyProtocolTest
client.accept(null, channel, new Session.Listener.Adapter(), promise);
Session session = promise.get(5, TimeUnit.SECONDS);
HttpFields fields = new HttpFields();
String uri = "http://localhost:" + connector.getLocalPort() + "/";
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI(uri), HttpVersion.HTTP_2, fields);
MetaData.Request metaData = new MetaData.Request("GET", HttpURI.from(uri), HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -177,9 +176,8 @@ public class ProxyProtocolTest
client.accept(null, channel, new Session.Listener.Adapter(), promise);
Session session = promise.get(5, TimeUnit.SECONDS);
HttpFields fields = new HttpFields();
String uri = "http://localhost:" + connector.getLocalPort() + "/";
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI(uri), HttpVersion.HTTP_2, fields);
MetaData.Request metaData = new MetaData.Request("GET", HttpURI.from(uri), HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()

View File

@ -125,7 +125,7 @@ public class ProxyTest
String host = "localhost";
int port = proxyConnector.getLocalPort();
String authority = host + ":" + port;
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields, -1);
}
@AfterEach
@ -165,7 +165,7 @@ public class ProxyTest
final CountDownLatch clientLatch = new CountDownLatch(1);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", "/", new HttpFields());
MetaData.Request metaData = newRequest("GET", "/", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{

View File

@ -70,7 +70,7 @@ public class PushCacheFilterTest extends AbstractTest
@Override
protected MetaData.Request newRequest(String method, String pathInfo, HttpFields fields)
{
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), contextPath + servletPath + pathInfo, HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:" + connector.getLocalPort()), contextPath + servletPath + pathInfo, HttpVersion.HTTP_2, fields, -1);
}
private String newURI(String pathInfo)
@ -102,8 +102,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String referrerURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
MetaData.Request primaryRequest = newRequest("GET", primaryResource, HttpFields.EMPTY);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -114,8 +113,8 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
secondaryFields.put(HttpHeader.REFERER, referrerURI);
HttpFields.Mutable secondaryFields = HttpFields.build()
.put(HttpHeader.REFERER, referrerURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -132,7 +131,7 @@ public class PushCacheFilterTest extends AbstractTest
assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
// Request again the primary resource, we should get the secondary resource pushed.
primaryRequest = newRequest("GET", primaryResource, primaryFields);
primaryRequest = newRequest("GET", primaryResource, HttpFields.EMPTY);
final CountDownLatch primaryResponseLatch = new CountDownLatch(2);
final CountDownLatch pushLatch = new CountDownLatch(2);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -206,7 +205,7 @@ public class PushCacheFilterTest extends AbstractTest
// The referrerURI does not point to the primary resource, so there will be no
// resource association with the primary resource and therefore won't be pushed.
final String referrerURI = "http://localhost:" + connector.getLocalPort();
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -218,8 +217,8 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
secondaryFields.put(HttpHeader.REFERER, referrerURI);
HttpFields.Mutable secondaryFields = HttpFields.build()
.put(HttpHeader.REFERER, referrerURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -292,7 +291,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String primaryURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -304,8 +303,8 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
secondaryFields.put(HttpHeader.REFERER, primaryURI);
HttpFields.Mutable secondaryFields = HttpFields.build()
.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -357,7 +356,7 @@ public class PushCacheFilterTest extends AbstractTest
assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
// Make sure the session is sane by requesting the secondary resource.
HttpFields secondaryFields = new HttpFields();
HttpFields.Mutable secondaryFields = HttpFields.build();
secondaryFields.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
final CountDownLatch secondaryResponseLatch = new CountDownLatch(1);
@ -395,7 +394,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String primaryURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -406,7 +405,7 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
HttpFields.Mutable secondaryFields = HttpFields.build();
secondaryFields.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -486,7 +485,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary, secondary and tertiary resource to build the cache.
final String primaryURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(2);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -499,8 +498,8 @@ public class PushCacheFilterTest extends AbstractTest
{
// Request for the secondary resources.
String secondaryURI1 = newURI(secondaryResource1);
HttpFields secondaryFields1 = new HttpFields();
secondaryFields1.put(HttpHeader.REFERER, primaryURI);
HttpFields.Mutable secondaryFields1 = HttpFields.build()
.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest1 = newRequest("GET", secondaryResource1, secondaryFields1);
session.newStream(new HeadersFrame(secondaryRequest1, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -511,8 +510,8 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the tertiary resource.
HttpFields tertiaryFields = new HttpFields();
tertiaryFields.put(HttpHeader.REFERER, secondaryURI1);
HttpFields.Mutable tertiaryFields = HttpFields.build()
.put(HttpHeader.REFERER, secondaryURI1);
MetaData.Request tertiaryRequest = newRequest("GET", tertiaryResource, tertiaryFields);
session.newStream(new HeadersFrame(tertiaryRequest, null, true), new Promise.Adapter<>(), new Adapter()
{
@ -528,8 +527,8 @@ public class PushCacheFilterTest extends AbstractTest
}
});
HttpFields secondaryFields2 = new HttpFields();
secondaryFields2.put(HttpHeader.REFERER, primaryURI);
HttpFields.Mutable secondaryFields2 = HttpFields.build()
.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest2 = newRequest("GET", secondaryResource2, secondaryFields2);
session.newStream(new HeadersFrame(secondaryRequest2, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -604,7 +603,7 @@ public class PushCacheFilterTest extends AbstractTest
// Make sure that explicitly requesting a secondary resource, we get the tertiary pushed.
CountDownLatch secondaryResponseLatch = new CountDownLatch(1);
CountDownLatch secondaryPushLatch = new CountDownLatch(1);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource1, new HttpFields());
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource1, HttpFields.EMPTY);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -675,7 +674,7 @@ public class PushCacheFilterTest extends AbstractTest
final Session session = newClient(new Session.Listener.Adapter());
// Login with the wrong credentials, causing a redirect to self.
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource + "?credentials=wrong", primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -690,7 +689,7 @@ public class PushCacheFilterTest extends AbstractTest
{
// Follow the redirect.
String location = response.getFields().get(HttpHeader.LOCATION);
HttpFields redirectFields = new HttpFields();
HttpFields.Mutable redirectFields = HttpFields.build();
redirectFields.put(HttpHeader.REFERER, primaryURI);
MetaData.Request redirectRequest = newRequest("GET", location, redirectFields);
session.newStream(new HeadersFrame(redirectRequest, null, true), new Promise.Adapter<>(), new Adapter()
@ -768,7 +767,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String primaryURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -779,7 +778,7 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
HttpFields.Mutable secondaryFields = HttpFields.build();
secondaryFields.put(HttpHeader.REFERER, primaryURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -861,7 +860,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String referrerURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -873,7 +872,7 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
HttpFields.Mutable secondaryFields = HttpFields.build();
secondaryFields.put(HttpHeader.REFERER, referrerURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -956,7 +955,7 @@ public class PushCacheFilterTest extends AbstractTest
// Request for the primary and secondary resource to build the cache.
final String referrerURI = newURI(primaryResource);
HttpFields primaryFields = new HttpFields();
HttpFields.Mutable primaryFields = HttpFields.build();
MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
final CountDownLatch warmupLatch = new CountDownLatch(1);
session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -968,7 +967,7 @@ public class PushCacheFilterTest extends AbstractTest
if (frame.isEndStream())
{
// Request for the secondary resource.
HttpFields secondaryFields = new HttpFields();
HttpFields.Mutable secondaryFields = HttpFields.build();
secondaryFields.put(HttpHeader.REFERER, referrerURI);
MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()

View File

@ -131,7 +131,7 @@ public class RawHTTP2ProxyTest
LOGGER.debug("SERVER1 received {}", frame);
if (frame.isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame reply = new HeadersFrame(stream.getId(), response, null, false);
if (LOGGER.isDebugEnabled())
LOGGER.debug("SERVER1 sending {}", reply);
@ -167,7 +167,7 @@ public class RawHTTP2ProxyTest
if (LOGGER.isDebugEnabled())
LOGGER.debug("SERVER2 received {}", frame);
callback.succeeded();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
Callback.Completable completable1 = new Callback.Completable();
HeadersFrame reply = new HeadersFrame(stream.getId(), response, null, false);
if (LOGGER.isDebugEnabled())
@ -183,7 +183,7 @@ public class RawHTTP2ProxyTest
return completable2;
}).thenRun(() ->
{
MetaData trailer = new MetaData(HttpVersion.HTTP_2, new HttpFields());
MetaData trailer = new MetaData(HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame end = new HeadersFrame(stream.getId(), trailer, null, true);
if (LOGGER.isDebugEnabled())
LOGGER.debug("SERVER2 sending {}", end);
@ -205,9 +205,9 @@ public class RawHTTP2ProxyTest
Session clientSession = clientPromise.get(5, TimeUnit.SECONDS);
// Send a request with trailers for server1.
HttpFields fields1 = new HttpFields();
HttpFields.Mutable fields1 = HttpFields.build();
fields1.put("X-Target", String.valueOf(connector1.getLocalPort()));
MetaData.Request request1 = new MetaData.Request("GET", new HttpURI("http://localhost/server1"), HttpVersion.HTTP_2, fields1);
MetaData.Request request1 = new MetaData.Request("GET", HttpURI.from("http://localhost/server1"), HttpVersion.HTTP_2, fields1);
FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
CountDownLatch latch1 = new CountDownLatch(1);
clientSession.newStream(new HeadersFrame(request1, null, false), streamPromise1, new Stream.Listener.Adapter()
@ -230,12 +230,12 @@ public class RawHTTP2ProxyTest
}
});
Stream stream1 = streamPromise1.get(5, TimeUnit.SECONDS);
stream1.headers(new HeadersFrame(stream1.getId(), new MetaData(HttpVersion.HTTP_2, new HttpFields()), null, true), Callback.NOOP);
stream1.headers(new HeadersFrame(stream1.getId(), new MetaData(HttpVersion.HTTP_2, HttpFields.EMPTY), null, true), Callback.NOOP);
// Send a request for server2.
HttpFields fields2 = new HttpFields();
HttpFields.Mutable fields2 = HttpFields.build();
fields2.put("X-Target", String.valueOf(connector2.getLocalPort()));
MetaData.Request request2 = new MetaData.Request("GET", new HttpURI("http://localhost/server1"), HttpVersion.HTTP_2, fields2);
MetaData.Request request2 = new MetaData.Request("GET", HttpURI.from("http://localhost/server1"), HttpVersion.HTTP_2, fields2);
FuturePromise<Stream> streamPromise2 = new FuturePromise<>();
CountDownLatch latch2 = new CountDownLatch(1);
clientSession.newStream(new HeadersFrame(request2, null, false), streamPromise2, new Stream.Listener.Adapter()

View File

@ -114,7 +114,7 @@ public class SessionFailureTest extends AbstractTest
clientFailureLatch.countDown();
}
});
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
Promise<Stream> promise = new Promise.Adapter<>();
session.newStream(frame, promise, null);

View File

@ -149,9 +149,10 @@ public class SmallThreadPoolLoadTest extends AbstractTest
int contentLength = random.nextInt(maxContentLength) + 1;
long requestId = requestIds.incrementAndGet();
MetaData.Request request = newRequest(method.asString(), "/" + requestId, new HttpFields());
if (download)
request.getFields().put("X-Download", String.valueOf(contentLength));
MetaData.Request request = newRequest(method.asString(), "/" + requestId,
download ? HttpFields.build().put("X-Download", String.valueOf(contentLength)) : HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, download);
FuturePromise<Stream> promise = new FuturePromise<>();
CountDownLatch requestLatch = new CountDownLatch(1);

View File

@ -65,7 +65,7 @@ public class StreamCloseTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(frame, promise, null);
Stream stream = promise.get(5, TimeUnit.SECONDS);
@ -82,7 +82,7 @@ public class StreamCloseTest extends AbstractTest
@Override
public Stream.Listener onNewStream(final Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(response, new Callback()
{
@ -99,7 +99,7 @@ public class StreamCloseTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(frame, promise, new Stream.Listener.Adapter()
{
@ -124,7 +124,7 @@ public class StreamCloseTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(response, completable);
@ -153,7 +153,7 @@ public class StreamCloseTest extends AbstractTest
final CountDownLatch completeLatch = new CountDownLatch(1);
Session session = newClient(new Session.Listener.Adapter());
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, false);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(frame, promise, new Stream.Listener.Adapter()
{
@ -196,7 +196,7 @@ public class StreamCloseTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", new HttpFields()));
PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), newRequest("GET", HttpFields.EMPTY));
stream.push(pushFrame, new Promise.Adapter<Stream>()
{
@Override
@ -216,14 +216,14 @@ public class StreamCloseTest extends AbstractTest
});
}
}, new Stream.Listener.Adapter());
HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()), null, true);
HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY), null, true);
stream.headers(response, Callback.NOOP);
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
final CountDownLatch clientLatch = new CountDownLatch(1);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -257,7 +257,7 @@ public class StreamCloseTest extends AbstractTest
@Override
public Stream.Listener onNewStream(final Stream stream, HeadersFrame frame)
{
PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", new HttpFields()));
PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", HttpFields.EMPTY));
stream.push(pushFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
@ -265,7 +265,7 @@ public class StreamCloseTest extends AbstractTest
{
assertTrue(pushedStream.isReset());
assertTrue(pushedStream.isClosed());
HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()), null, true);
HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY), null, true);
stream.headers(response, Callback.NOOP);
serverLatch.countDown();
}
@ -275,7 +275,7 @@ public class StreamCloseTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame frame = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
final CountDownLatch clientLatch = new CountDownLatch(2);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@ -339,11 +339,11 @@ public class StreamCloseTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
// First stream will be idle on server.
HeadersFrame request1 = new HeadersFrame(newRequest("HEAD", new HttpFields()), null, true);
HeadersFrame request1 = new HeadersFrame(newRequest("HEAD", HttpFields.EMPTY), null, true);
session.newStream(request1, new Promise.Adapter<>(), new Stream.Listener.Adapter());
// Second stream will fail on server.
HeadersFrame request2 = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
HeadersFrame request2 = new HeadersFrame(newRequest("GET", HttpFields.EMPTY), null, true);
session.newStream(request2, new Promise.Adapter<>(), new Stream.Listener.Adapter());
assertTrue(latch.await(5, TimeUnit.SECONDS));

View File

@ -73,8 +73,7 @@ public class StreamCountTest extends AbstractTest
{
if (frame.isEndStream())
{
HttpFields fields = new HttpFields();
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback);
}
else
@ -98,8 +97,7 @@ public class StreamCountTest extends AbstractTest
assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame1 = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
CountDownLatch responseLatch = new CountDownLatch(1);
@ -143,8 +141,7 @@ public class StreamCountTest extends AbstractTest
{
if (frame.isEndStream())
{
HttpFields fields = new HttpFields();
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback);
}
else
@ -166,8 +163,7 @@ public class StreamCountTest extends AbstractTest
}
});
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame1 = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
CountDownLatch responseLatch = new CountDownLatch(1);

View File

@ -104,7 +104,7 @@ public class StreamResetTest extends AbstractTest
start(new ServerSessionListener.Adapter());
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
@ -142,7 +142,7 @@ public class StreamResetTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
@ -170,7 +170,7 @@ public class StreamResetTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
@ -210,7 +210,7 @@ public class StreamResetTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request1 = newRequest("GET", new HttpFields());
MetaData.Request request1 = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame1 = new HeadersFrame(request1, null, false);
FuturePromise<Stream> promise1 = new FuturePromise<>();
final CountDownLatch stream1HeadersLatch = new CountDownLatch(1);
@ -233,7 +233,7 @@ public class StreamResetTest extends AbstractTest
Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
assertTrue(stream1HeadersLatch.await(5, TimeUnit.SECONDS));
MetaData.Request request2 = newRequest("GET", new HttpFields());
MetaData.Request request2 = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame2 = new HeadersFrame(request2, null, false);
FuturePromise<Stream> promise2 = new FuturePromise<>();
final CountDownLatch stream2DataLatch = new CountDownLatch(1);
@ -317,7 +317,7 @@ public class StreamResetTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
client.newStream(frame, new FuturePromise<>(), new Stream.Listener.Adapter()
{
@ -404,7 +404,7 @@ public class StreamResetTest extends AbstractTest
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
client.newStream(frame, new FuturePromise<>(), new Stream.Listener.Adapter()
{
@ -434,7 +434,7 @@ public class StreamResetTest extends AbstractTest
start(new EmptyHttpServlet());
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter());
@ -501,7 +501,7 @@ public class StreamResetTest extends AbstractTest
{
phaser.set(new CountDownLatch(1));
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter()
@ -532,7 +532,7 @@ public class StreamResetTest extends AbstractTest
}
// Send one more request to consume the whole session flow control window, then reset it.
MetaData.Request request = newRequest("GET", "/x", new HttpFields());
MetaData.Request request = newRequest("GET", "/x", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
// This request will get no event from the server since it's reset by the client.
@ -585,7 +585,7 @@ public class StreamResetTest extends AbstractTest
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter());
@ -648,7 +648,7 @@ public class StreamResetTest extends AbstractTest
AtomicLong received = new AtomicLong();
CountDownLatch latch = new CountDownLatch(1);
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter()
@ -697,7 +697,7 @@ public class StreamResetTest extends AbstractTest
AtomicLong received = new AtomicLong();
CountDownLatch latch = new CountDownLatch(1);
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter()
@ -774,7 +774,7 @@ public class StreamResetTest extends AbstractTest
AtomicLong received = new AtomicLong();
CountDownLatch latch = new CountDownLatch(1);
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter()
@ -830,7 +830,7 @@ public class StreamResetTest extends AbstractTest
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter());
@ -906,8 +906,8 @@ public class StreamResetTest extends AbstractTest
// Max session HTTP/2 flow control window.
generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
HttpURI uri = new HttpURI("http", host, port, servletPath);
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields());
HttpURI uri = HttpURI.from("http", host, port, servletPath);
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
int streamId = 3;
HeadersFrame headersFrame = new HeadersFrame(streamId, request, null, true);
generator.control(lease, headersFrame);
@ -1009,8 +1009,8 @@ public class StreamResetTest extends AbstractTest
// Max session HTTP/2 flow control window.
generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
HttpURI uri = new HttpURI("http", host, port, servletPath + "/1");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields());
HttpURI uri = HttpURI.from("http", host, port, servletPath + "/1");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame headersFrame = new HeadersFrame(3, request, null, true);
generator.control(lease, headersFrame);
@ -1020,8 +1020,8 @@ public class StreamResetTest extends AbstractTest
waitUntilTCPCongested(exchanger.exchange(null));
// Send a second request.
uri = new HttpURI("http", host, port, servletPath + "/2");
request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields());
uri = HttpURI.from("http", host, port, servletPath + "/2");
request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
int streamId = 5;
headersFrame = new HeadersFrame(streamId, request, null, true);
generator.control(lease, headersFrame);

View File

@ -72,7 +72,7 @@ public class TrailersTest extends AbstractTest
{
MetaData.Request request = (MetaData.Request)frame.getMetaData();
assertFalse(frame.isEndStream());
assertTrue(request.getFields().containsKey("X-Request"));
assertTrue(request.getFields().contains("X-Request"));
return new Stream.Listener.Adapter()
{
@Override
@ -80,7 +80,7 @@ public class TrailersTest extends AbstractTest
{
MetaData trailer = frame.getMetaData();
assertTrue(frame.isEndStream());
assertTrue(trailer.getFields().containsKey("X-Trailer"));
assertTrue(trailer.getFields().contains("X-Trailer"));
latch.countDown();
}
};
@ -89,7 +89,7 @@ public class TrailersTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields requestFields = new HttpFields();
HttpFields.Mutable requestFields = HttpFields.build();
requestFields.put("X-Request", "true");
MetaData.Request request = newRequest("GET", requestFields);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
@ -98,7 +98,7 @@ public class TrailersTest extends AbstractTest
Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
// Send the trailers.
HttpFields trailerFields = new HttpFields();
HttpFields.Mutable trailerFields = HttpFields.build();
trailerFields.put("X-Trailer", "true");
MetaData trailers = new MetaData(HttpVersion.HTTP_2, trailerFields);
HeadersFrame trailerFrame = new HeadersFrame(stream.getId(), trailers, null, true);
@ -140,7 +140,7 @@ public class TrailersTest extends AbstractTest
Session session = newClient(new Session.Listener.Adapter());
HttpFields requestFields = new HttpFields();
HttpFields.Mutable requestFields = HttpFields.build();
requestFields.put("X-Request", "true");
MetaData.Request request = newRequest("GET", requestFields);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
@ -168,7 +168,7 @@ public class TrailersTest extends AbstractTest
// Send the trailers.
callback.thenRun(() ->
{
HttpFields trailerFields = new HttpFields();
HttpFields.Mutable trailerFields = HttpFields.build();
trailerFields.put("X-Trailer", "true");
MetaData trailers = new MetaData(HttpVersion.HTTP_2, trailerFields);
HeadersFrame trailerFrame = new HeadersFrame(stream.getId(), trailers, null, true);
@ -186,7 +186,7 @@ public class TrailersTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
HttpFields responseFields = new HttpFields();
HttpFields.Mutable responseFields = HttpFields.build();
responseFields.put("X-Response", "true");
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, responseFields);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false);
@ -195,7 +195,7 @@ public class TrailersTest extends AbstractTest
@Override
public void succeeded()
{
HttpFields trailerFields = new HttpFields();
HttpFields.Mutable trailerFields = HttpFields.build();
trailerFields.put("X-Trailer", "true");
MetaData trailer = new MetaData(HttpVersion.HTTP_2, trailerFields);
HeadersFrame trailerFrame = new HeadersFrame(stream.getId(), trailer, null, true);
@ -207,7 +207,7 @@ public class TrailersTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
@ -221,14 +221,14 @@ public class TrailersTest extends AbstractTest
{
MetaData.Response response = (MetaData.Response)frame.getMetaData();
assertEquals(HttpStatus.OK_200, response.getStatus());
assertTrue(response.getFields().containsKey("X-Response"));
assertTrue(response.getFields().contains("X-Response"));
assertFalse(frame.isEndStream());
responded = true;
}
else
{
MetaData trailer = frame.getMetaData();
assertTrue(trailer.getFields().containsKey("X-Trailer"));
assertTrue(trailer.getFields().contains("X-Trailer"));
assertTrue(frame.isEndStream());
latch.countDown();
}
@ -250,7 +250,7 @@ public class TrailersTest extends AbstractTest
{
Request jettyRequest = (Request)request;
Response jettyResponse = jettyRequest.getResponse();
HttpFields trailers = new HttpFields();
HttpFields.Mutable trailers = HttpFields.build();
jettyResponse.setTrailerFields(() ->
trailers.stream().collect(Collectors.toMap(HttpField::getName, HttpField::getValue)));
@ -262,7 +262,7 @@ public class TrailersTest extends AbstractTest
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
MetaData.Request request = newRequest("GET", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, true);
CountDownLatch latch = new CountDownLatch(1);
List<Frame> frames = new ArrayList<>();
@ -304,7 +304,7 @@ public class TrailersTest extends AbstractTest
start(new EmptyHttpServlet());
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("POST", new HttpFields());
MetaData.Request request = newRequest("POST", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(requestFrame, promise, new Stream.Listener.Adapter());
@ -316,7 +316,7 @@ public class TrailersTest extends AbstractTest
completable.thenRun(() ->
{
// Invalid trailer: cannot contain pseudo headers.
HttpFields trailerFields = new HttpFields();
HttpFields.Mutable trailerFields = HttpFields.build();
trailerFields.put(HttpHeader.C_METHOD, "GET");
MetaData trailer = new MetaData(HttpVersion.HTTP_2, trailerFields);
HeadersFrame trailerFrame = new HeadersFrame(stream.getId(), trailer, null, true);
@ -355,7 +355,7 @@ public class TrailersTest extends AbstractTest
CountDownLatch clientLatch = new CountDownLatch(1);
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("POST", new HttpFields());
MetaData.Request request = newRequest("POST", HttpFields.EMPTY);
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
session.newStream(requestFrame, promise, new Stream.Listener.Adapter()
@ -375,7 +375,7 @@ public class TrailersTest extends AbstractTest
// Disable checks for invalid headers.
((HTTP2Session)session).getGenerator().setValidateHpackEncoding(false);
// Invalid trailer: cannot contain pseudo headers.
HttpFields trailerFields = new HttpFields();
HttpFields.Mutable trailerFields = HttpFields.build();
trailerFields.put(HttpHeader.C_METHOD, "GET");
MetaData trailer = new MetaData(HttpVersion.HTTP_2, trailerFields);
HeadersFrame trailerFrame = new HeadersFrame(stream.getId(), trailer, null, true);

View File

@ -22,10 +22,12 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -78,6 +80,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
private static final Logger LOG = LoggerFactory.getLogger(HTTP2Session.class);
private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
private final StreamCreator streamCreator = new StreamCreator();
private final AtomicBiInteger streamCount = new AtomicBiInteger(); // Hi = closed, Lo = stream count
private final AtomicInteger localStreamIds = new AtomicInteger();
private final AtomicInteger lastRemoteStreamId = new AtomicInteger();
@ -532,6 +535,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
@Override
public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
{
streamCreator.newStream(frame, promise, listener);
/*
try
{
// Synchronization is necessary to atomically create
@ -555,6 +560,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
{
promise.failed(x);
}
*/
}
/**
@ -569,18 +575,14 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
*/
public IStream newLocalStream(HeadersFrame frameIn, HeadersFrame[] frameOut)
{
HeadersFrame frame = frameIn;
int streamId = frameIn.getStreamId();
if (streamId <= 0)
{
streamId = localStreamIds.getAndAdd(2);
PriorityFrame priority = frameIn.getPriority();
priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(),
priority.getWeight(), priority.isExclusive());
frame = new HeadersFrame(streamId, frameIn.getMetaData(), priority, frameIn.isEndStream());
}
HeadersFrame frame = streamCreator.prepareHeadersFrame(streamId, frameIn);
if (frameOut != null)
frameOut[0] = frame;
return createLocalStream(streamId, (MetaData.Request)frame.getMetaData());
}
@ -592,45 +594,13 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
@Override
public int priority(PriorityFrame frame, Callback callback)
{
int streamId = frame.getStreamId();
IStream stream = streams.get(streamId);
if (stream == null)
{
streamId = localStreamIds.getAndAdd(2);
frame = new PriorityFrame(streamId, frame.getParentStreamId(),
frame.getWeight(), frame.isExclusive());
}
control(stream, callback, frame);
return streamId;
return streamCreator.priority(frame, callback);
}
@Override
public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener)
{
try
{
// Synchronization is necessary to atomically create
// the stream id and enqueue the frame to be sent.
boolean queued;
synchronized (this)
{
int streamId = localStreamIds.getAndAdd(2);
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
IStream pushStream = createLocalStream(streamId, frame.getMetaData());
pushStream.setListener(listener);
ControlEntry entry = new ControlEntry(frame, pushStream, new StreamPromiseCallback(promise, pushStream));
queued = flusher.append(entry);
}
// Iterate outside the synchronized block.
if (queued)
flusher.iterate();
}
catch (Throwable x)
{
promise.failed(x);
}
streamCreator.push(frame, promise, listener);
}
@Override
@ -1731,4 +1701,167 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
terminate(failure);
}
}
/**
* SPEC: It is required that stream ids are monotonically increasing.
* Here we use a queue to atomically create the stream id and
* claim the slot in the queue. Concurrent threads will only
* flush up to the slot with a non-null entry to make sure
* frames are sent strictly in their stream id order.
* See https://tools.ietf.org/html/rfc7540#section-5.1.1.
*/
private class StreamCreator
{
private final Queue<Slot> slots = new ArrayDeque<>();
private Thread flushing;
private int priority(PriorityFrame frame, Callback callback)
{
Slot slot = new Slot();
int currentStreamId = frame.getStreamId();
int streamId = reserveSlot(slot, currentStreamId);
if (currentStreamId <= 0)
frame = new PriorityFrame(streamId, frame.getParentStreamId(), frame.getWeight(), frame.isExclusive());
assignSlotAndFlush(slot, new ControlEntry(frame, null, callback));
return streamId;
}
private void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
{
Slot slot = new Slot();
int currentStreamId = frame.getStreamId();
int streamId = reserveSlot(slot, currentStreamId);
frame = prepareHeadersFrame(streamId, frame);
try
{
IStream stream = HTTP2Session.this.createLocalStream(streamId, (MetaData.Request)frame.getMetaData());
stream.setListener(listener);
stream.process(new PrefaceFrame(), Callback.NOOP);
assignSlotAndFlush(slot, new ControlEntry(frame, stream, new StreamPromiseCallback(promise, stream)));
}
catch (Throwable x)
{
releaseSlotFlushAndFail(slot, promise, x);
}
}
private HeadersFrame prepareHeadersFrame(int streamId, HeadersFrame frame)
{
if (frame.getStreamId() <= 0)
{
PriorityFrame priority = frame.getPriority();
priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(), priority.getWeight(), priority.isExclusive());
frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
}
return frame;
}
private void push(PushPromiseFrame frame, Promise<Stream> promise, Stream.Listener listener)
{
Slot slot = new Slot();
int streamId = reserveSlot(slot, 0);
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
try
{
IStream stream = HTTP2Session.this.createLocalStream(streamId, frame.getMetaData());
stream.setListener(listener);
assignSlotAndFlush(slot, new ControlEntry(frame, stream, new StreamPromiseCallback(promise, stream)));
}
catch (Throwable x)
{
releaseSlotFlushAndFail(slot, promise, x);
}
}
private void assignSlotAndFlush(Slot slot, ControlEntry entry)
{
// Every time a slot entry is assigned, we must flush.
slot.entry = entry;
flush();
}
private int reserveSlot(Slot slot, int streamId)
{
if (streamId <= 0)
{
synchronized (this)
{
streamId = localStreamIds.getAndAdd(2);
slots.offer(slot);
}
}
else
{
synchronized (this)
{
slots.offer(slot);
}
}
return streamId;
}
private void releaseSlotFlushAndFail(Slot slot, Promise<Stream> promise, Throwable x)
{
synchronized (this)
{
slots.remove(slot);
}
flush();
promise.failed(x);
}
/**
* Flush goes over the entries of the slots queue to flush the entries,
* until either one of the following two conditions is true:
* - The queue is empty.
* - It reaches a slot with a null entry.
* When a slot with a null entry is encountered, this means a concurrent thread reserved a slot
* but hasn't set its entry yet. Since entries must be flushed in order, the thread encountering
* the null entry must bail out and it is up to the concurrent thread to finish up flushing.
* Note that only one thread can flush at any one time, if two threads happen to call flush
* concurrently, one will do the work while the other will bail out, so it is safe that all
* threads call flush after they're done reserving a slot and setting the entry.
*/
private void flush()
{
Thread thread = Thread.currentThread();
boolean queued = false;
while (true)
{
ControlEntry entry;
synchronized (this)
{
if (flushing == null)
flushing = thread;
else if (flushing != thread)
return; // Another thread is flushing.
Slot slot = slots.peek();
entry = slot == null ? null : slot.entry;
if (entry == null)
{
flushing = null;
// No more slots or null entry, so we may iterate on the flusher.
break;
}
slots.poll();
}
queued |= flusher.append(entry);
}
if (queued)
flusher.iterate();
}
private class Slot
{
private volatile ControlEntry entry;
}
}
}

View File

@ -306,7 +306,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa
HttpFields fields = metaData.getFields();
long length = -1;
if (fields != null && !HttpMethod.CONNECT.is(request.getMethod()))
length = fields.getLongField(HttpHeader.CONTENT_LENGTH.asString());
length = fields.getLongField(HttpHeader.CONTENT_LENGTH);
dataLength = length >= 0 ? length : Long.MIN_VALUE;
}

View File

@ -26,6 +26,11 @@ public class PushPromiseFrame extends Frame
private final int promisedStreamId;
private final MetaData.Request metaData;
public PushPromiseFrame(int streamId, MetaData.Request metaData)
{
this(streamId, 0, metaData);
}
public PushPromiseFrame(int streamId, int promisedStreamId, MetaData.Request metaData)
{
super(FrameType.PUSH_PROMISE);

View File

@ -71,10 +71,10 @@ public class ContinuationParseTest
for (int i = 0; i < 2; ++i)
{
int streamId = 13;
HttpFields fields = new HttpFields();
fields.put("Accept", "text/html");
fields.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
HttpFields fields = HttpFields.build()
.put("Accept", "text/html")
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateHeaders(lease, streamId, metaData, null, true);

View File

@ -51,10 +51,10 @@ public class HeadersGenerateParseTest
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
int streamId = 13;
HttpFields fields = new HttpFields();
fields.put("Accept", "text/html");
fields.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
HttpFields fields = HttpFields.build()
.put("Accept", "text/html")
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
final List<HeadersFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
@ -124,10 +124,10 @@ public class HeadersGenerateParseTest
for (int i = 0; i < 2; ++i)
{
int streamId = 13;
HttpFields fields = new HttpFields();
fields.put("Accept", "text/html");
fields.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
HttpFields.Mutable fields = HttpFields.build()
.put("Accept", "text/html")
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);

View File

@ -62,10 +62,10 @@ public class PushPromiseGenerateParseTest
int streamId = 13;
int promisedStreamId = 17;
HttpFields fields = new HttpFields();
fields.put("Accept", "text/html");
fields.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
HttpFields.Mutable fields = HttpFields.build()
.put("Accept", "text/html")
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
@ -115,10 +115,10 @@ public class PushPromiseGenerateParseTest
int streamId = 13;
int promisedStreamId = 17;
HttpFields fields = new HttpFields();
fields.put("Accept", "text/html");
fields.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
HttpFields.Mutable fields = HttpFields.build()
.put("Accept", "text/html")
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.http2.hpack.HpackException.SessionException;
public class MetaDataBuilder
{
private final int _maxSize;
private final HttpFields.Mutable _fields = HttpFields.build();
private int _size;
private Integer _status;
private String _method;
@ -39,7 +40,6 @@ public class MetaDataBuilder
private String _path;
private String _protocol;
private long _contentLength = Long.MIN_VALUE;
private HttpFields _fields = new HttpFields();
private HpackException.StreamException _streamException;
private boolean _request;
private boolean _response;
@ -162,14 +162,6 @@ public class MetaDataBuilder
break;
case HOST:
// :authority fields must come first. If we have one, ignore the host header as far as authority goes.
if (_authority == null)
{
if (field instanceof HostPortHttpField)
_authority = (HostPortHttpField)field;
else if (value != null)
_authority = new AuthorityHttpField(value);
}
_fields.add(field);
break;
@ -242,7 +234,7 @@ public class MetaDataBuilder
if (_request && _response)
throw new HpackException.StreamException("Request and Response headers");
HttpFields fields = _fields;
HttpFields.Mutable fields = _fields;
try
{
if (_request)
@ -260,7 +252,14 @@ public class MetaDataBuilder
if (isConnect)
return new MetaData.ConnectRequest(_scheme, _authority, _path, fields, _protocol);
else
return new MetaData.Request(_method, _scheme, _authority, _path, HttpVersion.HTTP_2, fields, _contentLength);
return new MetaData.Request(
_method,
_scheme == null ? HttpScheme.HTTP.asString() : _scheme.asString(),
_authority,
_path,
HttpVersion.HTTP_2,
fields,
_contentLength);
}
if (_response)
{
@ -273,7 +272,7 @@ public class MetaDataBuilder
}
finally
{
_fields = new HttpFields(Math.max(16, fields.size() + 5));
_fields.clear();
_request = false;
_response = false;
_status = null;

View File

@ -38,7 +38,7 @@ public class HpackEncoderTest
public void testUnknownFieldsContextManagement() throws Exception
{
HpackEncoder encoder = new HpackEncoder(38 * 5);
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
HttpField[] field =
{
@ -151,8 +151,8 @@ public class HpackEncoderTest
HpackEncoder encoder = new HpackEncoder(38 * 5);
ByteBuffer buffer = BufferUtil.allocate(4096);
HttpFields fields = new HttpFields();
fields.put("set-cookie", "some cookie value");
HttpFields.Mutable fields = HttpFields.build()
.put("set-cookie", "some cookie value");
// encode
BufferUtil.clearToFill(buffer);
@ -180,7 +180,7 @@ public class HpackEncoderTest
@Test
public void testFieldLargerThanTable() throws Exception
{
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
HpackEncoder encoder = new HpackEncoder(128);
ByteBuffer buffer0 = BufferUtil.allocate(4096);
@ -244,9 +244,9 @@ public class HpackEncoderTest
@Test
public void testResize() throws Exception
{
HttpFields fields = new HttpFields();
fields.add("host", "localhost0");
fields.add("cookie", "abcdefghij");
HttpFields fields = HttpFields.build()
.add("host", "localhost0")
.add("cookie", "abcdefghij");
HpackEncoder encoder = new HpackEncoder(4096);

View File

@ -107,7 +107,7 @@ public class HpackPerfTest
var kase = (Map<String, Object>)c;
Object[] headers = (Object[])kase.get("headers");
// System.err.println(" "+headers);
HttpFields fields = new HttpFields();
HttpFields.Mutable fields = HttpFields.build();
for (Object header : headers)
{
@SuppressWarnings("unchecked")

View File

@ -52,23 +52,25 @@ public class HpackTest
HpackDecoder decoder = new HpackDecoder(4096, 8192);
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
HttpFields fields0 = new HttpFields();
fields0.add(HttpHeader.CONTENT_TYPE, "text/html");
fields0.add(HttpHeader.CONTENT_LENGTH, "1024");
fields0.add(new HttpField(HttpHeader.CONTENT_ENCODING, (String)null));
fields0.add(ServerJetty);
fields0.add(XPowerJetty);
fields0.add(Date);
fields0.add(HttpHeader.SET_COOKIE, "abcdefghijklmnopqrstuvwxyz");
fields0.add("custom-key", "custom-value");
HttpFields.Mutable fields0 = HttpFields.build()
.add(HttpHeader.CONTENT_TYPE, "text/html")
.add(HttpHeader.CONTENT_LENGTH, "1024")
.add(new HttpField(HttpHeader.CONTENT_ENCODING, (String)null))
.add(ServerJetty)
.add(XPowerJetty)
.add(Date)
.add(HttpHeader.SET_COOKIE, "abcdefghijklmnopqrstuvwxyz")
.add("custom-key", "custom-value");
Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
Response decoded0 = (Response)decoder.decode(buffer);
original0.getFields().put(new HttpField(HttpHeader.CONTENT_ENCODING, ""));
assertMetaDataResponseSame(original0, decoded0);
Response nullToEmpty = new MetaData.Response(HttpVersion.HTTP_2, 200,
fields0.put(new HttpField(HttpHeader.CONTENT_ENCODING, "")));
assertMetaDataResponseSame(nullToEmpty, decoded0);
// Same again?
BufferUtil.clearToFill(buffer);
@ -76,16 +78,16 @@ public class HpackTest
BufferUtil.flipToFlush(buffer, 0);
Response decoded0b = (Response)decoder.decode(buffer);
assertMetaDataResponseSame(original0, decoded0b);
assertMetaDataResponseSame(nullToEmpty, decoded0b);
HttpFields fields1 = new HttpFields();
fields1.add(HttpHeader.CONTENT_TYPE, "text/plain");
fields1.add(HttpHeader.CONTENT_LENGTH, "1234");
fields1.add(HttpHeader.CONTENT_ENCODING, " ");
fields1.add(ServerJetty);
fields1.add(XPowerJetty);
fields1.add(Date);
fields1.add("Custom-Key", "Other-Value");
HttpFields.Mutable fields1 = HttpFields.build()
.add(HttpHeader.CONTENT_TYPE, "text/plain")
.add(HttpHeader.CONTENT_LENGTH, "1234")
.add(HttpHeader.CONTENT_ENCODING, " ")
.add(ServerJetty)
.add(XPowerJetty)
.add(Date)
.add("Custom-Key", "Other-Value");
Response original1 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields1);
// Same again?
@ -105,9 +107,9 @@ public class HpackTest
HpackDecoder decoder = new HpackDecoder(4096, 164);
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
HttpFields fields0 = new HttpFields();
fields0.add("1234567890", "1234567890123456789012345678901234567890");
fields0.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
HttpFields fields0 = HttpFields.build()
.add("1234567890", "1234567890123456789012345678901234567890")
.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0);
BufferUtil.clearToFill(buffer);
@ -117,10 +119,10 @@ public class HpackTest
assertMetaDataSame(original0, decoded0);
HttpFields fields1 = new HttpFields();
fields1.add("1234567890", "1234567890123456789012345678901234567890");
fields1.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
fields1.add("x", "y");
HttpFields fields1 = HttpFields.build()
.add("1234567890", "1234567890123456789012345678901234567890")
.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR")
.add("x", "y");
MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1);
BufferUtil.clearToFill(buffer);
@ -144,10 +146,10 @@ public class HpackTest
HpackDecoder decoder = new HpackDecoder(4096, 8192);
ByteBuffer buffer = BufferUtil.allocate(16 * 1024);
HttpFields fields0 = new HttpFields();
HttpFields fields0 = HttpFields.build()
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
fields0.add("Cookie", "[\uD842\uDF9F]");
fields0.add("custom-key", "[\uD842\uDF9F]");
.add("Cookie", "[\uD842\uDF9F]")
.add("custom-key", "[\uD842\uDF9F]");
Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0);
BufferUtil.clearToFill(buffer);
@ -167,9 +169,9 @@ public class HpackTest
String longEnoughToBeEvicted = "012345678901234567890123456789012345678901234567890";
HttpFields fields0 = new HttpFields();
fields0.add(longEnoughToBeEvicted, "value");
fields0.add("foo", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
HttpFields fields0 = HttpFields.build()
.add(longEnoughToBeEvicted, "value")
.add("foo", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0);
BufferUtil.clearToFill(buffer);
@ -184,9 +186,9 @@ public class HpackTest
assertMetaDataSame(original0, decoded0);
HttpFields fields1 = new HttpFields();
fields1.add(longEnoughToBeEvicted, "other_value");
fields1.add("x", "y");
HttpFields fields1 = HttpFields.build()
.add(longEnoughToBeEvicted, "other_value")
.add("x", "y");
MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1);
BufferUtil.clearToFill(buffer);
@ -207,15 +209,15 @@ public class HpackTest
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
HttpFields input = new HttpFields();
input.put(HttpHeader.ACCEPT, "*");
input.put(HttpHeader.CONNECTION, "TE, Upgrade, Custom");
input.put("Custom", "Pizza");
input.put(HttpHeader.KEEP_ALIVE, "true");
input.put(HttpHeader.PROXY_CONNECTION, "foo");
input.put(HttpHeader.TE, "1234567890abcdef");
input.put(HttpHeader.TRANSFER_ENCODING, "chunked");
input.put(HttpHeader.UPGRADE, "gold");
HttpFields input = HttpFields.build()
.add(HttpHeader.ACCEPT, "*")
.add(HttpHeader.CONNECTION, "TE, Upgrade, Custom")
.add("Custom", "Pizza")
.add(HttpHeader.KEEP_ALIVE, "true")
.add(HttpHeader.PROXY_CONNECTION, "foo")
.add(HttpHeader.TE, "1234567890abcdef")
.add(HttpHeader.TRANSFER_ENCODING, "chunked")
.add(HttpHeader.UPGRADE, "gold");
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);
@ -234,12 +236,12 @@ public class HpackTest
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
HttpFields input = new HttpFields();
input.put(HttpHeader.CONNECTION, "TE");
String teValue = "trailers";
input.put(HttpHeader.TE, teValue);
String trailerValue = "Custom";
input.put(HttpHeader.TRAILER, trailerValue);
HttpFields input = HttpFields.build()
.add(HttpHeader.CONNECTION, "TE")
.add(HttpHeader.TE, teValue)
.add(HttpHeader.TRAILER, trailerValue);
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);
@ -259,9 +261,9 @@ public class HpackTest
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
HttpFields input = new HttpFields();
input.put(":status", "200");
input.put(":custom", "special");
HttpFields input = HttpFields.build()
.add(":status", "200")
.add(":custom", "special");
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);

View File

@ -61,7 +61,7 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S
private final AtomicBoolean closed = new AtomicBoolean();
private final AtomicInteger sweeps = new AtomicInteger();
private final Session session;
private boolean recycleHttpChannels;
private boolean recycleHttpChannels = true;
public HttpConnectionOverHTTP2(HttpDestination destination, Session session)
{
@ -105,7 +105,7 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S
// In case of HTTP/1.1 upgrade to HTTP/2, the request is HTTP/1.1
// (with upgrade) for a resource, and the response is HTTP/2.
// Create the implicit stream#1 so that it can receive the HTTP/2 response.
MetaData.Request metaData = new MetaData.Request(request.getMethod(), new HttpURI(request.getURI()), HttpVersion.HTTP_2, request.getHeaders());
MetaData.Request metaData = new MetaData.Request(request.getMethod(), HttpURI.from(request.getURI()), HttpVersion.HTTP_2, request.getHeaders());
// We do not support upgrade requests with content, so endStream=true.
HeadersFrame frame = new HeadersFrame(metaData, null, true);
IStream stream = ((HTTP2Session)session).newLocalStream(frame, null);

View File

@ -78,11 +78,14 @@ public class HttpSenderOverHTTP2 extends HttpSender
else
{
String path = relativize(request.getPath());
HttpURI uri = HttpURI.createHttpURI(request.getScheme(), request.getHost(), request.getPort(), path, null, request.getQuery(), null);
metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders());
HttpURI uri = HttpURI.build()
.scheme(request.getScheme())
.host(request.getHost())
.port(request.getPort())
.path(path)
.query(request.getQuery());
metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders(), -1, request.getTrailers());
}
Supplier<HttpFields> trailerSupplier = request.getTrailers();
metaData.setTrailerSupplier(trailerSupplier);
HeadersFrame headersFrame;
Promise<Stream> promise;
@ -93,6 +96,7 @@ public class HttpSenderOverHTTP2 extends HttpSender
}
else
{
Supplier<HttpFields> trailerSupplier = request.getTrailers();
if (BufferUtil.isEmpty(contentBuffer) && lastContent)
{
HttpFields trailers = trailerSupplier == null ? null : trailerSupplier.get();

View File

@ -155,7 +155,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), metaData, null, false), new Callback()
{
@Override
@ -232,7 +232,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
}
else
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
return null;
@ -489,7 +489,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
try
{
// Response.
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(request.getStreamId(), metaData, null, true);
generator.control(lease, response);
writeFrames();
@ -563,7 +563,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
int streamId = stream.getId();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.NO_CONTENT_204, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.NO_CONTENT_204, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(streamId, response, null, false);
Callback.Completable callback = new Callback.Completable();
stream.headers(responseFrame, callback);
@ -592,8 +592,8 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
// Disable checks for invalid headers.
((HTTP2Session)stream.getSession()).getGenerator().setValidateHpackEncoding(false);
// Produce an invalid HPACK block by adding a request pseudo-header to the response.
HttpFields fields = new HttpFields();
fields.put(":method", "get");
HttpFields fields = HttpFields.build()
.put(":method", "get");
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, fields, 0);
int streamId = stream.getId();
HeadersFrame responseFrame = new HeadersFrame(streamId, response, null, false);

View File

@ -62,15 +62,15 @@ public class PushedResourcesTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
HttpURI pushURI = new HttpURI("http://localhost:" + connector.getLocalPort() + pushPath);
MetaData.Request pushRequest = new MetaData.Request(HttpMethod.GET.asString(), pushURI, HttpVersion.HTTP_2, new HttpFields());
stream.push(new PushPromiseFrame(stream.getId(), 0, pushRequest), new Promise.Adapter<>()
HttpURI pushURI = HttpURI.from("http://localhost:" + connector.getLocalPort() + pushPath);
MetaData.Request pushRequest = new MetaData.Request(HttpMethod.GET.asString(), pushURI, HttpVersion.HTTP_2, HttpFields.EMPTY);
stream.push(new PushPromiseFrame(stream.getId(), pushRequest), new Promise.Adapter<>()
{
@Override
public void succeeded(Stream pushStream)
{
// Just send the normal response and wait for the reset.
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
}, new Stream.Listener.Adapter()

View File

@ -64,7 +64,7 @@ public class RequestTrailersTest extends AbstractTest
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
stream.headers(responseFrame, Callback.NOOP);
return new Stream.Listener.Adapter()
@ -79,7 +79,7 @@ public class RequestTrailersTest extends AbstractTest
});
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
HttpFields trailers = new HttpFields();
HttpFields.Mutable trailers = HttpFields.build();
request.trailers(() -> trailers);
if (content != null)
request.body(new StringRequestContent(content));
@ -109,7 +109,7 @@ public class RequestTrailersTest extends AbstractTest
// trailers, but instead a DATA frame with endStream=true.
if (dataFrame.isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
stream.headers(responseFrame, Callback.NOOP);
}
@ -119,7 +119,7 @@ public class RequestTrailersTest extends AbstractTest
});
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
HttpFields trailers = new HttpFields();
HttpFields.Mutable trailers = HttpFields.build();
request.trailers(() -> trailers);
AsyncRequestContent content = new AsyncRequestContent();
request.body(content);
@ -158,7 +158,7 @@ public class RequestTrailersTest extends AbstractTest
// trailers, but instead a DATA frame with endStream=true.
if (dataFrame.isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
stream.headers(responseFrame, Callback.NOOP);
}
@ -168,7 +168,7 @@ public class RequestTrailersTest extends AbstractTest
});
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
HttpFields trailers = new HttpFields();
HttpFields.Mutable trailers = HttpFields.build();
request.trailers(() -> trailers);
AsyncRequestContent content = new AsyncRequestContent();
request.body(content);

View File

@ -88,8 +88,8 @@ public class ResponseTrailerTest extends AbstractTest
http2Client.connect(address, new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
HttpURI uri = new HttpURI("http://" + host + ":" + port + "/");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields());
HttpURI uri = HttpURI.from("http://" + host + ":" + port + "/");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame frame = new HeadersFrame(request, null, true);
BlockingQueue<HeadersFrame> headers = new LinkedBlockingQueue<>();
CountDownLatch latch = new CountDownLatch(1);

View File

@ -71,7 +71,7 @@ public class HTTP2CServerConnectionFactory extends HTTP2ServerConnectionFactory
}
@Override
public Connection upgradeConnection(Connector connector, EndPoint endPoint, Request request, HttpFields response101) throws BadMessageException
public Connection upgradeConnection(Connector connector, EndPoint endPoint, Request request, HttpFields.Mutable response101) throws BadMessageException
{
if (LOG.isDebugEnabled())
LOG.debug("{} upgrading {}{}{}", this, request, System.lineSeparator(), request.getFields());

View File

@ -94,7 +94,7 @@ public class HTTP2ServerConnection extends HTTP2Connection
private final AtomicLong totalResponses = new AtomicLong();
private final ServerSessionListener listener;
private final HttpConfiguration httpConfig;
private boolean recycleHttpChannels;
private boolean recycleHttpChannels = true;
public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener)
{
@ -320,7 +320,7 @@ public class HTTP2ServerConnection extends HTTP2Connection
}
}
public boolean upgrade(Request request, HttpFields responseFields)
public boolean upgrade(Request request, HttpFields.Mutable responseFields)
{
if (HttpMethod.PRI.is(request.getMethod()))
{
@ -356,7 +356,7 @@ public class HTTP2ServerConnection extends HTTP2Connection
// This is the settings from the HTTP2-Settings header.
upgradeFrames.add(settingsFrame);
// Remember the request to send a response.
upgradeFrames.add(new HeadersFrame(1, new Request(request), null, true));
upgradeFrames.add(new HeadersFrame(1, request, null, true));
}
return true;
}

View File

@ -110,21 +110,9 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
MetaData.Request request = (MetaData.Request)frame.getMetaData();
HttpFields fields = request.getFields();
// HTTP/2 sends the Host header as the :authority
// pseudo-header, so we need to synthesize a Host header.
if (!fields.contains(HttpHeader.HOST))
{
String authority = request.getURI().getAuthority();
if (authority != null)
{
// Lower-case to be consistent with other HTTP/2 headers.
fields.put("host", authority);
}
}
_expect100Continue = fields.contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
HttpFields response = getResponse().getHttpFields();
HttpFields.Mutable response = getResponse().getHttpFields();
if (getHttpConfiguration().getSendServerVersion())
response.add(SERVER_VERSION);
if (getHttpConfiguration().getSendXPoweredBy())
@ -161,6 +149,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
}
catch (BadMessageException x)
{
if (LOG.isDebugEnabled())
LOG.debug("onRequest", x);
onBadMessage(x);
return null;
}

View File

@ -114,7 +114,14 @@ public class HttpTransportOverHTTP2 implements HttpTransport
long contentLength = response.getContentLength();
if (contentLength < 0)
{
response.setContentLength(realContentLength);
response = new MetaData.Response(
response.getHttpVersion(),
response.getStatus(),
response.getReason(),
response.getFields(),
realContentLength,
response.getTrailerSupplier()
);
}
else if (hasContent && contentLength != realContentLength)
{
@ -265,7 +272,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
if (LOG.isDebugEnabled())
LOG.debug("HTTP/2 Push {}", request);
stream.push(new PushPromiseFrame(stream.getId(), 0, request), new Promise<>()
stream.push(new PushPromiseFrame(stream.getId(), request), new Promise<>()
{
@Override
public void succeeded(Stream pushStream)

View File

@ -83,7 +83,7 @@ public class AbstractServerTest
String host = "localhost";
int port = connector.getLocalPort();
String authority = host + ":" + port;
return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields);
return new MetaData.Request(method, HttpScheme.HTTP.asString(), new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields, -1);
}
@AfterEach

View File

@ -65,7 +65,7 @@ public class CloseTest extends AbstractServerTest
try
{
sessionRef.set(stream.getSession());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
// Reply with HEADERS.
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
closeLatch.await(5, TimeUnit.SECONDS);
@ -81,7 +81,7 @@ public class CloseTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
@ -133,7 +133,7 @@ public class CloseTest extends AbstractServerTest
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
sessionRef.set(stream.getSession());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
return null;
}
@ -142,7 +142,7 @@ public class CloseTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(lease, new GoAwayFrame(1, ErrorCode.NO_ERROR.code, "OK".getBytes("UTF-8")));
@ -198,7 +198,7 @@ public class CloseTest extends AbstractServerTest
{
stream.setIdleTimeout(10 * idleTimeout);
sessionRef.set(stream.getSession());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
stream.getSession().close(ErrorCode.NO_ERROR.code, "OK", Callback.NOOP);
return null;
@ -209,7 +209,7 @@ public class CloseTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))

View File

@ -195,7 +195,7 @@ public class HTTP2CServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), "/two", HttpVersion.HTTP_2, new HttpFields());
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:" + connector.getLocalPort()), "/two", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
generator.control(lease, new HeadersFrame(3, metaData, null, true));
for (ByteBuffer buffer : lease.getByteBuffers())
{
@ -233,7 +233,7 @@ public class HTTP2CServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), "/test", HttpVersion.HTTP_2, new HttpFields());
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:" + connector.getLocalPort()), "/test", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))

View File

@ -82,7 +82,7 @@ public class HTTP2ServerTest extends AbstractServerTest
startServer(new HttpServlet() {});
// No preface bytes.
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
@ -127,7 +127,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
@ -185,7 +185,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
@ -361,7 +361,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector2.getLocalPort()))
{
@ -399,7 +399,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
@ -428,7 +428,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
return lease;
});
@ -443,7 +443,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, priority, true));
return lease;
});
@ -457,7 +457,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
// Take the HeadersFrame header and set the length to zero.
List<ByteBuffer> buffers = lease.getByteBuffers();
@ -479,7 +479,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, priority, true));
// Take the HeadersFrame header and set the length to just the priority frame.
List<ByteBuffer> buffers = lease.getByteBuffers();
@ -500,7 +500,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
// Take the ContinuationFrame header, duplicate it, and set the length to zero.
List<ByteBuffer> buffers = lease.getByteBuffers();
@ -524,7 +524,7 @@ public class HTTP2ServerTest extends AbstractServerTest
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", new HttpFields());
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
// Take the last CONTINUATION frame and reset the flag.
List<ByteBuffer> buffers = lease.getByteBuffers();
@ -562,7 +562,7 @@ public class HTTP2ServerTest extends AbstractServerTest
serverLatch.countDown();
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, HttpFields.EMPTY);
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return null;

View File

@ -64,7 +64,7 @@ public class DefaultJettyAtJettyHomeHelper
/**
* Set of config files to apply to a jetty Server instance if none are supplied by SYS_PROP_JETTY_ETC_FILES
*/
public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml";
public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deploy.xml";
/**
* Default location within bundle of a jetty home dir.

View File

@ -104,7 +104,7 @@ public class TestOSGiUtil
}
xmlConfigs.append(new File(etc, jettySelectorFileName).toURI());
xmlConfigs.append(";");
xmlConfigs.append(new File(etc, "jetty-deployer.xml").toURI());
xmlConfigs.append(new File(etc, "jetty-deploy.xml").toURI());
xmlConfigs.append(";");
xmlConfigs.append(new File(etc, "jetty-testrealm.xml").toURI());

View File

@ -44,6 +44,7 @@ import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpScheme;
@ -468,7 +469,7 @@ public abstract class AbstractProxyServlet extends HttpServlet
protected void copyRequestHeaders(HttpServletRequest clientRequest, Request proxyRequest)
{
// First clear possibly existing headers, as we are going to copy those from the client request.
proxyRequest.getHeaders().clear();
HttpFields.Mutable newHeaders = HttpFields.build();
Set<String> headersToRemove = findConnectionHeaders(clientRequest);
@ -490,13 +491,15 @@ public abstract class AbstractProxyServlet extends HttpServlet
{
String headerValue = headerValues.nextElement();
if (headerValue != null)
proxyRequest.header(headerName, headerValue);
newHeaders.add(headerName, headerValue);
}
}
// Force the Host header if configured
if (_hostHeader != null)
proxyRequest.header(HttpHeader.HOST, _hostHeader);
newHeaders.add(HttpHeader.HOST, _hostHeader);
proxyRequest.set(newHeaders);
}
protected Set<String> findConnectionHeaders(HttpServletRequest clientRequest)

View File

@ -439,7 +439,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet
@Override
public void onHeaders(Response serverResponse)
{
contentLength = serverResponse.getHeaders().getLongField(HttpHeader.CONTENT_LENGTH.asString());
contentLength = serverResponse.getHeaders().getLongField(HttpHeader.CONTENT_LENGTH);
onServerResponseHeaders(clientRequest, proxyResponse, serverResponse);
}

View File

@ -1497,7 +1497,7 @@ public class AsyncMiddleManServletTest
.timeout(5, TimeUnit.SECONDS)
.send();
assertEquals(200, response.getStatus());
assertTrue(response.getHeaders().containsKey(PROXIED_HEADER));
assertTrue(response.getHeaders().contains(PROXIED_HEADER));
}
private Path prepareTargetTestsDir() throws IOException

View File

@ -308,7 +308,7 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest
HttpTester.Input in = HttpTester.from(input);
HttpTester.Response response = HttpTester.parseResponse(in);
assertEquals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407, response.getStatus());
assertTrue(response.containsKey("Proxy-Authenticate".toLowerCase(Locale.ENGLISH)));
assertTrue(response.contains("Proxy-Authenticate".toLowerCase(Locale.ENGLISH)));
// Socket should be closed
assertEquals(-1, input.read());

Some files were not shown because too many files have changed in this diff Show More