Merge remote-tracking branch 'origin/jetty-12.0.x' into fix/12.0.x/bundle-copyright-update
This commit is contained in:
commit
460fdc60ec
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -50,6 +50,7 @@ public class MetaDataBuilder
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the maxSize.
|
||||
* @return the maxSize
|
||||
*/
|
||||
public int getMaxSize()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -56,6 +56,7 @@ public class ObjectMBean implements DynamicMBean
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the managed object.
|
||||
* @return the managed object
|
||||
*/
|
||||
public Object getManagedObject()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -52,6 +52,7 @@ public class InvalidURIRule extends Rule
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the response code.
|
||||
* @param code the response code
|
||||
*/
|
||||
public void setCode(int code)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -34,6 +34,7 @@ public abstract class RegexRule extends Rule
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the regular expression.
|
||||
* @return the regular expression
|
||||
*/
|
||||
public String getRegex()
|
||||
|
|
|
@ -52,6 +52,7 @@ public class ResponsePatternRule extends PatternRule
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the response code.
|
||||
* @param code the response code
|
||||
*/
|
||||
public void setCode(int code)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -263,6 +263,7 @@ public class Fields implements Iterable<Fields.Field>
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the number of fields.
|
||||
* @return the number of fields
|
||||
*/
|
||||
public int getSize()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue