Merge pull request #5935 from eclipse/jetty-10.0.x-5868-WSUpgradeRequestResponse

Issue #5868 - allow request attributes to be set in websocket upgrade
This commit is contained in:
Lachlan 2021-02-10 10:56:18 +11:00 committed by GitHub
commit 2549df99ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 652 additions and 106 deletions

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.QuotedStringTokenizer;
@ -432,7 +433,8 @@ public abstract class CoreClientUpgradeRequest extends HttpRequest implements Re
customizer.customize(coreSession);
HttpClient httpClient = wsClient.getHttpClient();
WebSocketConnection wsConnection = new WebSocketConnection(endPoint, httpClient.getExecutor(), httpClient.getScheduler(), httpClient.getByteBufferPool(), coreSession);
ByteBufferPool bufferPool = wsClient.getWebSocketComponents().getBufferPool();
WebSocketConnection wsConnection = new WebSocketConnection(endPoint, httpClient.getExecutor(), httpClient.getScheduler(), bufferPool, coreSession);
wsClient.getEventListeners().forEach(wsConnection::addEventListener);
coreSession.setWebSocketConnection(wsConnection);
notifyUpgradeListeners((listener) -> listener.onHandshakeResponse(this, response));

View File

@ -19,15 +19,16 @@ import java.net.SocketAddress;
import java.net.URI;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ -38,11 +39,15 @@ import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.core.server.internal.UpgradeHttpServletRequest;
/**
* Upgrade request used for websocket negotiation.
* Provides getters for things like the requested extensions and subprotocols so that the headers don't have to be parsed manually.
*/
public class ServerUpgradeRequest
{
private final URI requestURI;
private final String queryString;
private final UpgradeHttpServletRequest request;
private final HttpServletRequest request;
private final boolean secure;
private final WebSocketNegotiation negotiation;
private List<HttpCookie> cookies;
@ -51,20 +56,17 @@ public class ServerUpgradeRequest
public ServerUpgradeRequest(WebSocketNegotiation negotiation) throws BadMessageException
{
this.negotiation = negotiation;
HttpServletRequest httpRequest = negotiation.getRequest();
this.queryString = httpRequest.getQueryString();
this.secure = httpRequest.isSecure();
this.request = negotiation.getRequest();
this.queryString = request.getQueryString();
this.secure = request.isSecure();
try
{
// TODO why is this URL and not URI?
StringBuffer uri = httpRequest.getRequestURL();
// WHY?
StringBuffer uri = request.getRequestURL();
if (this.queryString != null)
uri.append("?").append(this.queryString);
uri.replace(0, uri.indexOf(":"), secure ? "wss" : "ws");
this.requestURI = new URI(uri.toString());
this.request = new UpgradeHttpServletRequest(httpRequest);
}
catch (Throwable t)
{
@ -88,17 +90,9 @@ public class ServerUpgradeRequest
{
if (cookies == null)
{
Cookie[] requestCookies = request.getCookies();
if (requestCookies != null)
{
cookies = new ArrayList<>();
for (Cookie requestCookie : requestCookies)
{
HttpCookie cookie = new HttpCookie(requestCookie.getName(), requestCookie.getValue());
// No point handling domain/path/expires/secure/httponly on client request cookies
cookies.add(cookie);
}
}
cookies = Arrays.stream(request.getCookies())
.map(c -> new HttpCookie(c.getName(), c.getValue()))
.collect(Collectors.toList());
}
return cookies;
@ -130,12 +124,7 @@ public class ServerUpgradeRequest
*/
public int getHeaderInt(String name)
{
String val = request.getHeader(name);
if (val == null)
{
return -1;
}
return Integer.parseInt(val);
return request.getIntHeader(name);
}
/**
@ -144,7 +133,14 @@ public class ServerUpgradeRequest
*/
public Map<String, List<String>> getHeadersMap()
{
return request.getHeaders();
Map<String, List<String>> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements())
{
String name = headerNames.nextElement();
headers.put(name, Collections.list(request.getHeaders(name)));
}
return headers;
}
/**
@ -154,7 +150,10 @@ public class ServerUpgradeRequest
*/
public List<String> getHeaders(String name)
{
return request.getHeaders().get(name);
Enumeration<String> headers = request.getHeaders(name);
if (headers == null || !headers.hasMoreElements())
return null;
return Collections.list(headers);
}
/**
@ -163,7 +162,6 @@ public class ServerUpgradeRequest
*/
public String getHost()
{
// TODO why is this not HttpServletRequest#getHost ?
return requestURI.getHost();
}
@ -209,7 +207,7 @@ public class ServerUpgradeRequest
*/
public SocketAddress getLocalSocketAddress()
{
// TODO: fix when HttpServletRequest can use Unix Socket stuff
// TODO: fix when HttpServletRequest can use Unix Socket stuff.
return new InetSocketAddress(request.getLocalAddr(), request.getLocalPort());
}
@ -326,11 +324,17 @@ public class ServerUpgradeRequest
/**
* @return Request attribute map
* @see UpgradeHttpServletRequest#getAttributes()
*/
public Map<String, Object> getServletAttributes()
{
return request.getAttributes();
Map<String, Object> attributes = new HashMap<>(2);
Enumeration<String> attributeNames = request.getAttributeNames();
while (attributeNames.hasMoreElements())
{
String name = attributeNames.nextElement();
attributes.put(name, request.getAttribute(name));
}
return attributes;
}
/**
@ -377,9 +381,7 @@ public class ServerUpgradeRequest
for (String protocol : getSubProtocols())
{
if (protocol.equalsIgnoreCase(subprotocol))
{
return true;
}
}
return false;
}

View File

@ -26,6 +26,10 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
/**
* Upgrade response used for websocket negotiation.
* Allows setting of extensions and subprotocol without using headers directly.
*/
public class ServerUpgradeResponse
{
private final HttpServletResponse response;

View File

@ -59,7 +59,11 @@ public abstract class AbstractHandshaker implements Handshaker
if (!validateRequest(request))
return false;
WebSocketNegotiation negotiation = newNegotiation(request, response, components);
// After negotiation these can be set to copy data from request and disable unavailable methods.
UpgradeHttpServletRequest upgradeRequest = new UpgradeHttpServletRequest(request);
UpgradeHttpServletResponse upgradeResponse = new UpgradeHttpServletResponse(response);
WebSocketNegotiation negotiation = newNegotiation(upgradeRequest, upgradeResponse, components);
if (LOG.isDebugEnabled())
LOG.debug("negotiation {}", negotiation);
negotiation.negotiate();
@ -127,7 +131,7 @@ public abstract class AbstractHandshaker implements Handshaker
Negotiated negotiated = new Negotiated(baseRequest.getHttpURI().toURI(), protocol, baseRequest.isSecure(), extensionStack, WebSocketConstants.SPEC_VERSION_STRING);
// Create the Session
WebSocketCoreSession coreSession = newWebSocketCoreSession(request, handler, negotiated, components);
WebSocketCoreSession coreSession = newWebSocketCoreSession(upgradeRequest, handler, negotiated, components);
if (defaultCustomizer != null)
defaultCustomizer.customize(coreSession);
negotiator.customize(coreSession);
@ -159,6 +163,10 @@ public abstract class AbstractHandshaker implements Handshaker
baseRequest.setAttribute(HttpTransport.UPGRADE_CONNECTION_ATTRIBUTE, connection);
// Save state from request/response and remove reference to the base request/response.
upgradeRequest.upgrade();
upgradeResponse.upgrade();
if (LOG.isDebugEnabled())
LOG.debug("upgrade connection={} session={} framehandler={}", connection, coreSession, handler);

View File

@ -14,6 +14,8 @@
package org.eclipse.jetty.websocket.core.server.internal;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.security.Principal;
import java.util.ArrayList;
@ -30,6 +32,7 @@ import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@ -49,9 +52,10 @@ import org.eclipse.jetty.server.UserIdentity;
*/
public class UpgradeHttpServletRequest implements HttpServletRequest
{
private static final String UNSUPPORTED_WITH_WEBSOCKET_UPGRADE = "Feature unsupported with a Upgraded to WebSocket HttpServletRequest";
private static final String UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE = "Feature unsupported after Upgraded to WebSocket";
private HttpServletRequest request;
private final Request baseRequest;
private final ServletContext context;
private final DispatcherType dispatcher;
private final String method;
@ -84,10 +88,15 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
private final String remoteName;
private final InetSocketAddress serverAddress;
private boolean isAsyncStarted;
private boolean isAsyncSupported;
public UpgradeHttpServletRequest(HttpServletRequest httpRequest)
{
// The original request object must be held temporarily for the duration of the handshake
// in order to be able to implement methods such as isUserInRole() and setAttribute().
request = httpRequest;
context = httpRequest.getServletContext();
dispatcher = httpRequest.getDispatcherType();
@ -107,7 +116,7 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
remoteUser = httpRequest.getRemoteUser();
principal = httpRequest.getUserPrincipal();
baseRequest = Objects.requireNonNull(Request.getBaseRequest(httpRequest));
Request baseRequest = Objects.requireNonNull(Request.getBaseRequest(httpRequest));
authentication = baseRequest.getAuthentication();
scope = baseRequest.getUserIdentityScope();
@ -120,13 +129,6 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
parameters.putAll(httpRequest.getParameterMap());
Enumeration<String> attributeNames = httpRequest.getAttributeNames();
while (attributeNames.hasMoreElements())
{
String name = attributeNames.nextElement();
attributes.put(name, httpRequest.getAttribute(name));
}
Enumeration<Locale> localeElements = httpRequest.getLocales();
while (localeElements.hasMoreElements())
{
@ -140,6 +142,25 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
serverAddress = InetSocketAddress.createUnresolved(httpRequest.getServerName(), httpRequest.getServerPort());
}
public void upgrade()
{
Enumeration<String> attributeNames = request.getAttributeNames();
while (attributeNames.hasMoreElements())
{
String name = attributeNames.nextElement();
attributes.put(name, request.getAttribute(name));
}
this.isAsyncStarted = request.isAsyncStarted();
this.isAsyncSupported = request.isAsyncSupported();
request = null;
}
public HttpServletRequest getHttpServletRequest()
{
return request;
}
@Override
public String getAuthType()
{
@ -184,13 +205,17 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
@Override
public long getDateHeader(String name)
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getDateHeader(name);
}
@Override
public int getIntHeader(String name)
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getIntHeader(name);
}
@Override
@ -234,7 +259,6 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
{
if (authentication instanceof Authentication.User)
return ((Authentication.User)authentication).isUserInRole(scope, role);
return false;
}
@ -265,8 +289,8 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
@Override
public HttpSession getSession(boolean create)
{
if (create)
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (create && (session == null))
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return session;
}
@ -276,56 +300,60 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
return session;
}
public Request getBaseRequest()
{
return baseRequest;
}
@Override
public String getRequestedSessionId()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getRequestedSessionId();
}
@Override
public boolean isRequestedSessionIdValid()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.isRequestedSessionIdValid();
}
@Override
public boolean isRequestedSessionIdFromCookie()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.isRequestedSessionIdFromCookie();
}
@Override
public boolean isRequestedSessionIdFromURL()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.isRequestedSessionIdFromURL();
}
@Override
public boolean isRequestedSessionIdFromUrl()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.isRequestedSessionIdFromUrl();
}
@Override
public Object getAttribute(String name)
{
return attributes.get(name);
if (request == null)
return attributes.get(name);
return request.getAttribute(name);
}
@Override
public Enumeration<String> getAttributeNames()
{
return Collections.enumeration(attributes.keySet());
}
public Map<String, Object> getAttributes()
{
return Collections.unmodifiableMap(attributes);
if (request == null)
return Collections.enumeration(attributes.keySet());
return request.getAttributeNames();
}
@Override
@ -400,13 +428,17 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
@Override
public void setAttribute(String name, Object value)
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
attributes.put(name, value);
request.setAttribute(name, value);
}
@Override
public void removeAttribute(String name)
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
attributes.remove(name);
request.removeAttribute(name);
}
@Override
@ -466,122 +498,162 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
}
@Override
public boolean authenticate(HttpServletResponse response)
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.authenticate(response);
}
@Override
public String changeSessionId()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.changeSessionId();
}
@Override
public AsyncContext getAsyncContext()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getAsyncContext();
}
@Override
public String getCharacterEncoding()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getCharacterEncoding();
}
@Override
public int getContentLength()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getContentLength();
}
@Override
public long getContentLengthLong()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getContentLengthLong();
}
@Override
public String getContentType()
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getContentType();
}
@Override
public ServletInputStream getInputStream()
public ServletInputStream getInputStream() throws IOException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getInputStream();
}
@Override
public Part getPart(String name)
public Part getPart(String name) throws IOException, ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getPart(name);
}
@Override
public Collection<Part> getParts()
public Collection<Part> getParts() throws IOException, ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getParts();
}
@Override
public BufferedReader getReader()
public BufferedReader getReader() throws IOException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getReader();
}
@Override
public RequestDispatcher getRequestDispatcher(String path)
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.getRequestDispatcher(path);
}
@Override
public boolean isAsyncStarted()
{
return false;
if (request == null)
return isAsyncStarted;
return request.isAsyncStarted();
}
@Override
public boolean isAsyncSupported()
{
return false;
if (request == null)
return isAsyncSupported;
return request.isAsyncSupported();
}
@Override
public void login(String username, String password)
public void login(String username, String password) throws ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
request.login(username, password);
}
@Override
public void logout()
public void logout() throws ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
request.logout();
}
@Override
public void setCharacterEncoding(String enc)
public void setCharacterEncoding(String enc) throws UnsupportedEncodingException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
request.setCharacterEncoding(enc);
}
@Override
public AsyncContext startAsync() throws IllegalStateException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.startAsync();
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.startAsync(servletRequest, servletResponse);
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException
{
throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE);
if (request == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return request.upgrade(handlerClass);
}
}

View File

@ -0,0 +1,367 @@
//
// ========================================================================
// Copyright (c) 1995-2021 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.websocket.core.server.internal;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public class UpgradeHttpServletResponse implements HttpServletResponse
{
private static final String UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE = "Feature unsupported after Upgraded to WebSocket";
private HttpServletResponse _response;
private int _status;
private Map<String, Collection<String>> _headers;
private Locale _locale;
private String _characterEncoding;
private String _contentType;
public UpgradeHttpServletResponse(HttpServletResponse response)
{
_response = response;
}
public void upgrade()
{
_status = _response.getStatus();
_locale = _response.getLocale();
_characterEncoding = _response.getCharacterEncoding();
_contentType = _response.getContentType();
_headers = new HashMap<>();
for (String name : _response.getHeaderNames())
{
_headers.put(name, _response.getHeaders(name));
}
_response = null;
}
public HttpServletResponse getResponse()
{
return _response;
}
@Override
public int getStatus()
{
if (_response == null)
return _status;
return _response.getStatus();
}
@Override
public String getHeader(String s)
{
if (_response == null)
{
Collection<String> values = _headers.get(s);
if (values == null)
return null;
return values.stream().findFirst().orElse(null);
}
return _response.getHeader(s);
}
@Override
public Collection<String> getHeaders(String s)
{
if (_response == null)
return _headers.get(s);
return _response.getHeaders(s);
}
@Override
public Collection<String> getHeaderNames()
{
if (_response == null)
return _headers.keySet();
return _response.getHeaderNames();
}
@Override
public Locale getLocale()
{
if (_response == null)
return _locale;
return _response.getLocale();
}
@Override
public boolean containsHeader(String s)
{
if (_response == null)
{
Collection<String> values = _headers.get(s);
return values != null && !values.isEmpty();
}
return _response.containsHeader(s);
}
@Override
public String getCharacterEncoding()
{
if (_response == null)
return _characterEncoding;
return _response.getCharacterEncoding();
}
@Override
public String getContentType()
{
if (_response == null)
return _contentType;
return _response.getContentType();
}
@Override
public void addCookie(Cookie cookie)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.addCookie(cookie);
}
@Override
public String encodeURL(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.encodeURL(s);
}
@Override
public String encodeRedirectURL(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.encodeRedirectURL(s);
}
@Override
public String encodeUrl(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.encodeUrl(s);
}
@Override
public String encodeRedirectUrl(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.encodeRedirectUrl(s);
}
@Override
public ServletOutputStream getOutputStream() throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.getOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.getWriter();
}
@Override
public void setCharacterEncoding(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setCharacterEncoding(s);
}
@Override
public void setContentLength(int i)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setContentLength(i);
}
@Override
public void setContentLengthLong(long l)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setContentLengthLong(l);
}
@Override
public void setContentType(String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setContentType(s);
}
@Override
public void setBufferSize(int i)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setBufferSize(i);
}
@Override
public int getBufferSize()
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.getBufferSize();
}
@Override
public void flushBuffer() throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.flushBuffer();
}
@Override
public void resetBuffer()
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.resetBuffer();
}
@Override
public boolean isCommitted()
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
return _response.isCommitted();
}
@Override
public void reset()
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.reset();
}
@Override
public void setLocale(Locale locale)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setLocale(locale);
}
@Override
public void sendError(int sc, String msg) throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.sendError(sc, msg);
}
@Override
public void sendError(int sc) throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.sendError(sc);
}
@Override
public void setHeader(String name, String value)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setHeader(name, value);
}
@Override
public void sendRedirect(String s) throws IOException
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.sendRedirect(s);
}
@Override
public void setDateHeader(String s, long l)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setDateHeader(s, l);
}
@Override
public void addDateHeader(String s, long l)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.addDateHeader(s, l);
}
@Override
public void addHeader(String name, String value)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.addHeader(name, value);
}
@Override
public void setIntHeader(String s, int i)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setIntHeader(s, i);
}
@Override
public void addIntHeader(String s, int i)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.addIntHeader(s, i);
}
@Override
public void setStatus(int i)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setStatus(i);
}
@Override
public void setStatus(int i, String s)
{
if (_response == null)
throw new UnsupportedOperationException(UNSUPPORTED_AFTER_WEBSOCKET_UPGRADE);
_response.setStatus(i, s);
}
}

View File

@ -37,6 +37,7 @@ import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,6 +51,7 @@ import org.testcontainers.utility.MountableFile;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Disabled
@Testcontainers
public class AutobahnTests
{

View File

@ -124,9 +124,8 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec");
WebSocketUpgradeFilter.ensureFilter(contextHandler.getServletContext());
webSocketMappings.addMapping(ps,
(req, resp) -> creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp)),
frameHandlerFactory, customizer);
WebSocketCreator coreCreator = (req, resp) -> creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp));
webSocketMappings.addMapping(ps, coreCreator, frameHandlerFactory, customizer);
}
public void addMapping(String pathSpec, final Class<?> endpointClass)

View File

@ -0,0 +1,90 @@
//
// ========================================================================
// Copyright (c) 1995-2021 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.websocket.tests;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
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.is;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class JettyWebSocketServletAttributeTest
{
private Server server;
private ServerConnector connector;
private WebSocketClient client;
private final EchoSocket serverEndpoint = new EchoSocket();
@BeforeEach
public void before()
{
server = new Server();
connector = new ServerConnector(server);
server.addConnector(connector);
client = new WebSocketClient();
}
@AfterEach
public void stop() throws Exception
{
client.stop();
server.stop();
}
public void start(JettyWebSocketServletContainerInitializer.Configurator configurator) throws Exception
{
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/");
server.setHandler(contextHandler);
JettyWebSocketServletContainerInitializer.configure(contextHandler, configurator);
server.start();
client.start();
}
@Test
public void testAttributeSetInNegotiation() throws Exception
{
start((context, container) -> container.addMapping("/", (req, resp) ->
{
req.setServletAttribute("myWebSocketCustomAttribute", "true");
return serverEndpoint;
}));
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/filterPath");
EventSocket clientEndpoint = new EventSocket();
client.connect(clientEndpoint, uri);
assertTrue(clientEndpoint.openLatch.await(5, TimeUnit.SECONDS));
assertTrue(serverEndpoint.openLatch.await(5, TimeUnit.SECONDS));
// We should have our custom attribute on the upgraded request, which was set in the negotiation.
JettyServerUpgradeRequest upgradeRequest = (JettyServerUpgradeRequest)serverEndpoint.session.getUpgradeRequest();
assertThat(upgradeRequest.getServletAttribute("myWebSocketCustomAttribute"), is("true"));
clientEndpoint.session.close();
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
}
}

View File

@ -347,8 +347,8 @@ public class WebSocketOverHTTP2Test
});
factory.addMapping("/ws/connectionClose", (request, response) ->
{
UpgradeHttpServletRequest servletRequest = (UpgradeHttpServletRequest)request.getHttpServletRequest();
Request baseRequest = servletRequest.getBaseRequest();
UpgradeHttpServletRequest upgradeRequest = (UpgradeHttpServletRequest)request.getHttpServletRequest();
Request baseRequest = (Request)upgradeRequest.getHttpServletRequest();
baseRequest.getHttpChannel().getEndPoint().close();
return new EchoSocket();
});