Merge pull request #8413 from eclipse/jetty-12.0.x-websocket-upgrade-contract
Jetty 12 : Strengthen WebSocket upgrade contract and other improvements
This commit is contained in:
commit
97dd7b30d2
|
@ -32,6 +32,10 @@ public final class WebSocketConstants
|
|||
public static final Duration DEFAULT_IDLE_TIMEOUT = Duration.ofSeconds(30);
|
||||
public static final Duration DEFAULT_WRITE_TIMEOUT = Duration.ZERO;
|
||||
|
||||
// Attributes for storing API requests as attributes on the base jetty-core request.
|
||||
public static final String WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE = "org.eclipse.jetty.websocket.wrappedRequest";
|
||||
public static final String WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE = "org.eclipse.jetty.websocket.wrappedResponse";
|
||||
|
||||
/**
|
||||
* Globally Unique Identifier for use in WebSocket handshake within {@code Sec-WebSocket-Accept} and <code>Sec-WebSocket-Key</code> http headers.
|
||||
* <p>
|
||||
|
|
|
@ -29,5 +29,33 @@ public interface Handshaker
|
|||
return new HandshakerSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A preliminary check to see if a request is likely to be a valid WebSocket Upgrade Request. If this returns true
|
||||
* the {@link Request} may be a valid upgrade request, but if this returns false returns false you can avoid calling
|
||||
* {@link #upgradeRequest(WebSocketNegotiator, Request, Response, Callback, WebSocketComponents, Configuration.Customizer)}
|
||||
* entirely as it will always fail</p>
|
||||
*
|
||||
* @param request the request
|
||||
* @return true if the request is thought to be a valid websocket upgrade request.
|
||||
*/
|
||||
boolean isWebSocketUpgradeRequest(Request request);
|
||||
|
||||
/**
|
||||
* <p>Attempts to upgrade a request to WebSocket.</p>
|
||||
*
|
||||
* <p>Returns {@code true} if the WebSocket upgrade is successful and a successful response is generated and the callback
|
||||
* eventually completed, or if the WebSocket upgrade failed and a failure response is generated and the callback eventually
|
||||
* completed. Returns {@code false} if a response is not generated and the caller is responsible for generating a response
|
||||
* and completing the callback.</p>
|
||||
*
|
||||
* @param negotiator the negotiator
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param callback the callback
|
||||
* @param components the WebSocket components
|
||||
* @param defaultCustomizer the customizer
|
||||
* @return true if a response was generated, false if a response is not generated
|
||||
* @throws IOException there is an error during the upgrade
|
||||
*/
|
||||
boolean upgradeRequest(WebSocketNegotiator negotiator, Request request, Response response, Callback callback, WebSocketComponents components, Configuration.Customizer defaultCustomizer) throws IOException;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.internal.WebSocketNegotiation;
|
||||
|
||||
/**
|
||||
* Upgrade request used for websocket negotiation.
|
||||
|
@ -41,6 +43,11 @@ public class ServerUpgradeRequest extends Request.Wrapper
|
|||
this.request = baseRequest;
|
||||
}
|
||||
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return negotiation.getWebSocketComponents();
|
||||
}
|
||||
|
||||
public void upgrade(Attributes attributes)
|
||||
{
|
||||
this.attributes.clearAttributes();
|
||||
|
@ -94,7 +101,6 @@ public class ServerUpgradeRequest extends Request.Wrapper
|
|||
|
||||
/**
|
||||
* @return The extensions offered
|
||||
* @see WebSocketNegotiation#getOfferedExtensions()
|
||||
*/
|
||||
public List<ExtensionConfig> getExtensions()
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.eclipse.jetty.http.HttpFields;
|
|||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.server.internal.WebSocketHttpFieldsWrapper;
|
||||
import org.eclipse.jetty.websocket.core.server.internal.WebSocketNegotiation;
|
||||
|
||||
/**
|
||||
* Upgrade response used for websocket negotiation.
|
||||
|
|
|
@ -15,12 +15,11 @@ package org.eclipse.jetty.websocket.core.server;
|
|||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
// TODO: improve javadoc.
|
||||
/**
|
||||
* Abstract WebSocket creator interface.
|
||||
* <p>
|
||||
* Should you desire filtering of the WebSocket object creation due to criteria such as origin or sub-protocol,
|
||||
* then you will be required to implement a custom WebSocketCreator implementation.
|
||||
* This can be used for filtering of the WebSocket object creation due to criteria such as origin or sub-protocol,
|
||||
* or for choosing a specific WebSocket object based on the upgrade request.
|
||||
* </p>
|
||||
*/
|
||||
public interface WebSocketCreator
|
||||
|
@ -28,10 +27,14 @@ public interface WebSocketCreator
|
|||
/**
|
||||
* Create a websocket from the incoming request.
|
||||
*
|
||||
* @param req the request details
|
||||
* @param resp the response details
|
||||
* @param callback callback
|
||||
* @return a websocket object to use, or null if no websocket should be created from this request.
|
||||
* <p>If the creator returns null it is responsible for completing the {@link Callback} and sending a response.
|
||||
* But if the creator intends to return non-null WebSocket object, it MUST NOT write content to the response or
|
||||
* complete the {@link Callback}, but it may modify the response headers.</p>
|
||||
*
|
||||
* @param request the request details
|
||||
* @param response the response details
|
||||
* @param callback the callback, should only be completed by the creator if a null WebSocket object is returned.
|
||||
* @return the WebSocket object, or null to take responsibility to send error response if no WebSocket is to be created.
|
||||
*/
|
||||
Object createWebSocket(ServerUpgradeRequest req, ServerUpgradeResponse resp, Callback callback);
|
||||
Object createWebSocket(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback);
|
||||
}
|
||||
|
|
|
@ -229,6 +229,21 @@ public class WebSocketMappings implements Dumpable, LifeCycle.Listener
|
|||
return negotiator;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to find a WebSocket mapping and upgrade a request to WebSocket.</p>
|
||||
*
|
||||
* <p>Returns {@code true} if the WebSocket upgrade is successful and a successful response is generated and the callback
|
||||
* eventually completed, or if the WebSocket upgrade failed and a failure response is generated and the callback eventually
|
||||
* completed. Returns {@code false} if a response is not generated and the caller is responsible for generating a response
|
||||
* and completing the callback.</p>
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param callback the callback
|
||||
* @param defaultCustomizer the customizer
|
||||
* @return true if the WebSocket upgrade was accepted
|
||||
* @throws IOException there is an error during the upgrade
|
||||
*/
|
||||
public boolean upgrade(Request request, Response response, Callback callback, Configuration.Customizer defaultCustomizer) throws IOException
|
||||
{
|
||||
String target = request.getPathInContext();
|
||||
|
@ -239,13 +254,25 @@ public class WebSocketMappings implements Dumpable, LifeCycle.Listener
|
|||
request.setAttribute(PathSpec.class.getName(), pathSpec);
|
||||
});
|
||||
|
||||
if (negotiator == null)
|
||||
return false;
|
||||
|
||||
// We have an upgrade request
|
||||
return handshaker.upgradeRequest(negotiator, request, response, callback, components, defaultCustomizer);
|
||||
return upgrade(negotiator, request, response, callback, defaultCustomizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to find a WebSocket mapping and upgrade a request to WebSocket.</p>
|
||||
*
|
||||
* <p>Returns {@code true} if the WebSocket upgrade is successful and a successful response is generated and the callback
|
||||
* eventually completed, or if the WebSocket upgrade failed and a failure response is generated and the callback eventually
|
||||
* completed. Returns {@code false} if a response is not generated and the caller is responsible for generating a response
|
||||
* and completing the callback.</p>
|
||||
*
|
||||
* @param negotiator the negotiator
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param callback the callback
|
||||
* @param defaultCustomizer the customizer
|
||||
* @return true if the WebSocket upgrade was accepted
|
||||
* @throws IOException there is an error during the upgrade
|
||||
*/
|
||||
public boolean upgrade(WebSocketNegotiator negotiator, Request request, Response response, Callback callback, Configuration.Customizer defaultCustomizer) throws IOException
|
||||
{
|
||||
if (negotiator == null)
|
||||
|
|
|
@ -13,38 +13,26 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.internal.CreatorNegotiator;
|
||||
|
||||
public interface WebSocketNegotiator extends Configuration.Customizer
|
||||
{
|
||||
FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException;
|
||||
|
||||
@Override
|
||||
default void customize(Configuration configurable)
|
||||
{
|
||||
}
|
||||
|
||||
static WebSocketNegotiator from(Function<WebSocketNegotiation, FrameHandler> negotiate)
|
||||
{
|
||||
return from(negotiate, null);
|
||||
}
|
||||
|
||||
static WebSocketNegotiator from(Function<WebSocketNegotiation, FrameHandler> negotiate, Configuration.Customizer customizer)
|
||||
{
|
||||
return new AbstractNegotiator(customizer)
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation)
|
||||
{
|
||||
return negotiate.apply(negotiation);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* <p>Creates a {@link FrameHandler} from the incoming request.</p>
|
||||
*
|
||||
* <p>If the negotiator returns null it is responsible for completing the {@link Callback} and sending a response.
|
||||
* If the negotiator intends to return non-null {@link FrameHandler}, it MUST NOT write content to the response or
|
||||
* complete the {@link Callback}, but it may modify the response headers.</p>
|
||||
*
|
||||
* @param request the request details
|
||||
* @param response the response details
|
||||
* @param callback the callback, should only be completed by the creator if a null WebSocket object is returned.
|
||||
* @return the FrameHandler, or null to take responsibility to send error response if no WebSocket is to be created.
|
||||
*/
|
||||
FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback);
|
||||
|
||||
static WebSocketNegotiator from(WebSocketCreator creator, FrameHandlerFactory factory)
|
||||
{
|
||||
|
@ -56,6 +44,11 @@ public interface WebSocketNegotiator extends Configuration.Customizer
|
|||
return new CreatorNegotiator(creator, factory, customizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void customize(Configuration configurable)
|
||||
{
|
||||
}
|
||||
|
||||
abstract class AbstractNegotiator extends Configuration.ConfigurationCustomizer implements WebSocketNegotiator
|
||||
{
|
||||
final Configuration.Customizer customizer;
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.eclipse.jetty.websocket.core.internal.Negotiated;
|
|||
import org.eclipse.jetty.websocket.core.internal.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession;
|
||||
import org.eclipse.jetty.websocket.core.server.Handshaker;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -56,7 +55,7 @@ public abstract class AbstractHandshaker implements Handshaker
|
|||
@Override
|
||||
public boolean upgradeRequest(WebSocketNegotiator negotiator, Request request, Response response, Callback callback, WebSocketComponents components, Configuration.Customizer defaultCustomizer) throws IOException
|
||||
{
|
||||
if (!validateRequest(request))
|
||||
if (!isWebSocketUpgradeRequest(request))
|
||||
return false;
|
||||
|
||||
WebSocketNegotiation negotiation = newNegotiation(request, response, callback, components);
|
||||
|
@ -68,7 +67,7 @@ public abstract class AbstractHandshaker implements Handshaker
|
|||
return false;
|
||||
|
||||
// Negotiate the FrameHandler
|
||||
FrameHandler handler = negotiator.negotiate(negotiation);
|
||||
FrameHandler handler = negotiator.negotiate(negotiation.getRequest(), negotiation.getResponse(), negotiation.getCallback());
|
||||
if (handler == null)
|
||||
return true;
|
||||
|
||||
|
@ -156,10 +155,22 @@ public abstract class AbstractHandshaker implements Handshaker
|
|||
return true;
|
||||
}
|
||||
|
||||
protected abstract boolean validateRequest(Request request);
|
||||
|
||||
protected abstract WebSocketNegotiation newNegotiation(Request request, Response response, Callback callback, WebSocketComponents webSocketComponents);
|
||||
|
||||
@Override
|
||||
public boolean isWebSocketUpgradeRequest(Request request)
|
||||
{
|
||||
String wsVersionHeader = request.getHeaders().get(HttpHeader.SEC_WEBSOCKET_VERSION);
|
||||
if (!WebSocketConstants.SPEC_VERSION_STRING.equals(wsVersionHeader))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("not upgraded: unsupported version {} {}", wsVersionHeader, request);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean validateNegotiation(WebSocketNegotiation negotiation)
|
||||
{
|
||||
if (!negotiation.validateHeaders())
|
||||
|
@ -169,13 +180,6 @@ public abstract class AbstractHandshaker implements Handshaker
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!WebSocketConstants.SPEC_VERSION_STRING.equals(negotiation.getVersion()))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("not upgraded: unsupported version {} {}", negotiation.getVersion(), negotiation.getRequest());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,16 +13,15 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.server.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.server.Context;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
|
||||
public class CreatorNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
||||
|
@ -48,28 +47,25 @@ public class CreatorNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
|||
}
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
Context context = negotiation.getRequest().getContext();
|
||||
ServerUpgradeRequest upgradeRequest = negotiation.getRequest();
|
||||
ServerUpgradeResponse upgradeResponse = negotiation.getResponse();
|
||||
|
||||
Context context = request.getContext();
|
||||
Object websocketPojo;
|
||||
try
|
||||
{
|
||||
AtomicReference<Object> result = new AtomicReference<>();
|
||||
context.run(() -> result.set(creator.createWebSocket(upgradeRequest, upgradeResponse, negotiation.getCallback())));
|
||||
context.run(() -> result.set(creator.createWebSocket(request, response, callback)));
|
||||
websocketPojo = result.get();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
negotiation.getCallback().failed(t);
|
||||
callback.failed(t);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (websocketPojo == null)
|
||||
return null;
|
||||
return factory.newFrameHandler(websocketPojo, upgradeRequest, upgradeResponse);
|
||||
return factory.newFrameHandler(websocketPojo, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,6 +33,12 @@ public class HandshakerSelector implements Handshaker
|
|||
private final RFC6455Handshaker rfc6455 = new RFC6455Handshaker();
|
||||
private final RFC8441Handshaker rfc8441 = new RFC8441Handshaker();
|
||||
|
||||
@Override
|
||||
public boolean isWebSocketUpgradeRequest(Request request)
|
||||
{
|
||||
return rfc6455.isWebSocketUpgradeRequest(request) || rfc8441.isWebSocketUpgradeRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean upgradeRequest(WebSocketNegotiator negotiator, Request request, Response response, Callback callback, WebSocketComponents components, Configuration.Customizer defaultCustomizer) throws IOException
|
||||
{
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
|||
import org.eclipse.jetty.websocket.core.internal.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCore;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
|
||||
public final class RFC6455Handshaker extends AbstractHandshaker
|
||||
{
|
||||
|
@ -40,7 +39,7 @@ public final class RFC6455Handshaker extends AbstractHandshaker
|
|||
private static final HttpField CONNECTION_UPGRADE = new PreEncodedHttpField(HttpHeader.CONNECTION, HttpHeader.UPGRADE.asString());
|
||||
|
||||
@Override
|
||||
protected boolean validateRequest(Request request)
|
||||
public boolean isWebSocketUpgradeRequest(Request request)
|
||||
{
|
||||
if (!HttpMethod.GET.is(request.getMethod()))
|
||||
{
|
||||
|
@ -56,7 +55,7 @@ public final class RFC6455Handshaker extends AbstractHandshaker
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return super.isWebSocketUpgradeRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.eclipse.jetty.server.Request;
|
|||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
|
||||
public class RFC6455Negotiation extends WebSocketNegotiation
|
||||
{
|
||||
|
|
|
@ -27,12 +27,11 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
|
||||
public class RFC8441Handshaker extends AbstractHandshaker
|
||||
{
|
||||
@Override
|
||||
protected boolean validateRequest(Request request)
|
||||
public boolean isWebSocketUpgradeRequest(Request request)
|
||||
{
|
||||
if (!HttpMethod.CONNECT.is(request.getMethod()))
|
||||
{
|
||||
|
@ -48,7 +47,7 @@ public class RFC8441Handshaker extends AbstractHandshaker
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return super.isWebSocketUpgradeRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.eclipse.jetty.server.Request;
|
|||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
|
||||
public class RFC8441Negotiation extends WebSocketNegotiation
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.util.Collections;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
|
||||
public class WebSocketHttpFieldsWrapper extends HttpFieldsWrapper
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.core.server;
|
||||
package org.eclipse.jetty.websocket.core.server.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -28,6 +28,8 @@ import org.eclipse.jetty.server.Response;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
||||
public abstract class WebSocketNegotiation
|
||||
{
|
||||
|
@ -64,6 +66,11 @@ public abstract class WebSocketNegotiation
|
|||
return callback;
|
||||
}
|
||||
|
||||
public WebSocketComponents getWebSocketComponents()
|
||||
{
|
||||
return components;
|
||||
}
|
||||
|
||||
public void negotiate() throws BadMessageException
|
||||
{
|
||||
try
|
|
@ -23,7 +23,6 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -47,7 +46,7 @@ public class DemandTest
|
|||
|
||||
WebSocketUpgradeHandler upgradeHandler = new WebSocketUpgradeHandler();
|
||||
_server.setHandler(upgradeHandler);
|
||||
upgradeHandler.addMapping("/", WebSocketNegotiator.from((neg) -> new EchoFrameHandler()));
|
||||
upgradeHandler.addMapping("/", (req, resp, cb) -> new EchoFrameHandler());
|
||||
_server.start();
|
||||
|
||||
_client = new WebSocketCoreClient();
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
|
||||
public class TestWebSocketNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
||||
|
@ -35,12 +36,11 @@ public class TestWebSocketNegotiator extends WebSocketNegotiator.AbstractNegotia
|
|||
}
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubprotocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubprotocols = request.getSubProtocols();
|
||||
if (!offeredSubprotocols.isEmpty())
|
||||
negotiation.setSubprotocol(offeredSubprotocols.get(0));
|
||||
|
||||
response.setAcceptedSubProtocol(offeredSubprotocols.get(0));
|
||||
return frameHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.eclipse.jetty.util.Blocker;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.client.CoreClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -64,7 +63,7 @@ public class WebSocketEchoTest
|
|||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
_upgradeHandler.addMapping("/", WebSocketNegotiator.from(n -> new EchoFrameHandler()));
|
||||
_upgradeHandler.addMapping("/", (req, resp, cb) -> new EchoFrameHandler());
|
||||
TestMessageHandler clientHandler = new TestMessageHandler();
|
||||
URI uri = URI.create("ws://localhost:" + _serverConnector.getLocalPort());
|
||||
CoreClientUpgradeRequest upgradeRequest = CoreClientUpgradeRequest.from(_client, uri, clientHandler);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -37,7 +36,8 @@ import org.eclipse.jetty.websocket.core.client.UpgradeListener;
|
|||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.exception.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -79,32 +79,32 @@ public class WebSocketNegotiationTest extends WebSocketTester
|
|||
WebSocketNegotiator negotiator = new WebSocketNegotiator.AbstractNegotiator()
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
if (negotiation.getOfferedSubprotocols().isEmpty())
|
||||
if (request.getSubProtocols().isEmpty())
|
||||
{
|
||||
negotiation.setSubprotocol("NotOffered");
|
||||
response.setAcceptedSubProtocol("NotOffered");
|
||||
return new EchoFrameHandler();
|
||||
}
|
||||
|
||||
String subprotocol = negotiation.getOfferedSubprotocols().get(0);
|
||||
negotiation.setSubprotocol(subprotocol);
|
||||
String subprotocol = request.getSubProtocols().get(0);
|
||||
response.setAcceptedSubProtocol(subprotocol);
|
||||
switch (subprotocol)
|
||||
{
|
||||
case "testExtensionSelection":
|
||||
negotiation.setNegotiatedExtensions(List.of(ExtensionConfig.parse("permessage-deflate;client_no_context_takeover")));
|
||||
response.setExtensions(List.of(ExtensionConfig.parse("permessage-deflate;client_no_context_takeover")));
|
||||
break;
|
||||
|
||||
case "testNotOfferedParameter":
|
||||
negotiation.setNegotiatedExtensions(List.of(ExtensionConfig.parse("permessage-deflate;server_no_context_takeover")));
|
||||
response.setExtensions(List.of(ExtensionConfig.parse("permessage-deflate;server_no_context_takeover")));
|
||||
break;
|
||||
|
||||
case "testNotAcceptingExtensions":
|
||||
negotiation.setNegotiatedExtensions(Collections.emptyList());
|
||||
response.setExtensions(Collections.emptyList());
|
||||
break;
|
||||
|
||||
case "testNoSubProtocolSelected":
|
||||
negotiation.setSubprotocol(null);
|
||||
response.setAcceptedSubProtocol(null);
|
||||
break;
|
||||
|
||||
case "test":
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -21,8 +20,10 @@ import org.eclipse.jetty.server.NetworkConnector;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
|
||||
|
@ -112,12 +113,11 @@ public class WebSocketServer
|
|||
}
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubprotocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubprotocols = request.getSubProtocols();
|
||||
if (!offeredSubprotocols.isEmpty())
|
||||
negotiation.setSubprotocol(offeredSubprotocols.get(0));
|
||||
|
||||
response.setAcceptedSubProtocol(offeredSubprotocols.get(0));
|
||||
return frameHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ import org.eclipse.jetty.websocket.core.CoreSession;
|
|||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -47,7 +47,7 @@ public class ChatWebSocketServer
|
|||
|
||||
private final Set<MessageHandler> members = new HashSet<>();
|
||||
|
||||
private FrameHandler negotiate(WebSocketNegotiation negotiation)
|
||||
private FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
// Finalize negotiations in API layer involves:
|
||||
// + MAY mutate the policy
|
||||
|
@ -56,10 +56,10 @@ public class ChatWebSocketServer
|
|||
// + MAY reject with sendError semantics
|
||||
// + MAY change/add/remove offered extensions
|
||||
// + MUST pick subprotocol
|
||||
List<String> subprotocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> subprotocols = request.getSubProtocols();
|
||||
if (!subprotocols.contains("chat"))
|
||||
return null;
|
||||
negotiation.setSubprotocol("chat");
|
||||
response.setAcceptedSubProtocol("chat");
|
||||
|
||||
// + MUST return the FrameHandler or null or exception?
|
||||
return new MessageHandler()
|
||||
|
@ -115,7 +115,7 @@ public class ChatWebSocketServer
|
|||
ChatWebSocketServer chat = new ChatWebSocketServer();
|
||||
WebSocketComponents components = new WebSocketComponents();
|
||||
WebSocketUpgradeHandler upgradeHandler = new WebSocketUpgradeHandler(components);
|
||||
upgradeHandler.addMapping(new ServletPathSpec("/*"), WebSocketNegotiator.from(chat::negotiate));
|
||||
upgradeHandler.addMapping(new ServletPathSpec("/*"), chat::negotiate);
|
||||
context.setHandler(upgradeHandler);
|
||||
|
||||
upgradeHandler.setHandler(new Handler.Processor()
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.extensions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
@ -36,7 +35,8 @@ import org.eclipse.jetty.websocket.core.WebSocketServer;
|
|||
import org.eclipse.jetty.websocket.core.client.CoreClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.client.UpgradeListener;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -64,14 +64,14 @@ public class PerMessageDeflaterBufferSizeTest
|
|||
int inflateBufferSize = -1;
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
for (ExtensionConfig extensionConfig : negotiation.getOfferedExtensions())
|
||||
for (ExtensionConfig extensionConfig : request.getExtensions())
|
||||
{
|
||||
assertFalse(extensionConfig.getName().startsWith("@"));
|
||||
}
|
||||
|
||||
for (ExtensionConfig extensionConfig : negotiation.getNegotiatedExtensions())
|
||||
for (ExtensionConfig extensionConfig : response.getExtensions())
|
||||
{
|
||||
if ("permessage-deflate".equals(extensionConfig.getName()))
|
||||
{
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.eclipse.jetty.websocket.core.OpCode;
|
|||
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.client.CoreClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -77,7 +76,7 @@ public class PermessageDeflateDemandTest
|
|||
public void test() throws Exception
|
||||
{
|
||||
ServerHandler serverHandler = new ServerHandler();
|
||||
_upgradeHandler.addMapping("/", WebSocketNegotiator.from(n -> serverHandler));
|
||||
_upgradeHandler.addMapping("/", (req, resp, cb) -> serverHandler);
|
||||
|
||||
TestFrameHandler clientHandler = new TestFrameHandler();
|
||||
URI uri = URI.create("ws://localhost:" + _connector.getLocalPort());
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.extensions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
|
@ -30,7 +30,8 @@ import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
|||
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketServer;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketTester;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -53,14 +54,14 @@ public class ValidationExtensionTest extends WebSocketTester
|
|||
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(serverHandler)
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<ExtensionConfig> negotiatedExtensions = new ArrayList<>();
|
||||
negotiatedExtensions.add(ExtensionConfig.parse(
|
||||
"@validation; outgoing-sequence; incoming-sequence; outgoing-frame; incoming-frame; incoming-utf8; outgoing-utf8"));
|
||||
negotiation.setNegotiatedExtensions(negotiatedExtensions);
|
||||
response.setExtensions(negotiatedExtensions);
|
||||
|
||||
return super.negotiate(negotiation);
|
||||
return super.negotiate(request, response, callback);
|
||||
}
|
||||
};
|
||||
server = new WebSocketServer(negotiator);
|
||||
|
|
|
@ -35,12 +35,15 @@ import org.eclipse.jetty.websocket.core.Configuration;
|
|||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.EchoFrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.TestAsyncFrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.client.CoreClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -113,7 +116,14 @@ public class WebSocketProxyTest
|
|||
handlers.addHandler(serverContext);
|
||||
|
||||
ContextHandler proxyContext = new ContextHandler("/proxy");
|
||||
negotiator = WebSocketNegotiator.from(negotiation -> proxy.client2Proxy, defaultCustomizer);
|
||||
negotiator = new WebSocketNegotiator.AbstractNegotiator(defaultCustomizer)
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
return proxy.client2Proxy;
|
||||
}
|
||||
};
|
||||
upgradeHandler = new WebSocketUpgradeHandler();
|
||||
upgradeHandler.addMapping("/*", negotiator);
|
||||
proxyContext.setHandler(upgradeHandler);
|
||||
|
|
|
@ -86,7 +86,6 @@ import org.slf4j.LoggerFactory;
|
|||
public class ServletContextRequest extends ContextRequest implements Runnable
|
||||
{
|
||||
public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig";
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServletContextRequest.class);
|
||||
private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault());
|
||||
private static final int INPUT_NONE = 0;
|
||||
|
|
|
@ -85,7 +85,7 @@ public class ServletContextResponse extends ContextResponse
|
|||
private ResponseWriter _writer;
|
||||
|
||||
private long _contentLength = -1;
|
||||
|
||||
|
||||
public static ServletContextResponse getBaseResponse(ServletResponse response)
|
||||
{
|
||||
if (response instanceof ServletApiResponse)
|
||||
|
|
|
@ -60,10 +60,10 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object createWebSocket(ServerUpgradeRequest req, ServerUpgradeResponse resp, Callback callback)
|
||||
public Object createWebSocket(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
final JsrHandshakeRequest jsrHandshakeRequest = new JsrHandshakeRequest(req);
|
||||
final JsrHandshakeResponse jsrHandshakeResponse = new JsrHandshakeResponse(resp);
|
||||
final JsrHandshakeRequest jsrHandshakeRequest = new JsrHandshakeRequest(request);
|
||||
final JsrHandshakeResponse jsrHandshakeResponse = new JsrHandshakeResponse(response);
|
||||
|
||||
// Establish a copy of the config, so that the UserProperties are unique
|
||||
// per upgrade request.
|
||||
|
@ -83,27 +83,27 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
// it is not JSR api breaking. A few users on #jetty and a few from cometd
|
||||
// have asked for access to this information.
|
||||
Map<String, Object> userProperties = config.getUserProperties();
|
||||
userProperties.put(PROP_LOCAL_ADDRESS, req.getConnectionMetaData().getLocalSocketAddress());
|
||||
userProperties.put(PROP_REMOTE_ADDRESS, req.getConnectionMetaData().getRemoteSocketAddress());
|
||||
userProperties.put(PROP_LOCALES, Request.getLocales(req));
|
||||
userProperties.put(PROP_LOCAL_ADDRESS, request.getConnectionMetaData().getLocalSocketAddress());
|
||||
userProperties.put(PROP_REMOTE_ADDRESS, request.getConnectionMetaData().getRemoteSocketAddress());
|
||||
userProperties.put(PROP_LOCALES, Request.getLocales(request));
|
||||
|
||||
// Get Configurator from config object (not guaranteed to be unique per endpoint upgrade)
|
||||
ServerEndpointConfig.Configurator configurator = config.getConfigurator();
|
||||
|
||||
// [JSR] Step 1: check origin
|
||||
if (!configurator.checkOrigin(req.getHeaders().get(HttpHeader.ORIGIN)))
|
||||
if (!configurator.checkOrigin(request.getHeaders().get(HttpHeader.ORIGIN)))
|
||||
{
|
||||
Response.writeError(req, resp, callback, HttpStatus.FORBIDDEN_403, "Origin mismatch");
|
||||
Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "Origin mismatch");
|
||||
return null;
|
||||
}
|
||||
|
||||
// [JSR] Step 2: deal with sub protocols
|
||||
List<String> supported = config.getSubprotocols();
|
||||
List<String> requested = req.getSubProtocols();
|
||||
List<String> requested = request.getSubProtocols();
|
||||
String subprotocol = configurator.getNegotiatedSubprotocol(supported, requested);
|
||||
if (StringUtil.isNotBlank(subprotocol))
|
||||
{
|
||||
resp.setAcceptedSubProtocol(subprotocol);
|
||||
response.setAcceptedSubProtocol(subprotocol);
|
||||
}
|
||||
|
||||
// [JSR] Step 3: deal with extensions
|
||||
|
@ -113,7 +113,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
installedExtensions.add(new JakartaWebSocketExtension(extName));
|
||||
}
|
||||
List<Extension> requestedExts = new ArrayList<>();
|
||||
for (ExtensionConfig reqCfg : req.getExtensions())
|
||||
for (ExtensionConfig reqCfg : request.getExtensions())
|
||||
{
|
||||
requestedExts.add(new JakartaWebSocketExtension(reqCfg));
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
configs.add(ecfg);
|
||||
}
|
||||
}
|
||||
resp.setExtensions(configs);
|
||||
response.setExtensions(configs);
|
||||
|
||||
// [JSR] Step 4: build out new ServerEndpointConfig
|
||||
Object pathSpecObject = jsrHandshakeRequest.getRequestPathSpec();
|
||||
|
@ -139,7 +139,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
{
|
||||
// We can get path params from PathSpec and Request Path.
|
||||
UriTemplatePathSpec pathSpec = (UriTemplatePathSpec)pathSpecObject;
|
||||
Map<String, String> pathParams = pathSpec.getPathParams(req.getPathInContext());
|
||||
Map<String, String> pathParams = pathSpec.getPathParams(request.getPathInContext());
|
||||
|
||||
// Wrap the config with the path spec information.
|
||||
config = new PathParamServerEndpointConfig(config, pathParams);
|
||||
|
|
|
@ -30,16 +30,18 @@ import jakarta.websocket.server.ServerEndpointConfig;
|
|||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextResponse;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.client.internal.JakartaWebSocketClientContainer;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.ContainerDefaultConfigurator;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
|
||||
|
@ -300,11 +302,25 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
ServletContextRequest baseRequest = ServletContextRequest.getBaseRequest(request);
|
||||
if (baseRequest == null)
|
||||
throw new IllegalStateException();
|
||||
ServletContextResponse baseResponse = baseRequest.getResponse();
|
||||
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
handshaker.upgradeRequest(negotiator, baseRequest, baseRequest.getResponse(), callback, components, defaultCustomizer);
|
||||
callback.block();
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (handshaker.upgradeRequest(negotiator, baseRequest, baseResponse, callback, components, defaultCustomizer))
|
||||
{
|
||||
callback.block();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.tests.framehandlers.FrameEcho;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.tests.framehandlers.WholeMessageEcho;
|
||||
|
@ -24,10 +22,12 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
|
||||
|
@ -39,18 +39,6 @@ public class CoreServer extends ContainerLifeCycle
|
|||
private URI serverUri;
|
||||
private URI wsUri;
|
||||
|
||||
public CoreServer(Function<WebSocketNegotiation, FrameHandler> negotiationFunction)
|
||||
{
|
||||
this(new WebSocketNegotiator.AbstractNegotiator()
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
{
|
||||
return negotiationFunction.apply(negotiation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CoreServer(WebSocketNegotiator negotiator)
|
||||
{
|
||||
this.negotiator = negotiator;
|
||||
|
@ -99,27 +87,26 @@ public class CoreServer extends ContainerLifeCycle
|
|||
public static class EchoNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
|
||||
List<String> offeredSubProtocols = request.getSubProtocols();
|
||||
if (offeredSubProtocols.isEmpty())
|
||||
{
|
||||
return new WholeMessageEcho();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (String offeredSubProtocol : negotiation.getOfferedSubprotocols())
|
||||
for (String offeredSubProtocol : offeredSubProtocols)
|
||||
{
|
||||
if ("echo-whole".equalsIgnoreCase(offeredSubProtocol))
|
||||
{
|
||||
negotiation.setSubprotocol("echo-whole");
|
||||
response.setAcceptedSubProtocol("echo-whole");
|
||||
return new WholeMessageEcho();
|
||||
}
|
||||
|
||||
if ("echo-frames".equalsIgnoreCase(offeredSubProtocol))
|
||||
{
|
||||
negotiation.setSubprotocol("echo-frames");
|
||||
response.setAcceptedSubProtocol("echo-frames");
|
||||
return new FrameEcho();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import jakarta.websocket.ContainerProvider;
|
||||
|
@ -33,8 +32,7 @@ import org.eclipse.jetty.ee10.websocket.jakarta.tests.framehandlers.WholeMessage
|
|||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -49,9 +47,9 @@ public class CookiesTest
|
|||
{
|
||||
private CoreServer server;
|
||||
|
||||
protected void startServer(Function<WebSocketNegotiation, FrameHandler> negotiationFunction) throws Exception
|
||||
protected void startServer(WebSocketNegotiator negotiator) throws Exception
|
||||
{
|
||||
server = new CoreServer(negotiationFunction);
|
||||
server = new CoreServer(negotiator);
|
||||
server.start();
|
||||
}
|
||||
|
||||
|
@ -68,10 +66,9 @@ public class CookiesTest
|
|||
final String cookieValue = "value";
|
||||
final String cookieString = cookieName + "=" + cookieValue;
|
||||
|
||||
startServer(negotiation ->
|
||||
startServer((req, resp, cb) ->
|
||||
{
|
||||
Request request = negotiation.getRequest();
|
||||
List<org.eclipse.jetty.http.HttpCookie> cookies = Request.getCookies(request);
|
||||
List<org.eclipse.jetty.http.HttpCookie> cookies = Request.getCookies(req);
|
||||
assertThat("Cookies", cookies, notNullValue());
|
||||
assertThat("Cookies", cookies.size(), is(1));
|
||||
org.eclipse.jetty.http.HttpCookie cookie = cookies.get(0);
|
||||
|
@ -79,8 +76,8 @@ public class CookiesTest
|
|||
assertEquals(cookieValue, cookie.getValue());
|
||||
|
||||
StringBuilder requestHeaders = new StringBuilder();
|
||||
request.getHeaders().getFieldNamesCollection()
|
||||
.forEach(name -> requestHeaders.append(name).append(": ").append(request.getHeaders().get(name)).append("\n"));
|
||||
req.getHeaders().getFieldNamesCollection()
|
||||
.forEach(name -> requestHeaders.append(name).append(": ").append(req.getHeaders().get(name)).append("\n"));
|
||||
|
||||
return new StaticText(requestHeaders.toString());
|
||||
});
|
||||
|
@ -112,10 +109,10 @@ public class CookiesTest
|
|||
final String cookieValue = "value";
|
||||
final String cookieDomain = "domain";
|
||||
final String cookiePath = "/path";
|
||||
startServer(negotiation ->
|
||||
startServer((req, resp, cb) ->
|
||||
{
|
||||
org.eclipse.jetty.http.HttpCookie cookie = new org.eclipse.jetty.http.HttpCookie(cookieName, cookieValue, cookieDomain, cookiePath);
|
||||
Response.addCookie(negotiation.getResponse(), cookie);
|
||||
Response.addCookie(resp, cookie);
|
||||
return new WholeMessageEcho();
|
||||
});
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.eclipse.jetty.ee10.websocket.jakarta.tests.CoreServer;
|
|||
import org.eclipse.jetty.ee10.websocket.jakarta.tests.WSEventTracker;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -50,14 +49,14 @@ public class DecoderReaderManySmallTest
|
|||
@BeforeEach
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
server = new CoreServer(WebSocketNegotiator.from((negotiation) ->
|
||||
server = new CoreServer((req, resp, cb) ->
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubProtocols = req.getSubProtocols();
|
||||
if (!offeredSubProtocols.isEmpty())
|
||||
negotiation.setSubprotocol(offeredSubProtocols.get(0));
|
||||
resp.setAcceptedSubProtocol(offeredSubProtocols.get(0));
|
||||
|
||||
return new EventIdFrameHandler();
|
||||
}));
|
||||
});
|
||||
server.start();
|
||||
|
||||
client = ContainerProvider.getWebSocketContainer();
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.tests.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -41,7 +40,8 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
|
|||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.TextUtils;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -348,28 +348,26 @@ public class MessageReceivingTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubProtocols = request.getSubProtocols();
|
||||
|
||||
if (offeredSubProtocols.contains("partial-text"))
|
||||
{
|
||||
negotiation.setSubprotocol("partial-text");
|
||||
response.setAcceptedSubProtocol("partial-text");
|
||||
return new SendPartialTextFrameHandler();
|
||||
}
|
||||
|
||||
if (offeredSubProtocols.contains("partial-binary"))
|
||||
{
|
||||
negotiation.setSubprotocol("partial-binary");
|
||||
SendPartialBinaryFrameHandler frameHandler = new SendPartialBinaryFrameHandler();
|
||||
return frameHandler;
|
||||
response.setAcceptedSubProtocol("partial-binary");
|
||||
return new SendPartialBinaryFrameHandler();
|
||||
}
|
||||
|
||||
if (offeredSubProtocols.contains("echo"))
|
||||
{
|
||||
negotiation.setSubprotocol("echo");
|
||||
EchoWholeMessageFrameHandler frameHandler = new EchoWholeMessageFrameHandler();
|
||||
return frameHandler;
|
||||
response.setAcceptedSubProtocol("echo");
|
||||
return new EchoWholeMessageFrameHandler();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -23,7 +23,11 @@ package org.eclipse.jetty.ee10.websocket.server;
|
|||
public interface JettyWebSocketCreator
|
||||
{
|
||||
/**
|
||||
* Create a websocket from the incoming request.
|
||||
* <p>Creates a websocket from the incoming request.</p>
|
||||
*
|
||||
* <p>If no websocket is to be created (return value of null), the {@link JettyWebSocketCreator}
|
||||
* is responsible for sending a response with {@link JettyServerUpgradeResponse#sendError(int, String)},
|
||||
* {@link JettyServerUpgradeResponse#sendForbidden(String)} or {@link JettyServerUpgradeResponse#setStatusCode(int)}.</p>
|
||||
*
|
||||
* @param req the request details
|
||||
* @param resp the response details
|
||||
|
|
|
@ -26,6 +26,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextResponse;
|
||||
import org.eclipse.jetty.ee10.websocket.api.Session;
|
||||
import org.eclipse.jetty.ee10.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.ee10.websocket.api.WebSocketContainer;
|
||||
|
@ -38,12 +39,13 @@ import org.eclipse.jetty.ee10.websocket.server.internal.DelegatedServerUpgradeRe
|
|||
import org.eclipse.jetty.ee10.websocket.server.internal.JettyServerFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.core.server.Handshaker;
|
||||
|
@ -152,7 +154,8 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
try
|
||||
{
|
||||
Object webSocket = creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp));
|
||||
cb.succeeded();
|
||||
if (webSocket == null)
|
||||
cb.succeeded();
|
||||
return webSocket;
|
||||
}
|
||||
catch (Throwable t)
|
||||
|
@ -184,10 +187,15 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
|
||||
/**
|
||||
* An immediate programmatic WebSocket upgrade that does not register a mapping or create a {@link WebSocketUpgradeFilter}.
|
||||
*
|
||||
* <p>A return value of true means the connection was Upgraded to WebSocket or an error response is being generated.
|
||||
* A return value of false means that it was a bad upgrade request and couldn't be upgraded to WebSocket and the
|
||||
* caller is responsible for generating the response.</p>
|
||||
*
|
||||
* @param creator the WebSocketCreator to use.
|
||||
* @param request the HttpServletRequest.
|
||||
* @param response the HttpServletResponse.
|
||||
* @return true if the connection was successfully upgraded to WebSocket.
|
||||
* @return true if the connection could be upgraded or an error was sent.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public boolean upgrade(JettyWebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
|
@ -210,16 +218,32 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
ServletContextRequest baseRequest = ServletContextRequest.getBaseRequest(request);
|
||||
if (baseRequest == null)
|
||||
throw new IllegalStateException("Base Request not available");
|
||||
ServletContextResponse baseResponse = baseRequest.getResponse();
|
||||
|
||||
WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, frameHandlerFactory, customizer);
|
||||
WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, frameHandlerFactory);
|
||||
Handshaker handshaker = webSocketMappings.getHandshaker();
|
||||
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
boolean upgraded = handshaker.upgradeRequest(negotiator, baseRequest, baseRequest.getResponse(), callback, components, null);
|
||||
callback.block();
|
||||
return upgraded;
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (handshaker.upgradeRequest(negotiator, baseRequest, baseResponse, callback, components, customizer))
|
||||
{
|
||||
callback.block();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextResponse;
|
||||
import org.eclipse.jetty.ee10.websocket.server.internal.DelegatedServerUpgradeRequest;
|
||||
import org.eclipse.jetty.ee10.websocket.server.internal.DelegatedServerUpgradeResponse;
|
||||
import org.eclipse.jetty.ee10.websocket.server.internal.JettyServerFrameHandlerFactory;
|
||||
|
@ -33,6 +34,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
@ -182,20 +184,32 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
ServletContextRequest request = ServletContextRequest.getBaseRequest(req);
|
||||
if (request == null)
|
||||
throw new IllegalStateException("Base Request not available");
|
||||
ServletContextResponse response = request.getResponse();
|
||||
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
if (mapping.upgrade(request, request.getResponse(), callback, null))
|
||||
// Do preliminary check before proceeding to attempt an upgrade.
|
||||
if (mapping.getHandshaker().isWebSocketUpgradeRequest(request))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
}
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
request.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, req);
|
||||
request.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, resp);
|
||||
|
||||
// If we reach this point, it means we had an incoming request to upgrade
|
||||
// but it was either not a proper websocket upgrade, or it was possibly rejected
|
||||
// due to incoming request constraints (controlled by WebSocketCreator)
|
||||
if (resp.isCommitted())
|
||||
return;
|
||||
if (mapping.upgrade(request, response, callback, null))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle normally
|
||||
super.service(req, resp);
|
||||
|
@ -281,11 +295,11 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object createWebSocket(ServerUpgradeRequest req, ServerUpgradeResponse resp, Callback callback)
|
||||
public Object createWebSocket(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object webSocket = creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp));
|
||||
Object webSocket = creator.createWebSocket(new DelegatedServerUpgradeRequest(request), new DelegatedServerUpgradeResponse(response));
|
||||
callback.succeeded();
|
||||
return webSocket;
|
||||
}
|
||||
|
|
|
@ -31,14 +31,13 @@ import java.util.stream.Collectors;
|
|||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.websocket.api.ExtensionConfig;
|
||||
import org.eclipse.jetty.ee10.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeRequest;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
|
||||
public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
||||
|
@ -52,13 +51,9 @@ public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
|||
|
||||
public DelegatedServerUpgradeRequest(ServerUpgradeRequest request)
|
||||
{
|
||||
this(request, Request.as(request, ServletContextRequest.class).getHttpServletRequest());
|
||||
}
|
||||
|
||||
public DelegatedServerUpgradeRequest(ServerUpgradeRequest request, HttpServletRequest servletRequest)
|
||||
{
|
||||
this.httpServletRequest = (HttpServletRequest)request
|
||||
.getAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
this.upgradeRequest = request;
|
||||
this.httpServletRequest = servletRequest;
|
||||
this.queryString = httpServletRequest.getQueryString();
|
||||
|
||||
try
|
||||
|
@ -145,13 +140,13 @@ public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
|||
@Override
|
||||
public String getMethod()
|
||||
{
|
||||
return upgradeRequest.getMethod();
|
||||
return httpServletRequest.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrigin()
|
||||
{
|
||||
return upgradeRequest.getHeaders().get(HttpHeader.ORIGIN);
|
||||
return httpServletRequest.getHeader(HttpHeader.ORIGIN.asString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,26 +21,34 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextResponse;
|
||||
import org.eclipse.jetty.ee10.websocket.api.ExtensionConfig;
|
||||
import org.eclipse.jetty.ee10.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeResponse;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
||||
public class DelegatedServerUpgradeResponse implements JettyServerUpgradeResponse
|
||||
{
|
||||
private final ServerUpgradeResponse upgradeResponse;
|
||||
private final HttpServletResponse httpServletResponse;
|
||||
|
||||
public DelegatedServerUpgradeResponse(ServerUpgradeResponse response)
|
||||
{
|
||||
upgradeResponse = response;
|
||||
ServletContextResponse servletContextResponse = Response.as(response, ServletContextResponse.class);
|
||||
this.httpServletResponse = (HttpServletResponse)servletContextResponse.getRequest()
|
||||
.getAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
// TODO: This should go to the httpServletResponse for headers but then it won't do interception of the websocket headers
|
||||
// which are done through the jetty-core Response wrapping ServerUpgradeResponse done by websocket-core.
|
||||
upgradeResponse.getHeaders().add(name, value);
|
||||
}
|
||||
|
||||
|
@ -97,17 +105,13 @@ public class DelegatedServerUpgradeResponse implements JettyServerUpgradeRespons
|
|||
@Override
|
||||
public int getStatusCode()
|
||||
{
|
||||
return upgradeResponse.getStatus();
|
||||
return httpServletResponse.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendForbidden(String message) throws IOException
|
||||
{
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
{
|
||||
Response.writeError(upgradeResponse.getRequest(), upgradeResponse, callback, HttpStatus.FORBIDDEN_403, message);
|
||||
callback.block();
|
||||
}
|
||||
httpServletResponse.sendError(HttpStatus.FORBIDDEN_403, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,22 +131,18 @@ public class DelegatedServerUpgradeResponse implements JettyServerUpgradeRespons
|
|||
@Override
|
||||
public void setStatusCode(int statusCode)
|
||||
{
|
||||
upgradeResponse.setStatus(statusCode);
|
||||
httpServletResponse.setStatus(statusCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommitted()
|
||||
{
|
||||
return upgradeResponse.isCommitted();
|
||||
return httpServletResponse.isCommitted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int statusCode, String message) throws IOException
|
||||
{
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
{
|
||||
Response.writeError(upgradeResponse.getRequest(), upgradeResponse, callback, statusCode, message);
|
||||
callback.block();
|
||||
}
|
||||
httpServletResponse.sendError(statusCode, message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,9 @@
|
|||
package org.eclipse.jetty.ee10.websocket.server.internal;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.websocket.common.JettyWebSocketFrameHandler;
|
||||
import org.eclipse.jetty.ee10.websocket.common.JettyWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory;
|
||||
|
@ -42,11 +39,8 @@ public class JettyServerFrameHandlerFactory extends JettyWebSocketFrameHandlerFa
|
|||
@Override
|
||||
public FrameHandler newFrameHandler(Object websocketPojo, ServerUpgradeRequest upgradeRequest, ServerUpgradeResponse upgradeResponse)
|
||||
{
|
||||
ServletContextRequest servletContextRequest = Request.as(upgradeRequest, ServletContextRequest.class);
|
||||
HttpServletRequest httpServletRequest = servletContextRequest.getHttpServletRequest();
|
||||
|
||||
JettyWebSocketFrameHandler frameHandler = super.newJettyFrameHandler(websocketPojo);
|
||||
frameHandler.setUpgradeRequest(new DelegatedServerUpgradeRequest(upgradeRequest, httpServletRequest));
|
||||
frameHandler.setUpgradeRequest(new DelegatedServerUpgradeRequest(upgradeRequest));
|
||||
frameHandler.setUpgradeResponse(new DelegatedServerUpgradeResponse(upgradeResponse));
|
||||
return frameHandler;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 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.ee10.websocket.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.websocket.api.Session;
|
||||
import org.eclipse.jetty.ee10.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.ee10.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
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.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class SimpleEchoTest
|
||||
{
|
||||
private Server _server;
|
||||
private WebSocketClient _client;
|
||||
private ServerConnector _connector;
|
||||
|
||||
@BeforeEach
|
||||
public void start() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new ServerConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
JettyWebSocketServletContainerInitializer.configure(contextHandler, ((servletContext, container) ->
|
||||
{
|
||||
container.setIdleTimeout(Duration.ZERO);
|
||||
container.addMapping("/", EchoSocket.class);
|
||||
}));
|
||||
_server.setHandler(contextHandler);
|
||||
_server.start();
|
||||
|
||||
_client = new WebSocketClient();
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
int timeout = 10000;
|
||||
_client.setIdleTimeout(Duration.ofSeconds(timeout));
|
||||
_client.setConnectTimeout(Duration.ofSeconds(timeout).toMillis());
|
||||
|
||||
URI uri = new URI("ws://localhost:" + _connector.getLocalPort());
|
||||
EventSocket clientEndpoint = new EventSocket();
|
||||
Session session = _client.connect(clientEndpoint, uri).get(timeout, TimeUnit.SECONDS);
|
||||
session.setIdleTimeout(Duration.ofSeconds(timeout));
|
||||
|
||||
String message = "hello world 1234";
|
||||
session.getRemote().sendString(message);
|
||||
String received = clientEndpoint.textMessages.poll(timeout, TimeUnit.SECONDS);
|
||||
assertThat(received, equalTo(message));
|
||||
|
||||
session.close();
|
||||
assertTrue(clientEndpoint.closeLatch.await(timeout, TimeUnit.SECONDS));
|
||||
assertThat(clientEndpoint.closeCode, equalTo(StatusCode.NORMAL));
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.ee10.servlet.FilterHolder;
|
|||
import org.eclipse.jetty.ee10.servlet.FilterMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
|
@ -38,6 +39,7 @@ import org.eclipse.jetty.util.component.Dumpable;
|
|||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -158,13 +160,31 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
ServletContextRequest baseRequest = ServletContextRequest.getBaseRequest(request);
|
||||
if (baseRequest == null)
|
||||
throw new IllegalStateException("Base Request not available");
|
||||
ServletContextResponse baseResponse = baseRequest.getResponse();
|
||||
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
if (mappings.upgrade(baseRequest, baseRequest.getResponse(), callback, defaultCustomizer))
|
||||
// Do preliminary check before proceeding to attempt an upgrade.
|
||||
if (mappings.getHandshaker().isWebSocketUpgradeRequest(baseRequest))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (mappings.upgrade(baseRequest, baseResponse, callback, defaultCustomizer))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach this point, it means we had an incoming request to upgrade
|
||||
|
|
|
@ -60,10 +60,10 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object createWebSocket(ServerUpgradeRequest req, ServerUpgradeResponse resp, Callback callback)
|
||||
public Object createWebSocket(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
final JsrHandshakeRequest jsrHandshakeRequest = new JsrHandshakeRequest(req);
|
||||
final JsrHandshakeResponse jsrHandshakeResponse = new JsrHandshakeResponse(resp);
|
||||
final JsrHandshakeRequest jsrHandshakeRequest = new JsrHandshakeRequest(request);
|
||||
final JsrHandshakeResponse jsrHandshakeResponse = new JsrHandshakeResponse(response);
|
||||
|
||||
// Establish a copy of the config, so that the UserProperties are unique
|
||||
// per upgrade request.
|
||||
|
@ -83,27 +83,27 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
// it is not JSR api breaking. A few users on #jetty and a few from cometd
|
||||
// have asked for access to this information.
|
||||
Map<String, Object> userProperties = config.getUserProperties();
|
||||
userProperties.put(PROP_LOCAL_ADDRESS, req.getConnectionMetaData().getLocalSocketAddress());
|
||||
userProperties.put(PROP_REMOTE_ADDRESS, req.getConnectionMetaData().getRemoteSocketAddress());
|
||||
userProperties.put(PROP_LOCALES, Request.getLocales(req));
|
||||
userProperties.put(PROP_LOCAL_ADDRESS, request.getConnectionMetaData().getLocalSocketAddress());
|
||||
userProperties.put(PROP_REMOTE_ADDRESS, request.getConnectionMetaData().getRemoteSocketAddress());
|
||||
userProperties.put(PROP_LOCALES, Request.getLocales(request));
|
||||
|
||||
// Get Configurator from config object (not guaranteed to be unique per endpoint upgrade)
|
||||
ServerEndpointConfig.Configurator configurator = config.getConfigurator();
|
||||
|
||||
// [JSR] Step 1: check origin
|
||||
if (!configurator.checkOrigin(req.getHeaders().get(HttpHeader.ORIGIN)))
|
||||
if (!configurator.checkOrigin(request.getHeaders().get(HttpHeader.ORIGIN)))
|
||||
{
|
||||
Response.writeError(req, resp, callback, HttpStatus.FORBIDDEN_403, "Origin mismatch");
|
||||
Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "Origin mismatch");
|
||||
return null;
|
||||
}
|
||||
|
||||
// [JSR] Step 2: deal with sub protocols
|
||||
List<String> supported = config.getSubprotocols();
|
||||
List<String> requested = req.getSubProtocols();
|
||||
List<String> requested = request.getSubProtocols();
|
||||
String subprotocol = configurator.getNegotiatedSubprotocol(supported, requested);
|
||||
if (StringUtil.isNotBlank(subprotocol))
|
||||
{
|
||||
resp.setAcceptedSubProtocol(subprotocol);
|
||||
response.setAcceptedSubProtocol(subprotocol);
|
||||
}
|
||||
|
||||
// [JSR] Step 3: deal with extensions
|
||||
|
@ -113,7 +113,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
installedExtensions.add(new JakartaWebSocketExtension(extName));
|
||||
}
|
||||
List<Extension> requestedExts = new ArrayList<>();
|
||||
for (ExtensionConfig reqCfg : req.getExtensions())
|
||||
for (ExtensionConfig reqCfg : request.getExtensions())
|
||||
{
|
||||
requestedExts.add(new JakartaWebSocketExtension(reqCfg));
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
configs.add(ecfg);
|
||||
}
|
||||
}
|
||||
resp.setExtensions(configs);
|
||||
response.setExtensions(configs);
|
||||
|
||||
// [JSR] Step 4: build out new ServerEndpointConfig
|
||||
Object pathSpecObject = jsrHandshakeRequest.getRequestPathSpec();
|
||||
|
@ -139,7 +139,7 @@ public class JakartaWebSocketCreator implements WebSocketCreator
|
|||
{
|
||||
// We can get path params from PathSpec and Request Path.
|
||||
UriTemplatePathSpec pathSpec = (UriTemplatePathSpec)pathSpecObject;
|
||||
Map<String, String> pathParams = pathSpec.getPathParams(req.getPathInContext());
|
||||
Map<String, String> pathParams = pathSpec.getPathParams(request.getPathInContext());
|
||||
|
||||
// Wrap the config with the path spec information.
|
||||
config = new PathParamServerEndpointConfig(config, pathParams);
|
||||
|
|
|
@ -36,10 +36,13 @@ import org.eclipse.jetty.ee9.websocket.jakarta.server.config.ContainerDefaultCon
|
|||
import org.eclipse.jetty.ee9.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
|
||||
|
@ -298,10 +301,26 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
Handshaker handshaker = webSocketMappings.getHandshaker();
|
||||
|
||||
HttpChannel httpChannel = (HttpChannel)request.getAttribute(HttpChannel.class.getName());
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
Request baseRequest = httpChannel.getCoreRequest();
|
||||
Response baseResponse = httpChannel.getCoreResponse();
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
handshaker.upgradeRequest(negotiator, httpChannel.getCoreRequest(), httpChannel.getCoreResponse(), callback, components, defaultCustomizer);
|
||||
callback.block();
|
||||
// Set the wrapped req and resp as attachments on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (handshaker.upgradeRequest(negotiator, baseRequest, baseResponse, callback, components, defaultCustomizer))
|
||||
{
|
||||
callback.block();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.tests.framehandlers.FrameEcho;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.tests.framehandlers.WholeMessageEcho;
|
||||
|
@ -24,10 +22,12 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||
|
||||
|
@ -39,18 +39,6 @@ public class CoreServer extends ContainerLifeCycle
|
|||
private URI serverUri;
|
||||
private URI wsUri;
|
||||
|
||||
public CoreServer(Function<WebSocketNegotiation, FrameHandler> negotiationFunction)
|
||||
{
|
||||
this(new WebSocketNegotiator.AbstractNegotiator()
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
{
|
||||
return negotiationFunction.apply(negotiation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CoreServer(WebSocketNegotiator negotiator)
|
||||
{
|
||||
this.negotiator = negotiator;
|
||||
|
@ -99,27 +87,26 @@ public class CoreServer extends ContainerLifeCycle
|
|||
public static class EchoNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
||||
{
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
|
||||
List<String> offeredSubProtocols = request.getSubProtocols();
|
||||
if (offeredSubProtocols.isEmpty())
|
||||
{
|
||||
return new WholeMessageEcho();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (String offeredSubProtocol : negotiation.getOfferedSubprotocols())
|
||||
for (String offeredSubProtocol : offeredSubProtocols)
|
||||
{
|
||||
if ("echo-whole".equalsIgnoreCase(offeredSubProtocol))
|
||||
{
|
||||
negotiation.setSubprotocol("echo-whole");
|
||||
response.setAcceptedSubProtocol("echo-whole");
|
||||
return new WholeMessageEcho();
|
||||
}
|
||||
|
||||
if ("echo-frames".equalsIgnoreCase(offeredSubProtocol))
|
||||
{
|
||||
negotiation.setSubprotocol("echo-frames");
|
||||
response.setAcceptedSubProtocol("echo-frames");
|
||||
return new FrameEcho();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.websocket.ClientEndpointConfig;
|
||||
import jakarta.websocket.ContainerProvider;
|
||||
|
@ -33,9 +32,7 @@ import org.eclipse.jetty.ee9.websocket.jakarta.tests.framehandlers.WholeMessageE
|
|||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -50,9 +47,9 @@ public class CookiesTest
|
|||
{
|
||||
private CoreServer server;
|
||||
|
||||
protected void startServer(Function<WebSocketNegotiation, FrameHandler> negotiationFunction) throws Exception
|
||||
protected void startServer(WebSocketNegotiator negotiator) throws Exception
|
||||
{
|
||||
server = new CoreServer(negotiationFunction);
|
||||
server = new CoreServer(negotiator);
|
||||
server.start();
|
||||
}
|
||||
|
||||
|
@ -69,10 +66,9 @@ public class CookiesTest
|
|||
final String cookieValue = "value";
|
||||
final String cookieString = cookieName + "=" + cookieValue;
|
||||
|
||||
startServer(negotiation ->
|
||||
startServer((req, resp, cb) ->
|
||||
{
|
||||
ServerUpgradeRequest request = negotiation.getRequest();
|
||||
List<org.eclipse.jetty.http.HttpCookie> cookies = Request.getCookies(request);
|
||||
List<org.eclipse.jetty.http.HttpCookie> cookies = Request.getCookies(req);
|
||||
assertThat("Cookies", cookies, notNullValue());
|
||||
assertThat("Cookies", cookies.size(), is(1));
|
||||
org.eclipse.jetty.http.HttpCookie cookie = cookies.get(0);
|
||||
|
@ -80,7 +76,7 @@ public class CookiesTest
|
|||
assertEquals(cookieValue, cookie.getValue());
|
||||
|
||||
StringBuilder requestHeaders = new StringBuilder();
|
||||
request.getHeaders()
|
||||
req.getHeaders()
|
||||
.forEach(field -> requestHeaders.append(field.getName()).append(": ").append(field.getValue()).append("\n"));
|
||||
|
||||
return new StaticText(requestHeaders.toString());
|
||||
|
@ -113,10 +109,10 @@ public class CookiesTest
|
|||
final String cookieValue = "value";
|
||||
final String cookieDomain = "domain";
|
||||
final String cookiePath = "/path";
|
||||
startServer(negotiation ->
|
||||
startServer((req, resp, cb) ->
|
||||
{
|
||||
org.eclipse.jetty.http.HttpCookie cookie = new org.eclipse.jetty.http.HttpCookie(cookieName, cookieValue, cookieDomain, cookiePath);
|
||||
Response.addCookie(negotiation.getResponse(), cookie);
|
||||
Response.addCookie(resp, cookie);
|
||||
return new WholeMessageEcho();
|
||||
});
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.eclipse.jetty.ee9.websocket.jakarta.tests.CoreServer;
|
|||
import org.eclipse.jetty.ee9.websocket.jakarta.tests.WSEventTracker;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -50,14 +49,13 @@ public class DecoderReaderManySmallTest
|
|||
@BeforeEach
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
server = new CoreServer(WebSocketNegotiator.from((negotiation) ->
|
||||
server = new CoreServer((req, resp, cb) ->
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubProtocols = req.getSubProtocols();
|
||||
if (!offeredSubProtocols.isEmpty())
|
||||
negotiation.setSubprotocol(offeredSubProtocols.get(0));
|
||||
|
||||
resp.setAcceptedSubProtocol(offeredSubProtocols.get(0));
|
||||
return new EventIdFrameHandler();
|
||||
}));
|
||||
});
|
||||
server.start();
|
||||
|
||||
client = ContainerProvider.getWebSocketContainer();
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.tests.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -41,7 +40,8 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
|
|||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.TextUtils;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -348,28 +348,26 @@ public class MessageReceivingTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
|
||||
public FrameHandler negotiate(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
List<String> offeredSubProtocols = negotiation.getOfferedSubprotocols();
|
||||
List<String> offeredSubProtocols = request.getSubProtocols();
|
||||
|
||||
if (offeredSubProtocols.contains("partial-text"))
|
||||
{
|
||||
negotiation.setSubprotocol("partial-text");
|
||||
response.setAcceptedSubProtocol("partial-text");
|
||||
return new SendPartialTextFrameHandler();
|
||||
}
|
||||
|
||||
if (offeredSubProtocols.contains("partial-binary"))
|
||||
{
|
||||
negotiation.setSubprotocol("partial-binary");
|
||||
SendPartialBinaryFrameHandler frameHandler = new SendPartialBinaryFrameHandler();
|
||||
return frameHandler;
|
||||
response.setAcceptedSubProtocol("partial-binary");
|
||||
return new SendPartialBinaryFrameHandler();
|
||||
}
|
||||
|
||||
if (offeredSubProtocols.contains("echo"))
|
||||
{
|
||||
negotiation.setSubprotocol("echo");
|
||||
EchoWholeMessageFrameHandler frameHandler = new EchoWholeMessageFrameHandler();
|
||||
return frameHandler;
|
||||
response.setAcceptedSubProtocol("echo");
|
||||
return new EchoWholeMessageFrameHandler();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -25,6 +25,10 @@ public interface JettyWebSocketCreator
|
|||
/**
|
||||
* Create a websocket from the incoming request.
|
||||
*
|
||||
* <p>If no websocket is to be created (return value of null), the {@link JettyWebSocketCreator}
|
||||
* is responsible for sending a response with {@link JettyServerUpgradeResponse#sendError(int, String)},
|
||||
* {@link JettyServerUpgradeResponse#sendForbidden(String)} or {@link JettyServerUpgradeResponse#setStatusCode(int)}.</p>
|
||||
*
|
||||
* @param req the request details
|
||||
* @param resp the response details
|
||||
* @return a websocket object to use, or null if no websocket should be created from this request.
|
||||
|
|
|
@ -38,12 +38,15 @@ import org.eclipse.jetty.ee9.websocket.server.internal.DelegatedServerUpgradeRes
|
|||
import org.eclipse.jetty.ee9.websocket.server.internal.JettyServerFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.servlet.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.core.server.Handshaker;
|
||||
|
@ -184,10 +187,15 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
|
||||
/**
|
||||
* An immediate programmatic WebSocket upgrade that does not register a mapping or create a {@link WebSocketUpgradeFilter}.
|
||||
*
|
||||
* <p>A return value of true means the connection was Upgraded to WebSocket or an error response is being generated.
|
||||
* A return value of false means that it was a bad upgrade request and couldn't be upgraded to WebSocket and the
|
||||
* caller is responsible for generating the response.</p>
|
||||
*
|
||||
* @param creator the WebSocketCreator to use.
|
||||
* @param request the HttpServletRequest.
|
||||
* @param response the HttpServletResponse.
|
||||
* @return true if the connection was successfully upgraded to WebSocket.
|
||||
* @return true if the connection could be upgraded or an error was sent.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public boolean upgrade(JettyWebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
|
@ -207,16 +215,33 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
}
|
||||
};
|
||||
|
||||
HttpChannel httpChannel = (HttpChannel)request.getAttribute(HttpChannel.class.getName());
|
||||
WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, frameHandlerFactory, customizer);
|
||||
WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, frameHandlerFactory);
|
||||
Handshaker handshaker = webSocketMappings.getHandshaker();
|
||||
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
HttpChannel httpChannel = (HttpChannel)request.getAttribute(HttpChannel.class.getName());
|
||||
Request baseRequest = httpChannel.getCoreRequest();
|
||||
Response baseResponse = httpChannel.getCoreResponse();
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
boolean upgraded = handshaker.upgradeRequest(negotiator, httpChannel.getCoreRequest(), httpChannel.getCoreResponse(), callback, components, null);
|
||||
callback.block();
|
||||
return upgraded;
|
||||
// Set the wrapped req and resp as attachments on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (handshaker.upgradeRequest(negotiator, baseRequest, baseResponse, callback, components, customizer))
|
||||
{
|
||||
callback.block();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,10 +30,13 @@ import org.eclipse.jetty.ee9.websocket.server.internal.DelegatedServerUpgradeReq
|
|||
import org.eclipse.jetty.ee9.websocket.server.internal.DelegatedServerUpgradeResponse;
|
||||
import org.eclipse.jetty.ee9.websocket.server.internal.JettyServerFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.servlet.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
@ -182,13 +185,33 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
throws ServletException, IOException
|
||||
{
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
HttpChannel channel = (HttpChannel)req.getAttribute(HttpChannel.class.getName());
|
||||
HttpChannel httpChannel = (HttpChannel)req.getAttribute(HttpChannel.class.getName());
|
||||
Request request = httpChannel.getCoreRequest();
|
||||
Response response = httpChannel.getCoreResponse();
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
if (mapping.upgrade(channel.getCoreRequest(), channel.getCoreResponse(), callback, null))
|
||||
// Do preliminary check before proceeding to attempt an upgrade.
|
||||
if (mapping.getHandshaker().isWebSocketUpgradeRequest(request))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
request.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, req);
|
||||
request.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, resp);
|
||||
|
||||
if (mapping.upgrade(request, response, callback, null))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
request.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach this point, it means we had an incoming request to upgrade
|
||||
|
@ -281,11 +304,11 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object createWebSocket(ServerUpgradeRequest req, ServerUpgradeResponse resp, Callback callback)
|
||||
public Object createWebSocket(ServerUpgradeRequest request, ServerUpgradeResponse response, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object webSocket = creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp));
|
||||
Object webSocket = creator.createWebSocket(new DelegatedServerUpgradeRequest(request), new DelegatedServerUpgradeResponse(response));
|
||||
callback.succeeded();
|
||||
return webSocket;
|
||||
}
|
||||
|
|
|
@ -31,14 +31,13 @@ import java.util.stream.Collectors;
|
|||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.eclipse.jetty.ee9.nested.ContextHandler;
|
||||
import org.eclipse.jetty.ee9.websocket.api.ExtensionConfig;
|
||||
import org.eclipse.jetty.ee9.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeRequest;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
|
||||
|
||||
public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
||||
|
@ -52,13 +51,9 @@ public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
|||
|
||||
public DelegatedServerUpgradeRequest(ServerUpgradeRequest request)
|
||||
{
|
||||
this(request, Request.as(request, ContextHandler.CoreContextRequest.class).getHttpChannel().getRequest());
|
||||
}
|
||||
|
||||
public DelegatedServerUpgradeRequest(ServerUpgradeRequest request, HttpServletRequest servletRequest)
|
||||
{
|
||||
this.httpServletRequest = (HttpServletRequest)request
|
||||
.getAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
this.upgradeRequest = request;
|
||||
this.httpServletRequest = servletRequest;
|
||||
this.queryString = httpServletRequest.getQueryString();
|
||||
|
||||
try
|
||||
|
@ -145,13 +140,13 @@ public class DelegatedServerUpgradeRequest implements JettyServerUpgradeRequest
|
|||
@Override
|
||||
public String getMethod()
|
||||
{
|
||||
return upgradeRequest.getMethod();
|
||||
return httpServletRequest.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrigin()
|
||||
{
|
||||
return upgradeRequest.getHeaders().get(HttpHeader.ORIGIN);
|
||||
return httpServletRequest.getHeader(HttpHeader.ORIGIN.asString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,26 +21,31 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee9.websocket.api.ExtensionConfig;
|
||||
import org.eclipse.jetty.ee9.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeResponse;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Blocker;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
|
||||
|
||||
public class DelegatedServerUpgradeResponse implements JettyServerUpgradeResponse
|
||||
{
|
||||
private final ServerUpgradeResponse upgradeResponse;
|
||||
private final HttpServletResponse httpServletResponse;
|
||||
|
||||
public DelegatedServerUpgradeResponse(ServerUpgradeResponse response)
|
||||
{
|
||||
upgradeResponse = response;
|
||||
this.upgradeResponse = response;
|
||||
this.httpServletResponse = (HttpServletResponse)response.getRequest()
|
||||
.getAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
// TODO: This should go to the httpServletResponse for headers but then it won't do interception of the websocket headers
|
||||
// which are done through the jetty-core Response wrapping ServerUpgradeResponse done by websocket-core.
|
||||
upgradeResponse.getHeaders().add(name, value);
|
||||
}
|
||||
|
||||
|
@ -97,17 +102,13 @@ public class DelegatedServerUpgradeResponse implements JettyServerUpgradeRespons
|
|||
@Override
|
||||
public int getStatusCode()
|
||||
{
|
||||
return upgradeResponse.getStatus();
|
||||
return httpServletResponse.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendForbidden(String message) throws IOException
|
||||
{
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
{
|
||||
Response.writeError(upgradeResponse.getRequest(), upgradeResponse, callback, HttpStatus.FORBIDDEN_403, message);
|
||||
callback.block();
|
||||
}
|
||||
httpServletResponse.sendError(HttpStatus.FORBIDDEN_403, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,22 +128,18 @@ public class DelegatedServerUpgradeResponse implements JettyServerUpgradeRespons
|
|||
@Override
|
||||
public void setStatusCode(int statusCode)
|
||||
{
|
||||
upgradeResponse.setStatus(statusCode);
|
||||
httpServletResponse.setStatus(statusCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommitted()
|
||||
{
|
||||
return upgradeResponse.isCommitted();
|
||||
return httpServletResponse.isCommitted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int statusCode, String message) throws IOException
|
||||
{
|
||||
try (Blocker.Callback callback = Blocker.callback())
|
||||
{
|
||||
Response.writeError(upgradeResponse.getRequest(), upgradeResponse, callback, statusCode, message);
|
||||
callback.block();
|
||||
}
|
||||
httpServletResponse.sendError(statusCode, message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,19 +26,20 @@ import jakarta.servlet.ServletContext;
|
|||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee9.nested.ContextHandler;
|
||||
import org.eclipse.jetty.ee9.nested.HttpChannel;
|
||||
import org.eclipse.jetty.ee9.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.ee9.servlet.FilterMapping;
|
||||
import org.eclipse.jetty.ee9.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -156,15 +157,33 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
{
|
||||
HttpServletRequest httpreq = (HttpServletRequest)request;
|
||||
HttpServletResponse httpresp = (HttpServletResponse)response;
|
||||
|
||||
HttpChannel httpChannel = (HttpChannel)request.getAttribute(HttpChannel.class.getName());
|
||||
FutureCallback callback = new FutureCallback();
|
||||
if (mappings.upgrade(httpChannel.getCoreRequest(), httpChannel.getCoreResponse(), callback, defaultCustomizer))
|
||||
Request baseRequest = httpChannel.getCoreRequest();
|
||||
Response baseResponse = httpChannel.getCoreResponse();
|
||||
|
||||
// Do preliminary check before proceeding to attempt an upgrade.
|
||||
if (mappings.getHandshaker().isWebSocketUpgradeRequest(baseRequest))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
// provide a null default customizer the customizer will be on the negotiator in the mapping
|
||||
FutureCallback callback = new FutureCallback();
|
||||
try
|
||||
{
|
||||
// Set the wrapped req and resp as attributes on the ServletContext Request/Response, so they
|
||||
// are accessible when websocket-core calls back the Jetty WebSocket creator.
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE, request);
|
||||
baseRequest.setAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE, response);
|
||||
|
||||
if (mappings.upgrade(baseRequest, baseResponse, callback, defaultCustomizer))
|
||||
{
|
||||
callback.block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_REQUEST_ATTRIBUTE);
|
||||
baseRequest.removeAttribute(WebSocketConstants.WEBSOCKET_WRAPPED_RESPONSE_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach this point, it means we had an incoming request to upgrade
|
||||
|
|
Loading…
Reference in New Issue