Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jetty 12 inserted handler in ee10 servlet context #9927

Merged
merged 32 commits into from
Jun 22, 2023
Merged
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
825aae8
Added distro test for static content features.
gregw Jun 15, 2023
fe1da61
fix ee9 DefaultServlet to make it able to send static content that is…
lorban Jun 15, 2023
1b926cf
Fixed favicon.ico test
gregw Jun 16, 2023
12b7e7b
Disabled gzipHandler for ee10 demo
gregw Jun 16, 2023
8e23eab
Wrap context with gzipHandler for ee10 test
gregw Jun 16, 2023
d0395a9
Misc cleanups of servlet request/response wrappers to simplify them.
gregw Jun 16, 2023
6644ff4
Merge branch 'jetty-12.0.x' into jetty-12-ee10-late-servlet-wrap
gregw Jun 16, 2023
f76bd97
WIP
gregw Jun 16, 2023
f95c515
ServletChannel holds HttpOutput
gregw Jun 16, 2023
bb3c636
WIP
gregw Jun 16, 2023
38bfa48
WIP
gregw Jun 19, 2023
e3b46f5
WIP
gregw Jun 19, 2023
38b2eb7
WIP
gregw Jun 19, 2023
eb03490
WIP
gregw Jun 19, 2023
df6aa6b
WIP
gregw Jun 19, 2023
d813b48
Testing gzip in context
gregw Jun 19, 2023
6de0808
Revert "Disabled gzipHandler for ee10 demo"
gregw Jun 19, 2023
305d824
improved comments
gregw Jun 19, 2023
9158757
updates from review
gregw Jun 19, 2023
55a483b
fixed javadoc
gregw Jun 19, 2023
be6fe3b
updates from review
gregw Jun 20, 2023
a75395a
update javadoc
gregw Jun 20, 2023
f871894
fixed websocket remove extension
gregw Jun 20, 2023
c7d140a
Added info interfaces
gregw Jun 20, 2023
7d2ad66
Added info interfaces
gregw Jun 20, 2023
539c172
Merge branch 'jetty-12.0.x' into jetty-12-ee10-late-servlet-wrap
gregw Jun 20, 2023
c0b6550
updates from review
gregw Jun 20, 2023
6407e18
fixed merge
gregw Jun 21, 2023
1a7ee80
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12-ee10…
gregw Jun 21, 2023
bea21c3
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12-ee10…
gregw Jun 21, 2023
58338f0
Merge branch 'jetty-12.0.x' into jetty-12-ee10-late-servlet-wrap
gregw Jun 22, 2023
21da275
updates from review
gregw Jun 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP
gregw committed Jun 19, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit e3b46f573810bd362620dc80c049ca90f619bf54
Original file line number Diff line number Diff line change
@@ -1214,137 +1214,142 @@ public Wrapper(Mutable fields)
_fields = fields;
}

public boolean onPutField(String name, String value)
public HttpField onAddField(HttpField field)
gregw marked this conversation as resolved.
Show resolved Hide resolved
{
return true;
}

public boolean onAddField(String name, String value)
{
return true;
return field;
}

public boolean onRemoveField(String name)
public boolean onRemoveField(HttpField field)
{
return true;
}

@Override
public Mutable add(String name, String value)
public HttpFields takeAsImmutable()
{
if (onAddField(name, value))
return _fields.add(name, value);
return this;
return Mutable.super.takeAsImmutable();
}

@Override
public Mutable add(HttpHeader header, HttpHeaderValue value)
public int size()
{
if (onAddField(header.asString(), value.asString()))
return _fields.add(header, value);
return this;
// This impl needed only as an optimization
return _fields.size();
}

@Override
public Mutable add(HttpHeader header, String value)
public Stream<HttpField> stream()
{
if (onAddField(header.asString(), value))
return _fields.add(header, value);
return this;
// This impl needed only as an optimization
return _fields.stream();
}

@Override
public Mutable add(HttpField field)
{
if (onAddField(field.getName(), field.getValue()))
return _fields.add(field);
return this;
}

@Override
public Mutable add(HttpFields fields)
{
for (HttpField field : fields)
// This impl needed only as an optimization
if (field != null)
{
add(field);
field = onAddField(field);
if (field != null)
return Mutable.super.add(field);
}
return this;
}

@Override
public Mutable clear()
public ListIterator<HttpField> listIterator()
{
return _fields.clear();
}
ListIterator<HttpField> i = _fields.listIterator();
return new ListIterator<>()
{
HttpField last;

@Override
public Iterator<HttpField> iterator()
{
return _fields.iterator();
}
@Override
public boolean hasNext()
{
return i.hasNext();
}

@Override
public ListIterator<HttpField> listIterator()
{
return _fields.listIterator();
}
@Override
public HttpField next()
{
return last = i.next();
}

@Override
public Mutable put(HttpField field)
{
if (onPutField(field.getName(), field.getValue()))
return _fields.put(field);
return this;
}
@Override
public boolean hasPrevious()
{
return i.hasPrevious();
}

@Override
public Mutable put(String name, String value)
{
if (onPutField(name, value))
return _fields.put(name, value);
return this;
}
@Override
public HttpField previous()
{
return last = i.previous();
}

@Override
public Mutable put(HttpHeader header, HttpHeaderValue value)
{
if (onPutField(header.asString(), value.asString()))
return _fields.put(header, value);
return this;
}
@Override
public int nextIndex()
{
return i.nextIndex();
}

@Override
public Mutable put(HttpHeader header, String value)
{
if (onPutField(header.asString(), value))
return _fields.put(header, value);
return this;
}
@Override
public int previousIndex()
{
return i.previousIndex();
}

@Override
public Mutable remove(HttpHeader header)
{
if (onRemoveField(header.asString()))
return _fields.remove(header);
return this;
}
@Override
public void remove()
{
if (last != null && onRemoveField(last))
{
last = null;
i.remove();
}
}

@Override
public Mutable remove(EnumSet<HttpHeader> fields)
{
for (HttpHeader header : fields)
{
remove(header);
}
return this;
}
@Override
public void set(HttpField field)
{
if (field == null)
{
if (last != null && onRemoveField(last))
{
last = null;
i.remove();
}
}
else
{
if (last != null && onRemoveField(last))
{
field = onAddField(field);
if (field != null)
{
last = null;
i.set(field);
}
}
}
}

@Override
public Mutable remove(String name)
{
if (onRemoveField(name))
return _fields.remove(name);
return this;
@Override
public void add(HttpField field)
{
if (field != null)
{
field = onAddField(field);
if (field != null)
{
last = null;
i.add(field);
}
}
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@ public static Stream<HttpFields.Mutable> mutables()
return Stream.of(
HttpFields.build(),
HttpFields.build(0),
new HttpFields.Mutable.Wrapper(HttpFields.build()),
new HttpFields.Mutable()
{
private final HttpFields.Mutable fields = HttpFields.build();
Original file line number Diff line number Diff line change
@@ -15,75 +15,69 @@

import java.util.Collections;

import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;

public class WebSocketHttpFieldsWrapper extends HttpFields.Mutable.Wrapper
{
private final WebSocketNegotiation _negotiation;
private final ServerUpgradeResponse _response;

public WebSocketHttpFieldsWrapper(Mutable fields, ServerUpgradeResponse response, WebSocketNegotiation negotiation)
{
super(fields);
_negotiation = negotiation;
_response = response;
}

@Override
public boolean onPutField(String name, String value)
public HttpField onAddField(HttpField field)
{
if (HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL.is(name))
if (field.getHeader() != null)
{
_response.setAcceptedSubProtocol(value);
return false;
}

if (HttpHeader.SEC_WEBSOCKET_EXTENSIONS.is(name))
{
_response.setExtensions(ExtensionConfig.parseList(value));
return false;
}
return switch (field.getHeader())
{
case SEC_WEBSOCKET_SUBPROTOCOL ->
{
_response.setAcceptedSubProtocol(field.getValue());
yield field;
}

return super.onPutField(name, value);
}

@Override
public boolean onAddField(String name, String value)
{
if (HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL.is(name))
{
_response.setAcceptedSubProtocol(value);
return false;
}
case SEC_WEBSOCKET_EXTENSIONS ->
{
_response.addExtensions(ExtensionConfig.parseList(field.getValue()));
yield field;
}

if (HttpHeader.SEC_WEBSOCKET_EXTENSIONS.is(name))
{
_response.addExtensions(ExtensionConfig.parseList(value));
return false;
default -> super.onAddField(field);
};
}

return super.onAddField(name, value);
return super.onAddField(field);
}

@Override
public boolean onRemoveField(String name)
public boolean onRemoveField(HttpField field)
{
if (HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL.is(name))
if (field.getHeader() != null)
{
_response.setAcceptedSubProtocol(null);
return false;
}
return switch (field.getHeader())
{
case SEC_WEBSOCKET_SUBPROTOCOL ->
{
_response.setAcceptedSubProtocol(null);
yield false;
}

if (HttpHeader.SEC_WEBSOCKET_EXTENSIONS.is(name))
{
// TODO: why add extensions??
_response.addExtensions(Collections.emptyList());
return false;
}
case SEC_WEBSOCKET_EXTENSIONS ->
{
// TODO: why add extensions??
gregw marked this conversation as resolved.
Show resolved Hide resolved
_response.addExtensions(Collections.emptyList());
yield false;
}

return super.onRemoveField(name);
default -> super.onRemoveField(field);
};
}
return super.onRemoveField(field);
}
}
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.channels.IllegalSelectorException;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
@@ -33,11 +32,9 @@
import org.eclipse.jetty.ee10.servlet.writer.Utf8HttpWriter;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.session.ManagedSession;
@@ -368,63 +365,13 @@ public void setContentType(String contentType)
if (contentType == null)
{
if (_servletContextResponse.isWriting() && getServletContextResponse().getCharacterEncoding() != null)
throw new IllegalSelectorException();
throw new IllegalStateException();

if (getServletContextResponse().getLocale() == null)
getServletContextResponse().setCharacterEncoding(null);
getServletContextResponse().setMimeType(null);
getServletContextResponse().setContentType(null);
getResponse().getHeaders().remove(HttpHeader.CONTENT_TYPE);
}
else
{
getServletContextResponse().setContentType(contentType);
getServletContextResponse().setMimeType(MimeTypes.CACHE.get(contentType));

String charset = MimeTypes.getCharsetFromContentType(contentType);
if (charset == null && getServletContextResponse().getMimeType() != null && getServletContextResponse().getMimeType().isCharsetAssumed())
charset = getServletContextResponse().getMimeType().getCharsetString();

if (charset == null)
{
switch (getServletContextResponse().getEncodingFrom())
{
case NOT_SET:
break;
case DEFAULT:
case INFERRED:
case SET_CONTENT_TYPE:
case SET_LOCALE:
case SET_CHARACTER_ENCODING:
{
getServletContextResponse().setContentType(contentType + ";charset=" + getServletContextResponse().getCharacterEncoding());
getServletContextResponse().setMimeType(MimeTypes.CACHE.get(getServletContextResponse().getContentType()));
break;
}
default:
throw new IllegalStateException(getServletContextResponse().getEncodingFrom().toString());
}
}
else if (_servletContextResponse.isWriting() && !charset.equalsIgnoreCase(getServletContextResponse().getCharacterEncoding()))
{
// too late to change the character encoding;
getServletContextResponse().setContentType(MimeTypes.getContentTypeWithoutCharset(getServletContextResponse().getContentType()));
if (getServletContextResponse().getCharacterEncoding() != null && (getServletContextResponse().getMimeType() == null || !getServletContextResponse().getMimeType().isCharsetAssumed()))
getServletContextResponse().setContentType(getServletContextResponse().getContentType() + ";charset=" + getServletContextResponse().getCharacterEncoding());
getServletContextResponse().setMimeType(MimeTypes.CACHE.get(getServletContextResponse().getContentType()));
}
else
{
getServletContextResponse().setRawCharacterEncoding(charset, ServletContextResponse.EncodingFrom.SET_CONTENT_TYPE);
}

if (HttpGenerator.__STRICT || getServletContextResponse().getMimeType() == null)
getResponse().getHeaders().put(HttpHeader.CONTENT_TYPE, getServletContextResponse().getContentType());
else
{
getServletContextResponse().setContentType(getServletContextResponse().getMimeType().asString());
getResponse().getHeaders().put(getServletContextResponse().getMimeType().getContentTypeField());
}
getResponse().getHeaders().put(HttpHeader.CONTENT_TYPE, contentType);
}
}

@@ -659,7 +606,7 @@ public int hashCode()
@Override
public boolean equals(Object obj)
{
return HttpCookie.equals(this, obj);
return obj instanceof HttpCookie && HttpCookie.equals(this, obj);
}

@Override
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
import jakarta.servlet.http.HttpSession;
import org.eclipse.jetty.ee10.servlet.writer.ResponseWriter;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpHeader;
@@ -48,6 +49,7 @@ protected enum OutputType

private final ServletChannel _servletChannel;
private final ServletApiResponse _servletApiResponse;
private final HttpFields.Mutable.Wrapper _headers;
private String _characterEncoding;
private String _contentType;
private MimeTypes.Type _mimeType;
@@ -79,6 +81,7 @@ public ServletContextResponse(ServletChannel servletChannel, ServletContextReque
super(servletChannel.getContext(), request, response);
_servletChannel = servletChannel;
_servletApiResponse = newServletApiResponse();
_headers = new HttpFieldsWrapper(response.getHeaders());
}

protected ResponseWriter getWriter()
@@ -111,11 +114,6 @@ protected MimeTypes.Type getMimeType()
return _mimeType;
}

protected void setMimeType(MimeTypes.Type mimeType)
{
this._mimeType = mimeType;
}

protected Supplier<Map<String, String>> getTrailers()
{
return _trailers;
@@ -126,21 +124,11 @@ public void setTrailers(Supplier<Map<String, String>> trailers)
this._trailers = trailers;
}

protected void setContentType(String contentType)
{
this._contentType = contentType;
}

protected String getCharacterEncoding()
{
return _characterEncoding;
}

protected void setCharacterEncoding(String value)
{
_characterEncoding = value;
}

protected void setOutputType(OutputType outputType)
{
_outputType = outputType;
@@ -224,7 +212,7 @@ public void setContentLength(int len)
@Override
public HttpFields.Mutable getHeaders()
{
return super.getHeaders();
return _headers;
}

public void setContentLength(long len)
@@ -533,4 +521,119 @@ protected enum EncodingFrom
*/
SET_CHARACTER_ENCODING
}

private class HttpFieldsWrapper extends HttpFields.Mutable.Wrapper
{
public HttpFieldsWrapper(Mutable fields)
{
super(fields);
}

@Override
public HttpField onAddField(HttpField field)
{
if (field.getHeader() != null)
{
switch (field.getHeader())
{
case CONTENT_LENGTH ->
{
if (!isCommitted())
{
_contentLength = field.getLongValue();
return field;
}
}
case CONTENT_TYPE ->
{
if (!isCommitted())
{
return setContentType(field);
}
}
}
}

return super.onAddField(field);
}

@Override
public boolean onRemoveField(HttpField field)
{
if (field.getHeader() != null)
{
switch (field.getHeader())
{
case CONTENT_LENGTH ->
{
if (!isCommitted())
_contentLength = -1;
}
case CONTENT_TYPE ->
{
if (!isCommitted())
{
if (_locale == null)
_characterEncoding = null;
_contentType = null;
_mimeType = null;
}
}
}
}
return true;
}

private HttpField setContentType(HttpField field)
{
_contentType = field.getValue();
_mimeType = MimeTypes.CACHE.get(_contentType);

String charset = MimeTypes.getCharsetFromContentType(_contentType);
if (charset == null && _mimeType != null && _mimeType.isCharsetAssumed())
charset = _mimeType.getCharsetString();

if (charset == null)
{
switch (_encodingFrom)
{
case NOT_SET:
break;
case DEFAULT:
case INFERRED:
case SET_CONTENT_TYPE:
case SET_LOCALE:
case SET_CHARACTER_ENCODING:
{
_contentType = _contentType + ";charset=" + _characterEncoding;
_mimeType = MimeTypes.CACHE.get(_contentType);
field = new HttpField(HttpHeader.CONTENT_TYPE, _contentType);
break;
}
default:
throw new IllegalStateException(_encodingFrom.toString());
}
}
else if (isWriting() && !charset.equalsIgnoreCase(_characterEncoding))
{
// too late to change the character encoding;
_contentType = MimeTypes.getContentTypeWithoutCharset(_contentType);
if (_characterEncoding != null && (_mimeType == null || !_mimeType.isCharsetAssumed()))
_contentType = _contentType + ";charset=" + _characterEncoding;
_mimeType = MimeTypes.CACHE.get(_contentType);
field = new HttpField(HttpHeader.CONTENT_TYPE, _contentType);
}
else
{
_characterEncoding = charset;
_encodingFrom = ServletContextResponse.EncodingFrom.SET_CONTENT_TYPE;
}

if (HttpGenerator.__STRICT || _mimeType == null)
return field;

_contentType = _mimeType.asString();
return _mimeType.getContentTypeField();
}
}
}