Merge remote-tracking branch 'origin/jetty-12.0.x' into fix/12.0.x/bundle-copyright-update

This commit is contained in:
Joakim Erdfelt 2023-09-18 13:21:53 -05:00
commit 460fdc60ec
No known key found for this signature in database
GPG Key ID: 2D0E1FB8FE4B68B4
245 changed files with 1940 additions and 352 deletions

View File

@ -21,11 +21,13 @@ import java.net.URI;
public interface AuthenticationStore
{
/**
* Add the {@link Authentication} to add.
* @param authentication the {@link Authentication} to add
*/
public void addAuthentication(Authentication authentication);
/**
* Remove an Authentication.
* @param authentication the {@link Authentication} to remove
*/
public void removeAuthentication(Authentication authentication);
@ -48,11 +50,13 @@ public interface AuthenticationStore
public Authentication findAuthentication(String type, URI uri, String realm);
/**
* Add the {@link Authentication.Result} to add.
* @param result the {@link Authentication.Result} to add
*/
public void addAuthenticationResult(Authentication.Result result);
/**
* Remove and Authentication Result
* @param result the {@link Authentication.Result} to remove
*/
public void removeAuthenticationResult(Authentication.Result result);

View File

@ -171,6 +171,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the {@link SslContextFactory.Client} that manages TLS encryption.
* @param sslContextFactory the {@link SslContextFactory.Client} that manages TLS encryption
*/
public void setSslContextFactory(SslContextFactory.Client sslContextFactory)
@ -260,6 +261,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the cookie store associated with this instance.
* @return the cookie store associated with this instance
*/
public HttpCookieStore getHttpCookieStore()
@ -268,6 +270,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the cookie store associated with this instance.
* @param cookieStore the cookie store associated with this instance
*/
public void setHttpCookieStore(HttpCookieStore cookieStore)
@ -285,6 +288,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the authentication store associated with this instance.
* @return the authentication store associated with this instance
*/
public AuthenticationStore getAuthenticationStore()
@ -293,6 +297,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the authentication store associated with this instance.
* @param authenticationStore the authentication store associated with this instance
*/
public void setAuthenticationStore(AuthenticationStore authenticationStore)
@ -574,6 +579,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the {@link ByteBufferPool} of this HttpClient.
* @return the {@link ByteBufferPool} of this HttpClient
*/
public ByteBufferPool getByteBufferPool()
@ -582,6 +588,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the {@link ByteBufferPool} of this HttpClient.
* @param byteBufferPool the {@link ByteBufferPool} of this HttpClient
*/
public void setByteBufferPool(ByteBufferPool byteBufferPool)
@ -661,6 +668,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the max time, in milliseconds, a connection can be idle (that is, without traffic of bytes in either direction).
* @param idleTimeout the max time, in milliseconds, a connection can be idle (that is, without traffic of bytes in either direction)
*/
public void setIdleTimeout(long idleTimeout)
@ -688,6 +696,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the "User-Agent" HTTP field of this HttpClient.
* @return the "User-Agent" HTTP field of this HttpClient
*/
public HttpField getUserAgentField()
@ -696,6 +705,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the "User-Agent" HTTP header string of this HttpClient.
* @param agent the "User-Agent" HTTP header string of this HttpClient
*/
public void setUserAgentField(HttpField agent)
@ -725,6 +735,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the {@link Executor} of this HttpClient.
* @return the {@link Executor} of this HttpClient
*/
public Executor getExecutor()
@ -733,6 +744,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the {@link Executor} of this HttpClient.
* @param executor the {@link Executor} of this HttpClient
*/
public void setExecutor(Executor executor)
@ -741,6 +753,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the {@link Scheduler} of this HttpClient.
* @return the {@link Scheduler} of this HttpClient
*/
public Scheduler getScheduler()
@ -749,6 +762,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the {@link Scheduler} of this HttpClient.
* @param scheduler the {@link Scheduler} of this HttpClient
*/
public void setScheduler(Scheduler scheduler)
@ -757,6 +771,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the {@link SocketAddressResolver} of this HttpClient.
* @return the {@link SocketAddressResolver} of this HttpClient
*/
public SocketAddressResolver getSocketAddressResolver()
@ -765,6 +780,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the {@link SocketAddressResolver} of this HttpClient.
* @param resolver the {@link SocketAddressResolver} of this HttpClient
*/
public void setSocketAddressResolver(SocketAddressResolver resolver)
@ -837,6 +853,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the size of the buffer (in bytes) used to write requests.
* @param requestBufferSize the size of the buffer (in bytes) used to write requests
*/
public void setRequestBufferSize(int requestBufferSize)
@ -854,6 +871,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the size of the buffer used to read responses.
* @param responseBufferSize the size of the buffer used to read responses
*/
public void setResponseBufferSize(int responseBufferSize)
@ -1010,6 +1028,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the default content type for request content.
* @param contentType the default content type for request content
*/
public void setDefaultRequestContentType(String contentType)
@ -1027,6 +1046,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set whether to use direct ByteBuffers for reading.
* @param useInputDirectByteBuffers whether to use direct ByteBuffers for reading
*/
public void setUseInputDirectByteBuffers(boolean useInputDirectByteBuffers)
@ -1044,6 +1064,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set whether to use direct ByteBuffers for writing.
* @param useOutputDirectByteBuffers whether to use direct ByteBuffers for writing
*/
public void setUseOutputDirectByteBuffers(boolean useOutputDirectByteBuffers)
@ -1061,6 +1082,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Set the max size in bytes of the response headers.
* @param maxResponseHeadersSize the max size in bytes of the response headers
*/
public void setMaxResponseHeadersSize(int maxResponseHeadersSize)
@ -1069,6 +1091,7 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* Get the forward proxy configuration.
* @return the forward proxy configuration
*/
public ProxyConfiguration getProxyConfiguration()

View File

@ -96,6 +96,7 @@ public interface HttpClientTransport extends ClientConnectionFactory
public ConnectionPool.Factory getConnectionPoolFactory();
/**
* Set the factory for ConnectionPool instances.
* @param factory the factory for ConnectionPool instances
*/
public void setConnectionPoolFactory(ConnectionPool.Factory factory);

View File

@ -24,6 +24,7 @@ package org.eclipse.jetty.client;
public interface ProtocolHandler
{
/**
* Get a unique name among protocol handlers.
* @return a unique name among protocol handlers
*/
public String getName();

View File

@ -56,6 +56,7 @@ public class Result
}
/**
* Get the request object.
* @return the request object
*/
public Request getRequest()
@ -64,6 +65,7 @@ public class Result
}
/**
* Get the request failure, if any.
* @return the request failure, if any
*/
public Throwable getRequestFailure()
@ -72,6 +74,7 @@ public class Result
}
/**
* Get the response object.
* @return the response object
*/
public Response getResponse()
@ -80,6 +83,7 @@ public class Result
}
/**
* Get the response failure, if any.
* @return the response failure, if any
*/
public Throwable getResponseFailure()
@ -104,6 +108,7 @@ public class Result
}
/**
* Get the response failure, if any, otherwise the request failure, if any.
* @return the response failure, if any, otherwise the request failure, if any
*/
public Throwable getFailure()

View File

@ -77,6 +77,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Get the user name of the user to login.
* @return the user name of the user to login
*/
public String getUserName()
@ -85,6 +86,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Set user name of the user to login.
* @param userName user name of the user to login
*/
public void setUserName(String userName)
@ -93,6 +95,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Get the password of the user to login.
* @return the password of the user to login
*/
public String getUserPassword()
@ -110,6 +113,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Get the path of the keyTab file with the user credentials.
* @return the path of the keyTab file with the user credentials
*/
public Path getUserKeyTabPath()
@ -127,6 +131,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Get the name of the service to use.
* @return the name of the service to use
*/
public String getServiceName()
@ -135,6 +140,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Set the name of the service to use.
* @param serviceName the name of the service to use
*/
public void setServiceName(String serviceName)
@ -160,6 +166,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Get the path of the ticket cache file.
* @return the path of the ticket cache file
*/
public Path getTicketCachePath()
@ -185,6 +192,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
}
/**
* Set whether to renew the ticket granting ticket.
* @param renewTGT whether to renew the ticket granting ticket
*/
public void setRenewTGT(boolean renewTGT)

View File

@ -21,9 +21,6 @@ contextHandlerClass?=org.eclipse.jetty.server.handler.ResourceHandler$ResourceCo
[ini-template]
## Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps
## - OR -
## Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps
## Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1

View File

@ -104,6 +104,7 @@ public class FastCGIProxyHandler extends ProxyHandler.Reverse
}
/**
* Get the root directory path of the FastCGI files.
* @return the root directory path of the FastCGI files
*/
public String getScriptRoot()

View File

@ -19,6 +19,7 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@ -27,6 +28,8 @@ import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpPrincipal;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.QuotedCSV;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
@ -36,6 +39,24 @@ import org.eclipse.jetty.server.Response;
*/
public class JettyHttpExchangeDelegate extends HttpExchange
{
/**
* Set of headers that RFC9110 says will not have a value list
*/
private static final EnumSet<HttpHeader> SINGLE_VALUE_HEADERS =
EnumSet.of(
HttpHeader.AUTHORIZATION,
HttpHeader.CONTENT_LENGTH,
HttpHeader.DATE,
HttpHeader.EXPIRES,
HttpHeader.HOST,
HttpHeader.IF_MODIFIED_SINCE,
HttpHeader.IF_UNMODIFIED_SINCE,
HttpHeader.IF_RANGE,
HttpHeader.LAST_MODIFIED,
HttpHeader.LOCATION,
HttpHeader.REFERER,
HttpHeader.RETRY_AFTER,
HttpHeader.USER_AGENT);
private final HttpContext _httpContext;
private final Request _request;
@ -68,10 +89,23 @@ public class JettyHttpExchangeDelegate extends HttpExchange
for (HttpField field : _request.getHeaders())
{
if (field.getValue() == null)
String rawValue = field.getValue();
if (rawValue == null)
continue;
for (String value : field.getValues())
headers.add(field.getName(), value);
HttpHeader header = field.getHeader();
if (header == null || !SINGLE_VALUE_HEADERS.contains(header))
{
// Using raw QuotedCSV here to preserve quotes (which HttpField.getValues() doesn't do)
QuotedCSV quotedCSV = new QuotedCSV(true, rawValue);
for (String value : quotedCSV.getValues())
headers.add(field.getName(), value);
}
else
{
headers.add(field.getName(), rawValue);
}
}
return headers;
}

View File

@ -15,13 +15,12 @@ package org.eclipse.jetty.http.spi;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import com.sun.net.httpserver.BasicAuthenticator;
import com.sun.net.httpserver.Headers;
@ -29,12 +28,20 @@ import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.client.AuthenticationStore;
import org.eclipse.jetty.client.BasicAuthentication;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
public class SPIServerTest
@ -44,9 +51,10 @@ public class SPIServerTest
LoggingUtil.init();
}
String host = "localhost";
HttpServer server;
int port;
private String host = "localhost";
private HttpServer server;
private int port;
private HttpClient client;
@BeforeEach
public void before() throws Exception
@ -55,13 +63,16 @@ public class SPIServerTest
server.start();
port = server.getAddress().getPort();
System.err.println(port);
client = new HttpClient();
client.start();
}
@AfterEach
public void after() throws Exception
{
server.stop(0);
LifeCycle.stop(client);
}
@Test
@ -81,13 +92,270 @@ public class SPIServerTest
}
});
URL url = new URL("http://localhost:" + port + "/");
assertThat(IO.toString(url.openConnection().getInputStream()), is("Hello"));
Request request = client.newRequest("localhost", port)
.scheme("http")
.method(HttpMethod.GET)
.path("/");
ContentResponse response = request.send();
assertThat(response.getStatus(), is(200));
assertThat(response.getHeaders().get("Content-Type"), is("text/plain"));
String body = response.getContentAsString();
assertThat(body, is("Hello"));
}
@Test
public void testComplexResponseMediaType() throws Exception
{
final String mediaType = "multipart/related;" +
"start=\"<a*b-c-d-e-f@example.com>\";" +
"type=\"application/xop+xml\";" +
"boundary=\"uuid:aa-bb-cc-dd-ee\";" +
"start-info=\"application/soap+xml;action=\\\"urn:xyz\\\"\"";
server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
{
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", mediaType);
exchange.sendResponseHeaders(200, 0);
OutputStream responseBody = exchange.getResponseBody();
responseBody.write("Hello".getBytes(StandardCharsets.ISO_8859_1));
responseBody.close();
}
});
Request request = client.newRequest("localhost", port)
.scheme("http")
.method(HttpMethod.GET)
.path("/");
ContentResponse response = request.send();
assertThat(response.getStatus(), is(200));
assertThat(response.getHeaders().get("Content-Type"), is(mediaType));
String body = response.getContentAsString();
assertThat(body, is("Hello"));
}
@Test
public void testComplexRequestMediaType() throws Exception
{
final String mediaType = "multipart/related;" +
"start=\"<a*b-c-d-e-f@example.com>\";" +
"type=\"application/xop+xml\";" +
"boundary=\"uuid:aa-bb-cc-dd-ee\";" +
"start-info=\"application/soap+xml;action=\\\"urn:xyz\\\"\"";
server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
{
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
Headers requestHeaders = exchange.getRequestHeaders();
List<String> mediaTypeValue = requestHeaders.get("Content-Type");
try (OutputStream responseBody = exchange.getResponseBody();
PrintStream out = new PrintStream(responseBody, true, StandardCharsets.UTF_8))
{
// should only have 1 entry, but joining together multiple in case of bad impl
out.print(String.join(",", mediaTypeValue));
}
}
});
Request request = client.newRequest("localhost", port)
.scheme("http")
.method(HttpMethod.GET)
.headers((headers) ->
headers.put("Content-Type", mediaType))
.path("/");
ContentResponse response = request.send();
assertThat(response.getStatus(), is(200));
String body = response.getContentAsString();
assertThat(body, is(mediaType));
}
@Test
public void testMultipleRequestHeaderMerging() throws Exception
{
server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
{
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
Headers requestHeaders = exchange.getRequestHeaders();
try (OutputStream responseBody = exchange.getResponseBody();
PrintStream out = new PrintStream(responseBody, true, StandardCharsets.UTF_8))
{
for (String name : requestHeaders.keySet().stream().sorted().toList())
{
out.printf("%s: %s%n", name, String.join(",", requestHeaders.get(name)));
}
}
}
});
// Sending this in the raw, as HttpURLConnection will not send multiple request headers with the same name
try (Socket socket = new Socket("localhost", port))
{
try (OutputStream output = socket.getOutputStream())
{
String request = """
GET / HTTP/1.1
Host: localhost
Connection: close
X-Action: Begin
X-Action: "Ongoing Behavior"
X-Action: Final
""";
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
HttpTester.Input input = HttpTester.from(socket.getInputStream());
HttpTester.Response response = HttpTester.parseResponse(input);
assertThat(response.getStatus(), is(200));
assertThat(response.getContent(), containsString("X-action: Begin,\"Ongoing Behavior\",Final"));
}
}
}
@Test
public void testRequestUserAgentHeader() throws Exception
{
// The `User-Agent` header that should ignore value list behaviors
final String ua = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36";
// The `Sec-Ch-Ua` header that should participate in value list behaviors
final String secua = "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\n";
server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
{
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
Headers requestheaders = exchange.getRequestHeaders();
try (OutputStream responseBody = exchange.getResponseBody();
PrintStream out = new PrintStream(responseBody, true, StandardCharsets.UTF_8))
{
// A `User-Agent` header, that should skip value list behaviors
String useragent = requestheaders.getFirst("User-Agent");
out.printf("User-Agent: %s%n", useragent);
// A `Sec-Ch-Ua` header, that should result in a value list
List<String> secuseragent = requestheaders.get("Sec-Ch-Ua");
int i = 0;
for (String value : secuseragent)
{
out.printf("Sec-Ch-Ua[%d]: %s%n", i++, value);
}
}
}
});
// Sending this in the raw, as HttpURLConnection will not send multiple request headers with the same name
try (Socket socket = new Socket("localhost", port))
{
try (OutputStream output = socket.getOutputStream())
{
String request = """
GET / HTTP/1.1
Host: localhost
Connection: close
User-Agent: %s
Sec-Ch-Ua: %s
""".formatted(ua, secua);
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
HttpTester.Input input = HttpTester.from(socket.getInputStream());
HttpTester.Response response = HttpTester.parseResponse(input);
assertThat(response.getStatus(), is(200));
String body = response.getContent();
assertThat(body, containsString("User-Agent: " + ua));
assertThat(body, containsString("Sec-Ch-Ua[0]: \"Chromium\";v=\"116\""));
assertThat(body, containsString("Sec-Ch-Ua[1]: \"Not)A;Brand\";v=\"24\""));
assertThat(body, containsString("Sec-Ch-Ua[2]: \"Google Chrome\";v=\"116\""));
}
}
}
@Test
public void testIfModifiedSinceHeader() throws Exception
{
final String since = "Sat, 29 Oct 1994 19:43:31 GMT";
server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
{
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
Headers requestheaders = exchange.getRequestHeaders();
try (OutputStream responseBody = exchange.getResponseBody();
PrintStream out = new PrintStream(responseBody, true, StandardCharsets.UTF_8))
{
// A `If-Modified-Since` header, that should skip value list behaviors
String ifmodified = requestheaders.getFirst("If-Modified-Since");
out.printf("If-Modified-Since: %s%n", ifmodified);
}
}
});
// Sending this in the raw, as HttpURLConnection will not send multiple request headers with the same name
try (Socket socket = new Socket("localhost", port))
{
try (OutputStream output = socket.getOutputStream())
{
String request = """
GET / HTTP/1.1
Host: localhost
Connection: close
If-Modified-Since: %s
""".formatted(since);
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
HttpTester.Input input = HttpTester.from(socket.getInputStream());
HttpTester.Response response = HttpTester.parseResponse(input);
assertThat(response.getStatus(), is(200));
String body = response.getContent();
assertThat(body, containsString("If-Modified-Since: " + since));
}
}
}
@Test
public void testAuth() throws Exception
{
final String testRealm = "Test";
final String testUsername = "username";
final String testPassword = "password";
final HttpContext httpContext = server.createContext("/", new HttpHandler()
{
public void handle(HttpExchange exchange) throws IOException
@ -102,37 +370,38 @@ public class SPIServerTest
}
});
httpContext.setAuthenticator(new BasicAuthenticator("Test")
httpContext.setAuthenticator(new BasicAuthenticator(testRealm)
{
@Override
public boolean checkCredentials(String username, String password)
{
if ("username".equals(username) && password.equals("password"))
if (testUsername.equals(username) && testPassword.equals(password))
return true;
return false;
}
});
URL url = new URL("http://localhost:" + port + "/");
HttpURLConnection client = (HttpURLConnection)url.openConnection();
client.connect();
assertThat(client.getResponseCode(), is(401));
Request request = client.newRequest("localhost", port)
.scheme("http")
.method(HttpMethod.GET)
.path("/");
Authenticator.setDefault(new Authenticator()
{
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication("username", "password".toCharArray());
}
});
ContentResponse response = request.send();
assertThat(response.getStatus(), is(401));
client = (HttpURLConnection)url.openConnection();
String userpass = "username:password";
String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userpass.getBytes(StandardCharsets.ISO_8859_1));
client.setRequestProperty("Authorization", basicAuth);
request = client.newRequest("localhost", port)
.scheme("http")
.method(HttpMethod.GET)
.path("/");
client.connect();
assertThat(client.getResponseCode(), is(200));
assertThat(IO.toString(client.getInputStream()), is("Hello"));
AuthenticationStore store = client.getAuthenticationStore();
URI uri = URI.create("http://localhost:" + port + "/");
store.addAuthentication(new BasicAuthentication(uri, testRealm, testUsername, testPassword));
response = request.send();
assertThat(response.getStatus(), is(200));
String body = response.getContentAsString();
assertThat(body, is("Hello"));
}
}

View File

@ -51,6 +51,7 @@ public record ByteRange(long first, long last)
}
/**
* Get the length of this byte range.
* @return the length of this byte range
*/
public long getLength()

View File

@ -0,0 +1,26 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.http;
import java.util.Collections;
import java.util.ListIterator;
class EmptyHttpFields implements HttpFields
{
@Override
public ListIterator<HttpField> listIterator(int index)
{
return Collections.emptyListIterator();
}
}

View File

@ -436,6 +436,7 @@ public class HttpField
}
/**
* Get the {@link HttpHeader} of this field, or {@code null}.
* @return the {@link HttpHeader} of this field, or {@code null}
*/
public HttpHeader getHeader()
@ -462,6 +463,7 @@ public class HttpField
}
/**
* Get the field name in lower-case.
* @return the field name in lower-case
*/
public String getLowerCaseName()
@ -470,6 +472,7 @@ public class HttpField
}
/**
* Get the field name.
* @return the field name
*/
public String getName()
@ -478,6 +481,7 @@ public class HttpField
}
/**
* Get the field value.
* @return the field value
*/
public String getValue()

View File

@ -64,7 +64,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
/**
* <p>A constant for an immutable and empty {@link HttpFields}.</p>
*/
HttpFields EMPTY = build().asImmutable();
HttpFields EMPTY = new EmptyHttpFields();
/**
* <p>Returns an empty {@link Mutable} instance.</p>

View File

@ -80,6 +80,7 @@ public class MetaData implements Iterable<HttpField>
}
/**
* Get the HTTP protocol version.
* @return the HTTP protocol version
*/
public HttpVersion getHttpVersion()
@ -88,6 +89,7 @@ public class MetaData implements Iterable<HttpField>
}
/**
* Get the HTTP headers or HTTP trailers.
* @return the HTTP headers or HTTP trailers
*/
public HttpFields getHttpFields()
@ -104,6 +106,7 @@ public class MetaData implements Iterable<HttpField>
}
/**
* Get the length of the content in bytes.
* @return the length of the content in bytes
*/
public long getContentLength()

View File

@ -37,6 +37,7 @@ public class HuffmanDecoder
private int _bits = 0;
/**
* Set in bytes of the huffman data..
* @param length in bytes of the huffman data.
*/
public void setLength(int length)

View File

@ -119,6 +119,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
}
/**
* Get the max number of cached files..
* @return the max number of cached files.
*/
public int getMaxCachedFiles()
@ -127,6 +128,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
}
/**
* Set the max number of cached files..
* @param maxCachedFiles the max number of cached files.
*/
public void setMaxCachedFiles(int maxCachedFiles)

View File

@ -41,16 +41,19 @@ import org.eclipse.jetty.util.Promise;
public interface Stream
{
/**
* Get the stream unique id.
* @return the stream unique id
*/
public int getId();
/**
* Get the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream.
* @return the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream
*/
public Listener getListener();
/**
* Get the session this stream is associated to.
* @return the session this stream is associated to
*/
public Session getSession();

View File

@ -50,6 +50,7 @@ public class MetaDataBuilder
}
/**
* Get the maxSize.
* @return the maxSize
*/
public int getMaxSize()

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.http3.frames.SettingsFrame;
public interface Session
{
/**
* Get the local socket address this session is bound to.
* @return the local socket address this session is bound to
*/
public default SocketAddress getLocalSocketAddress()
@ -45,6 +46,7 @@ public interface Session
}
/**
* Get the remote socket address this session is connected to.
* @return the remote socket address this session is connected to
*/
public default SocketAddress getRemoteSocketAddress()

View File

@ -44,11 +44,13 @@ import org.eclipse.jetty.util.Promise;
public interface Stream
{
/**
* Get the stream id.
* @return the stream id
*/
public long getId();
/**
* Get the session this stream is associated to.
* @return the session this stream is associated to
*/
public Session getSession();

View File

@ -480,6 +480,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
}
/**
* Set the growOutput to set.
* @param growOutput the growOutput to set
*/
public void setGrowOutput(boolean growOutput)

View File

@ -50,6 +50,7 @@ public class ByteBufferCallbackAccumulator
}
/**
* Get the total length of the content in the accumulator..
* @return the total length of the content in the accumulator.
*/
public int getLength()

View File

@ -52,6 +52,7 @@ public abstract class IdleTimeout
}
/**
* Get the period of time, in milliseconds, that this object was idle.
* @return the period of time, in milliseconds, that this object was idle
*/
public long getIdleFor()

View File

@ -69,6 +69,7 @@ public interface RetainableByteBuffer extends Retainable
public boolean isRetained();
/**
* Get the wrapped, not {@code null}, {@code ByteBuffer}.
* @return the wrapped, not {@code null}, {@code ByteBuffer}
*/
public ByteBuffer getByteBuffer();

View File

@ -116,6 +116,7 @@ public class ConnectorServer extends AbstractLifeCycle
}
/**
* Get the JMXServiceURL of this ConnectorServer.
* @return the JMXServiceURL of this ConnectorServer
*/
public JMXServiceURL getAddress()
@ -135,6 +136,7 @@ public class ConnectorServer extends AbstractLifeCycle
}
/**
* Get the ObjectName of this ConnectorServer.
* @return the ObjectName of this ConnectorServer
*/
public String getObjectName()
@ -143,6 +145,7 @@ public class ConnectorServer extends AbstractLifeCycle
}
/**
* Set the ObjectName of this ConnectorServer.
* @param objectName the ObjectName of this ConnectorServer
*/
public void setObjectName(String objectName)

View File

@ -56,6 +56,7 @@ public class ObjectMBean implements DynamicMBean
}
/**
* Get the managed object.
* @return the managed object
*/
public Object getManagedObject()

View File

@ -58,6 +58,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener
}
/**
* Get the filePath.
* @return the filePath
*/
public Path getFilePath()
@ -66,6 +67,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener
}
/**
* Set the filePath to set.
* @param filePath the filePath to set
*/
public void setFilePath(Path filePath)
@ -74,6 +76,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener
}
/**
* Get the sysPropertyName.
* @return the sysPropertyName
*/
public String getSysPropertyName()
@ -82,6 +85,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener
}
/**
* Set the sysPropertyName to set.
* @param sysPropertyName the sysPropertyName to set
*/
public void setSysPropertyName(String sysPropertyName)

View File

@ -101,6 +101,7 @@ public abstract class ProxyHandler extends Handler.Abstract
}
/**
* Get the proxy-to-server {@code Host} header value.
* @return the proxy-to-server {@code Host} header value
*/
public String getProxyToServerHost()
@ -120,6 +121,7 @@ public abstract class ProxyHandler extends Handler.Abstract
}
/**
* Get the value to use for the {@code Via} header.
* @return the value to use for the {@code Via} header
*/
public String getViaHost()

View File

@ -44,6 +44,7 @@ public class CookiePatternRule extends PatternRule
}
/**
* Get the response cookie name.
* @return the response cookie name
*/
public String getName()
@ -52,6 +53,7 @@ public class CookiePatternRule extends PatternRule
}
/**
* Set the response cookie name.
* @param name the response cookie name
*/
public void setName(String name)
@ -60,6 +62,7 @@ public class CookiePatternRule extends PatternRule
}
/**
* Get the response cookie value.
* @return the response cookie value
*/
public String getValue()
@ -68,6 +71,7 @@ public class CookiePatternRule extends PatternRule
}
/**
* Set the response cookie value.
* @param value the response cookie value
*/
public void setValue(String value)

View File

@ -65,6 +65,7 @@ public class HeaderPatternRule extends PatternRule
}
/**
* Set true to add the response header, false to put the response header..
* @param add true to add the response header, false to put the response header.
*/
public void setAdd(boolean add)

View File

@ -66,6 +66,7 @@ public class HeaderRegexRule extends RegexRule
}
/**
* Set true to add the response header, false to put the response header..
* @param add true to add the response header, false to put the response header.
*/
public void setAdd(boolean add)

View File

@ -52,6 +52,7 @@ public class InvalidURIRule extends Rule
}
/**
* Set the response code.
* @param code the response code
*/
public void setCode(int code)

View File

@ -54,6 +54,7 @@ public class RedirectPatternRule extends PatternRule
}
/**
* Set the location to redirect..
* @param value the location to redirect.
*/
public void setLocation(String value)
@ -67,6 +68,7 @@ public class RedirectPatternRule extends PatternRule
}
/**
* Set the 3xx redirect status code.
* @param statusCode the 3xx redirect status code
*/
public void setStatusCode(int statusCode)

View File

@ -56,6 +56,7 @@ public class RedirectRegexRule extends RegexRule
}
/**
* Set the location to redirect..
* @param location the location to redirect.
*/
public void setLocation(String location)

View File

@ -34,6 +34,7 @@ public abstract class RegexRule extends Rule
}
/**
* Get the regular expression.
* @return the regular expression
*/
public String getRegex()

View File

@ -52,6 +52,7 @@ public class ResponsePatternRule extends PatternRule
}
/**
* Set the response code.
* @param code the response code
*/
public void setCode(int code)

View File

@ -64,6 +64,7 @@ public class RewriteHandler extends Handler.Wrapper
}
/**
* Get the {@link RuleContainer} used by this handler.
* @return the {@link RuleContainer} used by this handler
*/
public RuleContainer getRuleContainer()

View File

@ -46,6 +46,7 @@ public class RuleContainer extends Rule implements Iterable<Rule>, Dumpable
}
/**
* Set the list of {@link Rule}..
* @param rules the list of {@link Rule}.
*/
public void setRules(List<Rule> rules)

View File

@ -47,6 +47,7 @@ public class VirtualHostRuleContainer extends RuleContainer
}
/**
* Add the virtual host to add to the existing list of virtual hosts.
* @param virtualHost the virtual host to add to the existing list of virtual hosts
*/
public void addVirtualHost(String virtualHost)

View File

@ -127,8 +127,22 @@ public interface Authenticator
IdentityService getIdentityService();
/**
* Should session ID be renewed on authentication.
* @return true if the session ID should be renewed on authentication
*/
boolean isSessionRenewedOnAuthentication();
/**
* Get the interval in seconds, which if non-zero, will be set
* with {@link Session#setMaxInactiveInterval(int)}
* when a session is newly authenticated
* @return An interval in seconds; or 0 to not set the interval
* on authentication; or a negative number to make the
* session never timeout after authentication.
*/
int getSessionMaxInactiveIntervalOnAuthentication();
class Wrapper implements Configuration
{
private final Configuration _configuration;
@ -179,6 +193,12 @@ public interface Authenticator
{
return _configuration.isSessionRenewedOnAuthentication();
}
@Override
public int getSessionMaxInactiveIntervalOnAuthentication()
{
return _configuration.getSessionMaxInactiveIntervalOnAuthentication();
}
}
}

View File

@ -98,6 +98,7 @@ public class HashLoginService extends AbstractLoginService
}
/**
* Get the scan interval in seconds for reloading the property file..
* @return the scan interval in seconds for reloading the property file.
*/
public int getReloadInterval()

View File

@ -126,6 +126,7 @@ public class PropertyUserStore extends UserStore implements Scanner.DiscreteList
}
/**
* Get the period in seconds to scan for property file changes, or 0 for no scanning.
* @return the period in seconds to scan for property file changes, or 0 for no scanning
*/
public int getReloadInterval()

View File

@ -80,6 +80,7 @@ public class SPNEGOLoginService extends ContainerLifeCycle implements LoginServi
}
/**
* Get the path of the keyTab file containing service credentials.
* @return the path of the keyTab file containing service credentials
*/
public Path getKeyTabPath()
@ -88,6 +89,7 @@ public class SPNEGOLoginService extends ContainerLifeCycle implements LoginServi
}
/**
* Set the path of the keyTab file containing service credentials.
* @param keyTabFile the path of the keyTab file containing service credentials
*/
public void setKeyTabPath(Path keyTabFile)
@ -123,6 +125,7 @@ public class SPNEGOLoginService extends ContainerLifeCycle implements LoginServi
}
/**
* Set the host name of the service.
* @param hostName the host name of the service
*/
public void setHostName(String hostName)

View File

@ -79,7 +79,8 @@ public abstract class SecurityHandler extends Handler.Wrapper implements Configu
private final Map<String, String> _parameters = new HashMap<>();
private LoginService _loginService;
private IdentityService _identityService;
private boolean _renewSession = true;
private boolean _renewSessionOnAuthentication = true;
private int _sessionMaxInactiveIntervalOnAuthentication = 0;
private AuthenticationState.Deferred _deferred;
static
@ -430,22 +431,42 @@ public abstract class SecurityHandler extends Handler.Wrapper implements Configu
@Override
public boolean isSessionRenewedOnAuthentication()
{
return _renewSession;
return _renewSessionOnAuthentication;
}
/**
* Set renew the session on Authentication.
* <p>
* If set to true, then on authentication, the session associated with a reqeuest is invalidated and replaced with a new session.
* If set to true, then on authentication, the session associated with a request is invalidated and replaced with a new session.
*
* @param renew true to renew the authentication on session
* @see Configuration#isSessionRenewedOnAuthentication()
*/
public void setSessionRenewedOnAuthentication(boolean renew)
{
_renewSession = renew;
_renewSessionOnAuthentication = renew;
}
@Override
public int getSessionMaxInactiveIntervalOnAuthentication()
{
return _sessionMaxInactiveIntervalOnAuthentication;
}
/**
* Set the interval in seconds, which if non-zero, will be set with
* {@link org.eclipse.jetty.server.Session#setMaxInactiveInterval(int)}
* when a session is newly authenticated.
* @param seconds An interval in seconds; or 0 to not set the interval
* on authentication; or a negative number to make the
* session never timeout after authentication.
* @see Configuration#getSessionMaxInactiveIntervalOnAuthentication()
*/
public void setSessionMaxInactiveIntervalOnAuthentication(int seconds)
{
_sessionMaxInactiveIntervalOnAuthentication = seconds;
}
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{

View File

@ -36,7 +36,8 @@ public abstract class LoginAuthenticator implements Authenticator
protected LoginService _loginService;
protected IdentityService _identityService;
private boolean _renewSession;
private boolean _sessionRenewedOnAuthentication;
private int _sessionMaxInactiveIntervalOnAuthentication;
protected LoginAuthenticator()
{
@ -61,7 +62,7 @@ public abstract class LoginAuthenticator implements Authenticator
LOG.debug("{}.login {}", this, user);
if (user != null)
{
renewSession(request, response);
updateSession(request, response);
return user;
}
return null;
@ -87,7 +88,8 @@ public abstract class LoginAuthenticator implements Authenticator
_identityService = configuration.getIdentityService();
if (_identityService == null)
throw new IllegalStateException("No IdentityService for " + this + " in " + configuration);
_renewSession = configuration.isSessionRenewedOnAuthentication();
_sessionRenewedOnAuthentication = configuration.isSessionRenewedOnAuthentication();
_sessionMaxInactiveIntervalOnAuthentication = configuration.getSessionMaxInactiveIntervalOnAuthentication();
}
public LoginService getLoginService()
@ -96,35 +98,40 @@ public abstract class LoginAuthenticator implements Authenticator
}
/**
* Change the session id.
* Update the session on authentication.
* The session is changed to a new instance with a new ID if and only if:<ul>
* <li>A session exists.
* <li>The {@link Configuration#isSessionRenewedOnAuthentication()} returns true.
* <li>The session ID has been given to unauthenticated responses
* </ul>
*
* @param httpRequest the request
* @param httpResponse the response
* @return The new session.
* @see Configuration#isSessionRenewedOnAuthentication()
* @see Configuration#getSessionMaxInactiveIntervalOnAuthentication()
*/
protected Session renewSession(Request httpRequest, Response httpResponse)
protected void updateSession(Request httpRequest, Response httpResponse)
{
Session session = httpRequest.getSession(false);
if (_renewSession && session != null)
if (session != null && (_sessionRenewedOnAuthentication || _sessionMaxInactiveIntervalOnAuthentication != 0))
{
synchronized (session)
{
//if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
//(indicated by SESSION_SECURED not being set on the session) then we should change id
if (session.getAttribute(SecurityHandler.SESSION_AUTHENTICATED_ATTRIBUTE) != Boolean.TRUE)
if (_sessionMaxInactiveIntervalOnAuthentication != 0)
session.setMaxInactiveInterval(_sessionMaxInactiveIntervalOnAuthentication < 0 ? -1 : _sessionMaxInactiveIntervalOnAuthentication);
if (_sessionRenewedOnAuthentication)
{
session.setAttribute(SecurityHandler.SESSION_AUTHENTICATED_ATTRIBUTE, Boolean.TRUE);
session.renewId(httpRequest, httpResponse);
return session;
//if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
//(indicated by SESSION_SECURED not being set on the session) then we should change id
if (session.getAttribute(SecurityHandler.SESSION_AUTHENTICATED_ATTRIBUTE) != Boolean.TRUE)
{
session.setAttribute(SecurityHandler.SESSION_AUTHENTICATED_ATTRIBUTE, Boolean.TRUE);
session.renewId(httpRequest, httpResponse);
}
}
}
}
return session;
}
/**

View File

@ -71,6 +71,7 @@ public class SPNEGOAuthenticator extends LoginAuthenticator
}
/**
* Get the authentication duration.
* @return the authentication duration
*/
public Duration getAuthenticationDuration()
@ -101,7 +102,7 @@ public class SPNEGOAuthenticator extends LoginAuthenticator
RoleDelegateUserIdentity user = (RoleDelegateUserIdentity)_loginService.login(username, password, request, request::getSession);
if (user != null && user.isEstablished())
{
renewSession(request, response);
updateSession(request, response);
}
return user;
}

View File

@ -130,6 +130,7 @@ public class SslClientCertAuthenticator extends LoginAuthenticator
}
/**
* Set true if SSL certificates have to be validated..
* @param validateCerts true if SSL certificates have to be validated.
*/
public void setValidateCerts(boolean validateCerts)

View File

@ -101,6 +101,7 @@ public class JAASLoginService extends ContainerLifeCycle implements LoginService
}
/**
* Get the configuration.
* @return the configuration
*/
public Configuration getConfiguration()
@ -109,6 +110,7 @@ public class JAASLoginService extends ContainerLifeCycle implements LoginService
}
/**
* Set the configuration to set.
* @param configuration the configuration to set
*/
public void setConfiguration(Configuration configuration)

View File

@ -13,6 +13,8 @@
package org.eclipse.jetty.security;
import java.util.stream.Stream;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
@ -24,14 +26,21 @@ import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.session.ManagedSession;
import org.eclipse.jetty.session.SessionHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertNull;
public class FormAuthenticatorTest
{
@ -95,7 +104,6 @@ public class FormAuthenticatorTest
_securityHandler.put("/known/*", Constraint.KNOWN_ROLE);
_securityHandler.put("/admin/*", Constraint.from("admin"));
_securityHandler.setAuthenticator(new FormAuthenticator("/login", "/error", dispatch));
_server.start();
}
@AfterEach
@ -112,6 +120,7 @@ public class FormAuthenticatorTest
public void testLoginRedirect() throws Exception
{
configureServer(false);
_server.start();
String response;
response = _connector.getResponse("GET /ctx/some/thing HTTP/1.0\r\n\r\n");
@ -147,6 +156,7 @@ public class FormAuthenticatorTest
public void testUseExistingSession() throws Exception
{
configureServer(false);
_server.start();
String response;
response = _connector.getResponse("GET /ctx/some/thing?action=session HTTP/1.0\r\n\r\n");
@ -165,6 +175,7 @@ public class FormAuthenticatorTest
public void testError() throws Exception
{
configureServer(false);
_server.start();
String response;
@ -198,6 +209,7 @@ public class FormAuthenticatorTest
public void testLoginQuery() throws Exception
{
configureServer(false);
_server.start();
String response;
@ -236,6 +248,7 @@ public class FormAuthenticatorTest
public void testLoginForm() throws Exception
{
configureServer(false);
_server.start();
String response;
@ -282,6 +295,7 @@ public class FormAuthenticatorTest
public void testRedirectToPost() throws Exception
{
configureServer(false);
_server.start();
String response;
String sessionId = "unknown";
@ -321,6 +335,7 @@ public class FormAuthenticatorTest
public void testLoginDispatch() throws Exception
{
configureServer(true);
_server.start();
String response = _connector.getResponse("GET /ctx/admin/user HTTP/1.0\r\nHost:host:8888\r\n\r\n");
assertThat(response, containsString("HTTP/1.1 200 OK"));
@ -332,10 +347,97 @@ public class FormAuthenticatorTest
public void testErrorDispatch() throws Exception
{
configureServer(true);
_server.start();
String response = _connector.getResponse("GET /ctx/j_security_check?j_username=user&j_password=wrong HTTP/1.0\r\nHost:host:8888\r\n\r\n");
assertThat(response, containsString("HTTP/1.1 200 OK"));
assertThat(response, containsString("Deferred"));
assertThat(response, containsString("path=/ctx/error,"));
}
public static Stream<Arguments> onAuthenticationTests()
{
return Stream.of(
Arguments.of(false, 0),
Arguments.of(false, -1),
Arguments.of(false, 2400),
Arguments.of(true, 0),
Arguments.of(true, -1),
Arguments.of(true, 2400)
);
}
@ParameterizedTest
@MethodSource("onAuthenticationTests")
public void testSessionOnAuthentication(boolean sessionRenewOnAuthentication, int sessionMaxInactiveIntervalOnAuthentication) throws Exception
{
final int UNAUTH_SECONDS = 1200;
configureServer(false);
// Use a FormAuthenticator as an example of session authentication
_securityHandler.setAuthenticator(new FormAuthenticator("/testLoginPage", "/testErrorPage", false));
_sessionHandler.setMaxInactiveInterval(UNAUTH_SECONDS);
_securityHandler.setSessionRenewedOnAuthentication(sessionRenewOnAuthentication);
_securityHandler.setSessionMaxInactiveIntervalOnAuthentication(sessionMaxInactiveIntervalOnAuthentication);
_server.start();
String response;
response = _connector.getResponse("GET /ctx/any/info HTTP/1.0\r\n\r\n");
assertThat(response, containsString(" 302 Found"));
assertThat(response, containsString("/ctx/testLoginPage"));
assertThat(response, containsString("JSESSIONID="));
String sessionId = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf("; Path=/ctx"));
response = _connector.getResponse("GET /ctx/testLoginPage HTTP/1.0\r\n" +
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
"\r\n");
assertThat(response, containsString(" 200 OK"));
assertThat(response, containsString("path=/ctx/testLoginPage"));
assertThat(response, not(containsString("JSESSIONID=" + sessionId)));
response = _connector.getResponse("POST /ctx/j_security_check HTTP/1.0\r\n" +
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Content-Length: 35\r\n" +
"\r\n" +
"j_username=user&j_password=password");
assertThat(response, startsWith("HTTP/1.1 302 "));
assertThat(response, containsString("Location"));
assertThat(response, containsString("/ctx/any/info"));
if (sessionRenewOnAuthentication)
{
// check session ID has changed.
assertNull(_sessionHandler.getManagedSession(sessionId));
assertThat(response, containsString("Set-Cookie:"));
assertThat(response, containsString("JSESSIONID="));
assertThat(response, not(containsString("JSESSIONID=" + sessionId)));
sessionId = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf("; Path=/ctx"));
}
else
{
// check session ID has not changed.
assertThat(response, not(containsString("Set-Cookie:")));
assertThat(response, not(containsString("JSESSIONID=")));
}
ManagedSession session = _sessionHandler.getManagedSession(sessionId);
if (sessionMaxInactiveIntervalOnAuthentication == 0)
{
// check max interval has not been updated
assertThat(session.getMaxInactiveInterval(), is(UNAUTH_SECONDS));
}
else
{
// check max interval has not been updated
assertThat(session.getMaxInactiveInterval(), is(sessionMaxInactiveIntervalOnAuthentication));
}
// check session still there.
response = _connector.getResponse("GET /ctx/any/info HTTP/1.0\r\n" +
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
"\r\n");
assertThat(response, startsWith("HTTP/1.1 200 OK"));
}
}

View File

@ -9,7 +9,7 @@
<New id="DebugListener" class="org.eclipse.jetty.server.DebugListener">
<Arg name="outputStream">
<New class="org.eclipse.jetty.util.RolloverFileOutputStream">
<Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
<Arg type="String"><Property name="jetty.debug.logs" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
<Arg type="boolean"><Property name="jetty.debug.append" default="true"/></Arg>
<Arg type="int"><Property name="jetty.debug.retainDays" default="14"/></Arg>
<Arg>

View File

@ -43,9 +43,6 @@
<Set name="acceptedTcpNoDelay"><Property name="jetty.http.acceptedTcpNoDelay" default="true"/></Set>
<Set name="acceptedReceiveBufferSize" property="jetty.http.acceptedReceiveBufferSize" />
<Set name="acceptedSendBufferSize" property="jetty.http.acceptedSendBufferSize" />
<Get name="SelectorManager">
<Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
</Get>
</New>
</Arg>
</Call>

View File

@ -36,9 +36,6 @@
<Set name="acceptedTcpNoDelay"><Property name="jetty.ssl.acceptedTcpNoDelay" default="true"/></Set>
<Set name="acceptedReceiveBufferSize" property="jetty.ssl.acceptedReceiveBufferSize" />
<Set name="acceptedSendBufferSize" property="jetty.ssl.acceptedSendBufferSize" />
<Get name="SelectorManager">
<Set name="connectTimeout" property="jetty.ssl.connectTimeout"/>
</Get>
</New>
</Arg>
</Call>

View File

@ -23,6 +23,12 @@ etc/jetty-debug.xml
## How many days to retain old log files
# jetty.debug.retainDays=14
## Should existing log be appended to
# jetty.debug.append=true
## Log directory for jetty debug logs
# jetty.debug.logs=./logs
## Timezone of the log entries
# jetty.debug.timezone=GMT

View File

@ -18,9 +18,6 @@ etc/jetty-gzip.xml
## Minimum content length after which gzip is enabled
# jetty.gzip.minGzipSize=32
## Check whether a file with *.gz extension exists
# jetty.gzip.checkGzExists=false
## Inflate request buffer size, or 0 for no request inflation
# jetty.gzip.inflateBufferSize=0

View File

@ -38,6 +38,9 @@ etc/jetty.xml
## Max response content write length that is buffered (in bytes)
# jetty.httpConfig.outputAggregationSize=8192
## If HTTP/1.x persistent connections should be enabled
# jetty.httpConfig.persistentConnectionsEnabled=true
## Max request headers size (in bytes)
# jetty.httpConfig.requestHeaderSize=8192

View File

@ -36,21 +36,25 @@ import org.eclipse.jetty.util.thread.Scheduler;
public interface Connector extends LifeCycle, Container, Graceful
{
/**
* Get the {@link Server} instance associated with this {@link Connector}.
* @return the {@link Server} instance associated with this {@link Connector}
*/
public Server getServer();
/**
* Get the {@link Executor} used to submit tasks.
* @return the {@link Executor} used to submit tasks
*/
public Executor getExecutor();
/**
* Get the {@link Scheduler} used to schedule tasks.
* @return the {@link Scheduler} used to schedule tasks
*/
public Scheduler getScheduler();
/**
* Get the {@link ByteBufferPool} to acquire buffers from and release buffers to.
* @return the {@link ByteBufferPool} to acquire buffers from and release buffers to
*/
public ByteBufferPool getByteBufferPool();
@ -64,6 +68,7 @@ public interface Connector extends LifeCycle, Container, Graceful
public <T> T getConnectionFactory(Class<T> factoryType);
/**
* Get the default {@link ConnectionFactory} associated with the default protocol name.
* @return the default {@link ConnectionFactory} associated with the default protocol name
*/
public ConnectionFactory getDefaultConnectionFactory();
@ -79,6 +84,7 @@ public interface Connector extends LifeCycle, Container, Graceful
public long getIdleTimeout();
/**
* Get the underlying socket, channel, buffer etc. for the connector..
* @return the underlying socket, channel, buffer etc. for the connector.
*/
public Object getTransport();

View File

@ -278,6 +278,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
}
/**
* Get the header name for forwarded server..
* @return the header name for forwarded server.
*/
public String getForwardedServerHeader()
@ -298,6 +299,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
}
/**
* Get the forwarded for header.
* @return the forwarded for header
*/
public String getForwardedForHeader()
@ -427,6 +429,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
}
/**
* Set the header name holding a forwarded Https status indicator(default {@code X-Proxied-Https}).
* @param forwardedHttpsHeader the header name holding a forwarded Https status indicator(default {@code X-Proxied-Https})
*/
public void setForwardedHttpsHeader(String forwardedHttpsHeader)

View File

@ -121,6 +121,7 @@ public interface Handler extends LifeCycle, Destroyable, Request.Handler
Server getServer();
/**
* Set the {@code Server} to associate to this {@code Handler}.
* @param server the {@code Server} to associate to this {@code Handler}
*/
void setServer(Server server);

View File

@ -37,6 +37,7 @@ public interface HttpChannel extends Invocable
ConnectionMetaData getConnectionMetaData();
/**
* Set the {@link HttpStream} to associate to this channel..
* @param httpStream the {@link HttpStream} to associate to this channel.
*/
void setHttpStream(HttpStream httpStream);

View File

@ -324,6 +324,7 @@ public class HttpConfiguration implements Dumpable
}
/**
* Set if true, delays the application dispatch until content is available (defaults to true).
* @param delay if true, delays the application dispatch until content is available (defaults to true)
*/
public void setDelayDispatchUntilContent(boolean delay)
@ -338,6 +339,7 @@ public class HttpConfiguration implements Dumpable
}
/**
* Set whether to use direct ByteBuffers for reading.
* @param useInputDirectByteBuffers whether to use direct ByteBuffers for reading
*/
public void setUseInputDirectByteBuffers(boolean useInputDirectByteBuffers)
@ -352,6 +354,7 @@ public class HttpConfiguration implements Dumpable
}
/**
* Set whether to use direct ByteBuffers for writing.
* @param useOutputDirectByteBuffers whether to use direct ByteBuffers for writing
*/
public void setUseOutputDirectByteBuffers(boolean useOutputDirectByteBuffers)
@ -621,6 +624,7 @@ public class HttpConfiguration implements Dumpable
}
/**
* Set whether remote errors, when detected, are notified to async applications.
* @param notifyRemoteAsyncErrors whether remote errors, when detected, are notified to async applications
*/
public void setNotifyRemoteAsyncErrors(boolean notifyRemoteAsyncErrors)

View File

@ -60,6 +60,7 @@ public class NetworkTrafficServerConnector extends ServerConnector
}
/**
* Set the listener to set, or null to unset.
* @param listener the listener to set, or null to unset
*/
public void setNetworkTrafficListener(NetworkTrafficListener listener)
@ -68,6 +69,7 @@ public class NetworkTrafficServerConnector extends ServerConnector
}
/**
* Get the listener.
* @return the listener
*/
public NetworkTrafficListener getNetworkTrafficListener()

View File

@ -131,6 +131,7 @@ public class ResourceService
}
/**
* Get the cacheControl header to set on all static content..
* @return the cacheControl header to set on all static content.
*/
public String getCacheControl()
@ -831,6 +832,7 @@ public class ResourceService
}
/**
* Set the cacheControl header to set on all static content..
* @param cacheControl the cacheControl header to set on all static content.
*/
public void setCacheControl(String cacheControl)
@ -855,6 +857,7 @@ public class ResourceService
}
/**
* Set file extensions that signify that a file is gzip compressed. Eg ".svgz".
* @param gzipEquivalentFileExtensions file extensions that signify that a file is gzip compressed. Eg ".svgz"
*/
public void setGzipEquivalentFileExtensions(List<String> gzipEquivalentFileExtensions)

View File

@ -55,6 +55,7 @@ public interface Response extends Content.Sink
int getStatus();
/**
* Set the response HTTP status code.
* @param code the response HTTP status code
*/
void setStatus(int code);

View File

@ -208,6 +208,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
}
/**
* Set whether the {@code includeSubdomains} attribute is sent with the Strict-Transport-Security response header.
* @param stsIncludeSubDomains whether the {@code includeSubdomains} attribute is sent with the Strict-Transport-Security response header
*/
public void setStsIncludeSubDomains(boolean stsIncludeSubDomains)

View File

@ -450,6 +450,7 @@ public class Server extends Handler.Wrapper implements Attributes
}
/**
* Set true if {@link #dumpStdErr()} is called after starting.
* @param dumpAfterStart true if {@link #dumpStdErr()} is called after starting
*/
public void setDumpAfterStart(boolean dumpAfterStart)
@ -467,6 +468,7 @@ public class Server extends Handler.Wrapper implements Attributes
}
/**
* Set true if {@link #dumpStdErr()} is called before stopping.
* @param dumpBeforeStop true if {@link #dumpStdErr()} is called before stopping
*/
public void setDumpBeforeStop(boolean dumpBeforeStop)

View File

@ -459,6 +459,7 @@ public class ServerConnector extends AbstractNetworkConnector
}
/**
* Set the accept queue size (also known as accept backlog).
* @param acceptQueueSize the accept queue size (also known as accept backlog)
*/
public void setAcceptQueueSize(int acceptQueueSize)
@ -495,6 +496,7 @@ public class ServerConnector extends AbstractNetworkConnector
}
/**
* Set whether it is allowed to bind multiple server sockets to the same host and port.
* @param reusePort whether it is allowed to bind multiple server sockets to the same host and port
*/
public void setReusePort(boolean reusePort)

View File

@ -30,7 +30,6 @@ import java.util.Set;
import java.util.function.Predicate;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.thread.AutoLock;
@ -175,6 +174,7 @@ public class ShutdownMonitor
}
/**
* Set true to exit the VM on shutdown.
* @param exitVm true to exit the VM on shutdown
*/
public void setExitVm(boolean exitVm)

View File

@ -113,6 +113,7 @@ public class ConnectHandler extends Handler.Wrapper
}
/**
* Get the timeout, in milliseconds, to connect to the remote server.
* @return the timeout, in milliseconds, to connect to the remote server
*/
public long getConnectTimeout()
@ -121,6 +122,7 @@ public class ConnectHandler extends Handler.Wrapper
}
/**
* Set the timeout, in milliseconds, to connect to the remote server.
* @param connectTimeout the timeout, in milliseconds, to connect to the remote server
*/
public void setConnectTimeout(long connectTimeout)
@ -129,6 +131,7 @@ public class ConnectHandler extends Handler.Wrapper
}
/**
* Get the idle timeout, in milliseconds.
* @return the idle timeout, in milliseconds
*/
public long getIdleTimeout()
@ -137,6 +140,7 @@ public class ConnectHandler extends Handler.Wrapper
}
/**
* Set the idle timeout, in milliseconds.
* @param idleTimeout the idle timeout, in milliseconds
*/
public void setIdleTimeout(long idleTimeout)

View File

@ -299,6 +299,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Alias
}
/**
* Set true if /context is not redirected to /context/.
* @param allowNullPathInContext true if /context is not redirected to /context/
*/
public void setAllowNullPathInContext(boolean allowNullPathInContext)
@ -1033,6 +1034,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Alias
}
/**
* Set list of AliasCheck instances.
* @param checks list of AliasCheck instances
*/
public void setAliasChecks(List<AliasCheck> checks)

View File

@ -118,6 +118,7 @@ public class DebugHandler extends Handler.Wrapper implements Connection.Listener
}
/**
* Get the out.
* @return the out
*/
public OutputStream getOutputStream()
@ -126,6 +127,7 @@ public class DebugHandler extends Handler.Wrapper implements Connection.Listener
}
/**
* Set the out to set.
* @param out the out to set
*/
public void setOutputStream(OutputStream out)

View File

@ -235,6 +235,7 @@ public class DefaultHandler extends Handler.Abstract
}
/**
* Set true if the handle can server the jetty favicon.ico.
* @param serveFavIcon true if the handle can server the jetty favicon.ico
*/
public void setServeFavIcon(boolean serveFavIcon)

View File

@ -481,6 +481,7 @@ public class ErrorHandler implements Request.Handler
}
/**
* Set if true, the error message appears in page title.
* @param showMessageInTitle if true, the error message appears in page title
*/
public void setShowMessageInTitle(boolean showMessageInTitle)

View File

@ -42,6 +42,7 @@ public class MovedContextHandler extends ContextHandler
}
/**
* Get the redirect status code, by default 303.
* @return the redirect status code, by default 303
*/
public int getStatusCode()
@ -61,6 +62,7 @@ public class MovedContextHandler extends ContextHandler
}
/**
* Get the URI to redirect to.
* @return the URI to redirect to
*/
public String getRedirectURI()
@ -124,6 +126,7 @@ public class MovedContextHandler extends ContextHandler
}
/**
* Get the {@code Cache-Control} header value or {@code null}.
* @return the {@code Cache-Control} header value or {@code null}
*/
public String getCacheControl()
@ -132,6 +135,7 @@ public class MovedContextHandler extends ContextHandler
}
/**
* Set the {@code Cache-Control} header value or {@code null}.
* @param cacheControl the {@code Cache-Control} header value or {@code null}
*/
public void setCacheControl(String cacheControl)

View File

@ -118,6 +118,7 @@ public class QoSHandler extends Handler.Wrapper
}
/**
* Get the max duration of time a request may stay suspended.
* @return the max duration of time a request may stay suspended
*/
public Duration getMaxSuspend()

View File

@ -183,6 +183,7 @@ public class ResourceHandler extends Handler.Wrapper
}
/**
* Get the cacheControl header to set on all static content..
* @return the cacheControl header to set on all static content.
*/
public String getCacheControl()
@ -284,6 +285,7 @@ public class ResourceHandler extends Handler.Wrapper
}
/**
* Set the cacheControl header to set on all static content..
* @param cacheControl the cacheControl header to set on all static content.
*/
public void setCacheControl(String cacheControl)
@ -308,6 +310,7 @@ public class ResourceHandler extends Handler.Wrapper
}
/**
* Set file extensions that signify that a file is gzip compressed. Eg ".svgz".
* @param gzipEquivalentFileExtensions file extensions that signify that a file is gzip compressed. Eg ".svgz"
*/
public void setGzipEquivalentFileExtensions(List<String> gzipEquivalentFileExtensions)

View File

@ -82,6 +82,7 @@ public class TryPathsHandler extends Handler.Wrapper
}
/**
* Get the attribute name of the original request path.
* @return the attribute name of the original request path
*/
public String getOriginalPathAttribute()
@ -102,6 +103,7 @@ public class TryPathsHandler extends Handler.Wrapper
}
/**
* Get the attribute name of the original request query.
* @return the attribute name of the original request query
*/
public String getOriginalQueryAttribute()

View File

@ -406,7 +406,7 @@ public class PartialRFC2616Test
}
/**
* @throws Exception
* @throws Exception if there is an unspecified problem
* @see <a href="https://www.rfc-editor.org/rfc/rfc2616#section-5.2">RFC 2616 - Section 5.2 - The Resource Identified by a Request</a>
*/
@Test

View File

@ -49,6 +49,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Set the flushOnResponseCommit to set.
* @param flushOnResponseCommit the flushOnResponseCommit to set
*/
public void setFlushOnResponseCommit(boolean flushOnResponseCommit)
@ -65,6 +66,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Set the saveOnCreate to set.
* @param saveOnCreate the saveOnCreate to set
*/
public void setSaveOnCreate(boolean saveOnCreate)
@ -81,6 +83,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Set the removeUnloadableSessions to set.
* @param removeUnloadableSessions the removeUnloadableSessions to set
*/
public void setRemoveUnloadableSessions(boolean removeUnloadableSessions)
@ -89,6 +92,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Get the evictionPolicy.
* @return the evictionPolicy
*/
public int getEvictionPolicy()
@ -97,6 +101,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Set the evictionPolicy to set.
* @param evictionPolicy the evictionPolicy to set
*/
public void setEvictionPolicy(int evictionPolicy)
@ -113,6 +118,7 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory
}
/**
* Set the saveOnInactiveEvict to set.
* @param saveOnInactiveEvict the saveOnInactiveEvict to set
*/
public void setSaveOnInactiveEviction(boolean saveOnInactiveEvict)

View File

@ -23,6 +23,7 @@ public abstract class AbstractSessionDataStoreFactory implements SessionDataStor
int _savePeriodSec = AbstractSessionDataStore.DEFAULT_SAVE_PERIOD_SEC;
/**
* Get the gracePeriodSec.
* @return the gracePeriodSec
*/
public int getGracePeriodSec()
@ -31,6 +32,7 @@ public abstract class AbstractSessionDataStoreFactory implements SessionDataStor
}
/**
* Set the gracePeriodSec to set.
* @param gracePeriodSec the gracePeriodSec to set
*/
public void setGracePeriodSec(int gracePeriodSec)
@ -39,6 +41,7 @@ public abstract class AbstractSessionDataStoreFactory implements SessionDataStor
}
/**
* Get the savePeriodSec.
* @return the savePeriodSec
*/
public int getSavePeriodSec()
@ -47,6 +50,7 @@ public abstract class AbstractSessionDataStoreFactory implements SessionDataStor
}
/**
* Set the savePeriodSec to set.
* @param savePeriodSec the savePeriodSec to set
*/
public void setSavePeriodSec(int savePeriodSec)

View File

@ -14,6 +14,7 @@
package org.eclipse.jetty.session;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@ -67,7 +68,7 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
* -1 means no timeout
*/
private int _dftMaxIdleSecs = -1;
private boolean _usingURLs;
private boolean _usingUriParameters;
private boolean _usingCookies = true;
private SessionIdManager _sessionIdManager;
private ClassLoader _loader;
@ -339,6 +340,7 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
/**
* @return the max period of inactivity, after which the session is invalidated, in seconds.
* If less than or equal to zero, then the session is immortal
* @see #setMaxInactiveInterval(int)
*/
@Override
@ -350,7 +352,7 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
/**
* Sets the max period of inactivity, after which the session is invalidated, in seconds.
*
* @param seconds the max inactivity period, in seconds.
* @param seconds the max inactivity period, in seconds. If less than or equal to zero, then the session is immortal
* @see #getMaxInactiveInterval()
*/
public void setMaxInactiveInterval(int seconds)
@ -673,8 +675,9 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
return null;
// should not encode if cookies in evidence
if ((isUsingCookies() && cookiesInUse) || !isUsingURLs())
if ((isUsingCookies() && cookiesInUse) || !isUsingUriParameters())
{
// strip session param from URI
int prefix = uri.indexOf(sessionURLPrefix);
if (prefix != -1)
{
@ -933,16 +936,34 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
* @return whether the session management is handled via URLs.
*/
@Override
public boolean isUsingURLs()
public boolean isUsingUriParameters()
{
return _usingURLs;
return _usingUriParameters;
}
public void setUsingUriParameters(boolean usingUriParameters)
{
_usingUriParameters = usingUriParameters;
}
/**
* @deprecated use {@link #isUsingUriParameters()} instead, will be removed in Jetty 12.1.0
*/
@Deprecated(since = "12.0.1", forRemoval = true)
public boolean isUsingURLs()
{
return isUsingUriParameters();
}
/**
* @deprecated use {@link #setUsingUriParameters(boolean)} instead, will be removed in Jetty 12.1.0
*/
@Deprecated(since = "12.0.1", forRemoval = true)
public void setUsingURLs(boolean usingURLs)
{
_usingURLs = usingURLs;
setUsingUriParameters(usingURLs);
}
/**
* Create a new Session, using the requested session id if possible.
* @param request the inbound request
@ -1166,7 +1187,9 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
boolean requestedSessionIdFromCookie = false;
ManagedSession session = null;
//first try getting id from a cookie
List<String> ids = null;
//first try getting list of id from cookies
if (isUsingCookies())
{
//Cookie[] cookies = request.getCookies();
@ -1178,109 +1201,130 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
{
if (sessionCookie.equalsIgnoreCase(cookie.getName()))
{
String id = cookie.getValue();
requestedSessionIdFromCookie = true;
if (LOG.isDebugEnabled())
LOG.debug("Got Session ID {} from cookie {}", id, sessionCookie);
if (session == null)
{
//we currently do not have a session selected, use this one if it is valid
ManagedSession s = getManagedSession(id);
if (s != null && s.isValid())
{
//associate it with the request so its reference count is decremented as the
//request exits
requestedSessionId = id;
session = s;
if (LOG.isDebugEnabled())
LOG.debug("Selected session {}", session);
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("No session found for session cookie id {}", id);
//if we don't have a valid session id yet, just choose the current id
if (requestedSessionId == null)
requestedSessionId = id;
}
}
else
{
//we currently have a valid session selected. We will throw an error
//if there is a _different_ valid session id cookie. Duplicate ids, or
//invalid session ids are ignored
if (!session.getId().equals(getSessionIdManager().getId(id)))
{
if (LOG.isDebugEnabled())
LOG.debug("Multiple different valid session ids: {}, {}", requestedSessionId, id);
//load the session to see if it is valid or not
ManagedSession s = getManagedSession(id);
if (s != null && s.isValid())
{
//release both sessions straight away??
try
{
_sessionCache.release(session);
_sessionCache.release(s);
}
catch (Exception x)
{
if (LOG.isDebugEnabled())
LOG.debug("Error releasing duplicate valid session: {}", id);
}
throw new BadMessageException("Duplicate valid session cookies: " + requestedSessionId + " ," + id);
}
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("Duplicate valid session cookie id: {}", id);
}
}
if (ids == null)
ids = new ArrayList<>();
ids.add(cookie.getValue());
}
}
}
}
int cookieIds = ids == null ? 0 : ids.size();
//try getting id from a url
if (isUsingURLs() && (requestedSessionId == null))
if (isUsingUriParameters())
{
HttpURI uri = request.getHttpURI();
String param = uri.getParam();
param = (param == null ? "" : param.trim());
int start = param.indexOf(getSessionIdPathParameterName());
if (start >= 0)
if (StringUtil.isNotBlank(param))
{
int s = start;
s += getSessionIdPathParameterName().length();
if (param.charAt(s) == '=')
s++;
int i = s;
while (i < param.length())
String name = getSessionIdPathParameterName();
String[] params = param.split(";");
for (String p : params)
{
char c = param.charAt(i);
if (c == ';' || c == '#' || c == '?' || c == '/')
break;
i++;
if (!p.startsWith(name) || p.length() <= name.length() || p.charAt(name.length()) != '=')
continue;
if (ids == null)
ids = new ArrayList<>();
ids.add(p.substring(name.length() + 1).trim());
}
requestedSessionId = param.substring(s, i);
requestedSessionIdFromCookie = false;
}
}
if (ids == null)
return NO_REQUESTED_SESSION;
if (LOG.isDebugEnabled())
LOG.debug("Got Session IDs {} from cookies {}", ids, cookieIds);
for (int i = 0; i < ids.size(); i++)
{
String id = ids.get(i);
if (session == null)
{
//we currently do not have a session selected, use this one if it is valid
ManagedSession s = getManagedSession(id);
if (s != null && s.isValid())
{
//associate it with the request so its reference count is decremented as the
//request exits
requestedSessionId = id;
requestedSessionIdFromCookie = i < cookieIds;
session = s;
if (LOG.isDebugEnabled())
LOG.debug("Selected session {}", session);
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("No session found for session id {}", id);
//if we don't have a valid session id yet, just choose the first one
if (requestedSessionId == null)
{
requestedSessionId = id;
requestedSessionIdFromCookie = i < cookieIds;
}
}
}
else if (session.getId().equals(getSessionIdManager().getId(id)))
{
//we already have a valid session and now have a duplicate ID for it
if (LOG.isDebugEnabled())
LOG.debug("Got Session ID {} from URL", requestedSessionId);
LOG.debug(duplicateSession(
requestedSessionId, true, requestedSessionIdFromCookie,
id, false, i < cookieIds));
}
else
{
//we already have a valid session and now have an ID for a different session
//load the session to see if it is valid or not
ManagedSession s = getManagedSession(id);
if (s != null && s.isValid())
{
try
{
_sessionCache.release(session);
}
catch (Exception x)
{
if (LOG.isDebugEnabled())
LOG.debug("Error releasing duplicate valid session: {}", requestedSessionId);
}
try
{
_sessionCache.release(s);
}
catch (Exception x)
{
if (LOG.isDebugEnabled())
LOG.debug("Error releasing duplicate valid session: {}", id);
}
session = getManagedSession(requestedSessionId);
throw new BadMessageException(duplicateSession(
requestedSessionId, true, requestedSessionIdFromCookie,
id, true, i < cookieIds));
}
else if (LOG.isDebugEnabled())
{
LOG.debug(duplicateSession(
requestedSessionId, true, requestedSessionIdFromCookie,
id, false, i < cookieIds));
}
}
}
return new RequestedSession((session != null && session.isValid()) ? session : null, requestedSessionId, requestedSessionIdFromCookie);
}
private static String duplicateSession(String id0, boolean valid0, boolean cookie0, String id1, boolean valid1, boolean cookie1)
{
return "Duplicate sessions: %s[%s,%s] & %s[%s,%s]".formatted(
id0, valid0 ? "valid" : "unknown", cookie0 ? "cookie" : "param",
id1, valid1 ? "valid" : "unknown", cookie1 ? "cookie" : "param");
}
/**
* Prepare sessions for session manager shutdown
*/
@ -1293,6 +1337,8 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
{
}
private static final RequestedSession NO_REQUESTED_SESSION = new RequestedSession(null, null, false);
/**
* A session cookie is marked as secure IFF any of the following conditions are true:
* <ol>

View File

@ -63,6 +63,7 @@ public class CachingSessionDataStore extends ContainerLifeCycle implements Sessi
}
/**
* Get the delegate session store.
* @return the delegate session store
*/
public SessionDataStore getSessionStore()
@ -71,6 +72,7 @@ public class CachingSessionDataStore extends ContainerLifeCycle implements Sessi
}
/**
* Get the fronting cache for session data.
* @return the fronting cache for session data
*/
public SessionDataMap getSessionDataMap()

View File

@ -27,6 +27,7 @@ public class CachingSessionDataStoreFactory extends AbstractSessionDataStoreFact
protected SessionDataMapFactory _mapFactory;
/**
* Get the SessionDataMapFactory.
* @return the SessionDataMapFactory
*/
public SessionDataMapFactory getMapFactory()
@ -35,6 +36,7 @@ public class CachingSessionDataStoreFactory extends AbstractSessionDataStoreFact
}
/**
* Set the SessionDataMapFactory.
* @param mapFactory the SessionDataMapFactory
*/
public void setSessionDataMapFactory(SessionDataMapFactory mapFactory)

View File

@ -81,6 +81,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
* Set the server associated with this id manager.
* @param server the server associated with this id manager
*/
public void setServer(Server server)
@ -89,6 +90,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
* Get the server associated with this id manager.
* @return the server associated with this id manager
*/
public Server getServer()
@ -153,6 +155,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
* Get the random number generator.
* @return the random number generator
*/
public Random getRandom()
@ -161,6 +164,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
* Set a random number generator for generating ids.
* @param random a random number generator for generating ids
*/
public void setRandom(Random random)
@ -170,6 +174,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
* Get the reseed probability.
* @return the reseed probability
*/
public long getReseed()

View File

@ -32,6 +32,7 @@ public class FileSessionDataStoreFactory extends AbstractSessionDataStoreFactory
}
/**
* Set the deleteUnrestorableFiles to set.
* @param deleteUnrestorableFiles the deleteUnrestorableFiles to set
*/
public void setDeleteUnrestorableFiles(boolean deleteUnrestorableFiles)
@ -40,6 +41,7 @@ public class FileSessionDataStoreFactory extends AbstractSessionDataStoreFactory
}
/**
* Get the storeDir.
* @return the storeDir
*/
public File getStoreDir()
@ -48,6 +50,7 @@ public class FileSessionDataStoreFactory extends AbstractSessionDataStoreFactory
}
/**
* Set the storeDir to set.
* @param storeDir the storeDir to set
*/
public void setStoreDir(File storeDir)

View File

@ -41,6 +41,7 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
}
/**
* Set the {@link DatabaseAdaptor} to set.
* @param adaptor the {@link DatabaseAdaptor} to set
*/
public void setDatabaseAdaptor(DatabaseAdaptor adaptor)
@ -49,6 +50,7 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
}
/**
* Set the {@link JDBCSessionDataStoreFactory} to set.
* @param schema the {@link JDBCSessionDataStoreFactory} to set
*/
public void setSessionTableSchema(JDBCSessionDataStore.SessionTableSchema schema)

View File

@ -65,7 +65,7 @@ public interface SessionConfig
boolean isUsingCookies();
@ManagedAttribute("true if sessions are tracked with URLs")
boolean isUsingURLs();
boolean isUsingUriParameters();
interface Mutable extends SessionConfig
{
@ -99,7 +99,7 @@ public interface SessionConfig
void setUsingCookies(boolean value);
void setUsingURLs(boolean value);
void setUsingUriParameters(boolean value);
void setSessionCache(SessionCache cache);

View File

@ -207,6 +207,7 @@ public class SessionData implements Serializable
}
/**
* Get time at which session was last written out.
* @return time at which session was last written out
*/
public long getLastSaved()
@ -246,6 +247,7 @@ public class SessionData implements Serializable
}
/**
* Set true means non-attribute data has changed.
* @param metaDataDirty true means non-attribute data has changed
*/
public void setMetaDataDirty(boolean metaDataDirty)
@ -311,6 +313,7 @@ public class SessionData implements Serializable
}
/**
* Get the id of the session.
* @return the id of the session
*/
public String getId()
@ -324,6 +327,7 @@ public class SessionData implements Serializable
}
/**
* Get the context path associated with this session.
* @return the context path associated with this session
*/
public String getContextPath()
@ -337,6 +341,7 @@ public class SessionData implements Serializable
}
/**
* Get virtual host of context associated with session.
* @return virtual host of context associated with session
*/
public String getVhost()
@ -350,6 +355,7 @@ public class SessionData implements Serializable
}
/**
* Get last node to manage the session.
* @return last node to manage the session
*/
public String getLastNode()
@ -363,6 +369,7 @@ public class SessionData implements Serializable
}
/**
* Get time at which session expires.
* @return time at which session expires
*/
public long getExpiry()
@ -408,6 +415,7 @@ public class SessionData implements Serializable
}
/**
* Get time cookie was set.
* @return time cookie was set
*/
public long getCookieSet()
@ -421,6 +429,7 @@ public class SessionData implements Serializable
}
/**
* Get time session was accessed.
* @return time session was accessed
*/
public long getAccessed()
@ -434,6 +443,7 @@ public class SessionData implements Serializable
}
/**
* Get previous time session was accessed.
* @return previous time session was accessed
*/
public long getLastAccessed()

View File

@ -92,6 +92,7 @@ public interface SessionIdManager extends LifeCycle
void scavenge();
/**
* Set the housekeeper for doing scavenging.
* @param houseKeeper the housekeeper for doing scavenging
*/
void setSessionHouseKeeper(HouseKeeper houseKeeper);

View File

@ -26,6 +26,7 @@ public class UnreadableSessionDataException extends Exception
private SessionContext _sessionContext;
/**
* Get the session id.
* @return the session id
*/
public String getId()
@ -34,6 +35,7 @@ public class UnreadableSessionDataException extends Exception
}
/**
* Get the SessionContext to which the unreadable session belongs.
* @return the SessionContext to which the unreadable session belongs
*/
public SessionContext getSessionContext()

View File

@ -443,7 +443,7 @@ public abstract class AbstractSessionDataStoreTest
/**
* Test that a session containing no attributes can be stored and re-read
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testEmptyLoadSession() throws Exception

View File

@ -203,7 +203,7 @@ public class AbstractSessionManagerTest
* Test that an immortal session is never scavenged, regardless of whether it
* is evicted from the cache or not.
*
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testImmortalScavenge() throws Exception
@ -256,7 +256,7 @@ public class AbstractSessionManagerTest
/**
* Test that a session that has a max valid time is always scavenged,
* regardless of whether it is evicted from the cache or not.
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testNonImmortalScavenge() throws Exception

View File

@ -321,7 +321,7 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest
* Test that the DefaultSessionCache shares the session object amongst
* requests.
*
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testSessionShared() throws Exception
@ -352,7 +352,7 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest
/**
* Test adding a session to the cache
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testAdd()
@ -389,7 +389,7 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest
/**
* Test releasing use of a session
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testRelease()
@ -556,7 +556,7 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest
* Test that if saveOnEviction==true, the session will be persisted before
* it is evicted.
*
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testSaveOnEviction()
@ -600,7 +600,7 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest
/**
* Test that when saveOnEviction=true, if the save fails, the session
* remains in the cache and can be used later.
* @throws Exception
* @throws Exception if there is an unspecified problem
*/
@Test
public void testSaveOnEvictionFail() throws Exception

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.Session;
import org.eclipse.jetty.util.Callback;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -40,12 +41,13 @@ import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
/**
* SimpleSessionHandlerTest
* SessionHandlerTest
*/
public class SessionHandlerTest
{
private Server _server;
private LocalConnector _connector;
private SessionHandler _sessionHandler;
private static final Logger LOGGER = LoggerFactory.getLogger(SessionHandlerTest.class);
@ -57,14 +59,15 @@ public class SessionHandlerTest
_connector = new LocalConnector(_server);
_server.addConnector(_connector);
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setSessionCookie("SIMPLE");
sessionHandler.setUsingCookies(true);
sessionHandler.setUsingURLs(false);
sessionHandler.setSessionPath("/");
_server.setHandler(sessionHandler);
_sessionHandler = new SessionHandler();
_sessionHandler.setSessionCookie("SESSION_ID");
_sessionHandler.setSessionIdPathParameterName("session_id");
_sessionHandler.setUsingCookies(true);
_sessionHandler.setUsingUriParameters(false);
_sessionHandler.setSessionPath("/");
_server.setHandler(_sessionHandler);
sessionHandler.setHandler(new Handler.Abstract()
_sessionHandler.setHandler(new Handler.Abstract()
{
@Override
public boolean handle(Request request, Response response, Callback callback)
@ -147,6 +150,9 @@ public class SessionHandlerTest
out.append("New\n");
for (String name : session.getAttributeNameSet())
out.append("Attribute ").append(name).append(" = ").append(session.getAttribute(name)).append('\n');
out.append("URI [")
.append(session.encodeURI(request, "/some/path", request.getHeaders().contains(HttpHeader.COOKIE)))
.append("]");
}
else
{
@ -178,7 +184,7 @@ public class SessionHandlerTest
GET / HTTP/1.1
Host: localhost
Cookie: SIMPLE=oldCookieId
Cookie: SESSION_ID=oldCookieId
""");
@ -200,11 +206,11 @@ public class SessionHandlerTest
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SIMPLE=oldCookieId
Cookie: SESSION_ID=oldCookieId
GET /create HTTP/1.1
Host: localhost
Cookie: SIMPLE=oldCookieId
Cookie: SESSION_ID=oldCookieId
""");
@ -216,7 +222,7 @@ public class SessionHandlerTest
assertThat(response.getStatus(), equalTo(200));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SIMPLE=") + 7, setCookie.indexOf("; Path=/"));
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
assertThat(id, not(equalTo("oldCookieId")));
String content = response.getContent();
@ -225,7 +231,7 @@ public class SessionHandlerTest
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
""".formatted(id));
@ -251,18 +257,18 @@ public class SessionHandlerTest
HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SIMPLE=") + 7, setCookie.indexOf("; Path=/"));
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
String content = response.getContent();
assertThat(content, startsWith("Session="));
endPoint.addInput("""
GET /set/attribute/value HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
GET /set/another/attribute HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
""".formatted(id, id));
@ -299,16 +305,16 @@ public class SessionHandlerTest
assertThat(content, startsWith("Session="));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SIMPLE=") + 7, setCookie.indexOf("; Path=/"));
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
endPoint.addInput("""
GET /set/attribute/value HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
GET /change HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
""".formatted(id, id));
@ -322,7 +328,7 @@ public class SessionHandlerTest
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
setCookie = response.get(HttpHeader.SET_COOKIE);
String newId = setCookie.substring(setCookie.indexOf("SIMPLE=") + 7, setCookie.indexOf("; Path=/"));
String newId = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
assertThat(newId, not(id));
id = newId;
@ -333,7 +339,7 @@ public class SessionHandlerTest
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SIMPLE=%s
Cookie: SESSION_ID=%s
""".formatted(id));
@ -452,4 +458,267 @@ public class SessionHandlerTest
assertThat(history.get(3), containsString("n1: v1->V1"));
assertThat(history.get(4), containsString("n2: v2->null"));
}
@Test
public void testCookieAndURI() throws Exception
{
_sessionHandler.setUsingCookies(true);
_sessionHandler.setUsingUriParameters(true);
_server.start();
try (LocalConnector.LocalEndPoint endPoint = _connector.connect())
{
endPoint.addInput("""
GET /create HTTP/1.1
Host: localhost
""");
HttpTester.Response response;
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
String content = response.getContent();
assertThat(content, startsWith("Session="));
assertThat(content, containsString("URI [/some/path;session_id=%s]".formatted(id))); // Cookies not known to be in use
// Get with cookie
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path]")); // Cookies known to be in use
// Get with parameter
endPoint.addInput("""
GET /;session_id=%s HTTP/1.1
Host: localhost
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path;session_id=%s]".formatted(id))); // Cookies not in use
// Get with both, but param wrong
endPoint.addInput("""
GET /;session_id=wrong HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path]")); // Cookies known to be in use
// Get with both, but cookie wrong
endPoint.addInput("""
GET /;session_id=%s HTTP/1.1
Host: localhost
Cookie: SESSION_ID=wrong
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path]")); // Cookies known to be in use
}
}
@Test
public void testCookieOnly() throws Exception
{
_sessionHandler.setUsingCookies(true);
_sessionHandler.setUsingUriParameters(false);
_server.start();
try (LocalConnector.LocalEndPoint endPoint = _connector.connect())
{
endPoint.addInput("""
GET /create HTTP/1.1
Host: localhost
""");
HttpTester.Response response;
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
String content = response.getContent();
assertThat(content, startsWith("Session="));
assertThat(content, containsString("URI [/some/path]"));
// Get with cookie
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path]")); // Cookies known to be in use
// Get with multiple cookie
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SESSION_ID=wrong
Cookie: SESSION_ID=%s
Cookie: SESSION_ID=other
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path]")); // Cookies known to be in use
// Try with parameter
endPoint.addInput("""
GET /;session_id=%s HTTP/1.1
Host: localhost
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("No Session"));
// Get with bad cookies
endPoint.addInput("""
GET /;session_id=%s HTTP/1.1
Host: localhost
Cookie: SESSION_ID
Cookie: SESSION_ID=
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("No Session"));
}
}
@Test
public void testUriParameterOnly() throws Exception
{
_sessionHandler.setUsingCookies(false);
_sessionHandler.setUsingUriParameters(true);
_server.start();
try (LocalConnector.LocalEndPoint endPoint = _connector.connect())
{
endPoint.addInput("""
GET /create HTTP/1.1
Host: localhost
""");
HttpTester.Response response;
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
Assert.assertNull(response.get(HttpHeader.SET_COOKIE));
String content = response.getContent();
assertThat(content, startsWith("Session="));
int i = content.indexOf("Session=");
String id = content.substring(i + 8, content.indexOf("\n", i + 8)) + ".node0";
assertThat(content, containsString("URI [/some/path;session_id=%s]".formatted(id)));
// Try with cookie
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("No Session"));
// Get with parameter
endPoint.addInput("""
GET /;session_id=%s HTTP/1.1
Host: localhost
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path;session_id=%s]".formatted(id)));
// Get with multiple parameters
endPoint.addInput("""
GET /;session_id=wrong;session_id=%s;session_id=other;session_id=;session_id HTTP/1.1
Host: localhost
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("URI [/some/path;session_id=%s]".formatted(id)));
// Get with bad parameter
endPoint.addInput("""
GET /;session_id=;session_id HTTP/1.1
Host: localhost
""");
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
assertThat(response.getStatus(), equalTo(200));
content = response.getContent();
assertThat(content, containsString("No Session"));
}
}
}

View File

@ -36,6 +36,7 @@ public class AtomicBiInteger extends AtomicLong
}
/**
* Get the hi value.
* @return the hi value
*/
public int getHi()
@ -55,6 +56,7 @@ public class AtomicBiInteger extends AtomicLong
}
/**
* Get the lo value.
* @return the lo value
*/
public int getLo()

View File

@ -761,6 +761,7 @@ public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQu
}
/**
* Get the current capacity of this queue.
* @return the current capacity of this queue
*/
public int getCapacity()
@ -777,6 +778,7 @@ public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQu
}
/**
* Get the max capacity of this queue, or -1 if this queue is unbounded.
* @return the max capacity of this queue, or -1 if this queue is unbounded
*/
public int getMaxCapacity()

View File

@ -263,6 +263,7 @@ public class Fields implements Iterable<Fields.Field>
}
/**
* Get the number of fields.
* @return the number of fields
*/
public int getSize()

View File

@ -72,6 +72,7 @@ public class JavaVersion
}
/**
* Get the string from which this JavaVersion was created.
* @return the string from which this JavaVersion was created
*/
public String getVersion()

View File

@ -118,6 +118,7 @@ public class VirtualThreads
}
/**
* Get a default virtual thread per task {@code Executor}.
* @return a default virtual thread per task {@code Executor}
*/
public static Executor getDefaultVirtualThreadsExecutor()

View File

@ -83,6 +83,7 @@ public abstract class CompressionPool<T> extends ContainerLifeCycle
}
/**
* Release an Entry.
* @param entry returns this Object to the pool or calls {@link #end(Object)} if the pool is full.
*/
public void release(Entry entry)

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