From b2c69a03e45b45613f363de02a7048d15d81e2a9 Mon Sep 17 00:00:00 2001 From: Flavia Rainone Date: Tue, 18 Jul 2023 15:26:28 -0300 Subject: [PATCH] [UNDERTOW-2293] Replace boolean values inside of HttpServletResponseImpl by a single flags field. Signed-off-by: Flavia Rainone --- .../servlet/spec/HttpServletResponseImpl.java | 94 +++++++++++-------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/servlet/src/main/java/io/undertow/servlet/spec/HttpServletResponseImpl.java b/servlet/src/main/java/io/undertow/servlet/spec/HttpServletResponseImpl.java index 1fa6f925be..353cf58f0c 100644 --- a/servlet/src/main/java/io/undertow/servlet/spec/HttpServletResponseImpl.java +++ b/servlet/src/main/java/io/undertow/servlet/spec/HttpServletResponseImpl.java @@ -56,12 +56,16 @@ import io.undertow.util.Protocols; import io.undertow.util.RedirectBuilder; import io.undertow.util.StatusCodes; +import org.xnio.Bits; import static io.undertow.util.URLUtils.isAbsoluteUrl; /** + * Implementation of {@code HttpServletResponse}. + * * @author Stuart Douglas * @author Richard Opalka + * @author Flavia Rainone */ public final class HttpServletResponseImpl implements HttpServletResponse { @@ -74,17 +78,22 @@ public final class HttpServletResponseImpl implements HttpServletResponse { private PrintWriter writer; private Integer bufferSize; private long contentLength = -1; - private boolean insideInclude = false; - private Locale locale; - private boolean responseDone = false; - private boolean ignoredFlushPerformed = false; - - private boolean treatAsCommitted = false; + private int flags = 0; + // response is inside include + private static final int INSIDE_INCLUDE_FLAG = 1 << 0x00; + // response is done + private static final int RESPONSE_DONE_FLAG = 1 << 0x01; + // ignored flush has been performed + private static final int IGNORED_FLUSH_PERFORMED_FLAG = 1 << 0x02; + // prevents anything to be added to response + private static final int TREAT_AS_COMMITTED_FLAG = 1 << 0x03; // indicates that we are closing the response and no further content should be written - private boolean contentFullyWritten = false; + private static final int CONTENT_FULLY_WRITTEN_FLAG = 1 << 0x04; + //if a content type has been set either implicitly or implicitly + private static final int CHARSET_SET_FLAG = 1 << 0x05; - private boolean charsetSet = false; //if a content type has been set either implicitly or implicitly + private Locale locale; private String contentType; private String charset; private Supplier> trailerSupplier; @@ -101,7 +110,7 @@ public HttpServerExchange getExchange() { @Override public void addCookie(final Cookie newCookie) { - if (insideInclude) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG)) { return; } final ServletCookieAdaptor servletCookieAdaptor = new ServletCookieAdaptor(newCookie); @@ -118,7 +127,7 @@ public boolean containsHeader(final String name) { @Override public void sendError(final int sc, final String msg) throws IOException { - if(insideInclude) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG)) { //not 100% sure this is the correct action return; } @@ -137,7 +146,7 @@ public void sendError(final int sc, final String msg) throws IOException { exchange.setStatusCode(sc); if(src.isRunningInsideHandler()) { //all we do is set the error on the context, we handle it when the request is returned - treatAsCommitted = true; + flags |= TREAT_AS_COMMITTED_FLAG; src.setError(sc, msg); } else { //if the src is null there is no outer handler, as we are in an asnc request @@ -150,7 +159,7 @@ public void doErrorDispatch(int sc, String error) throws IOException { responseState = ResponseState.NONE; resetBuffer(); exchange.getResponseHeaders().remove(Headers.CONTENT_LENGTH); - treatAsCommitted = false; + flags &= ~TREAT_AS_COMMITTED_FLAG; final String location = servletContext.getDeployment().getErrorPages().getErrorLocation(sc); if (location != null) { RequestDispatcherImpl requestDispatcher = new RequestDispatcherImpl(location, servletContext); @@ -232,7 +241,7 @@ public void setHeader(final HttpString name, final String value) { if(name == null) { throw UndertowServletMessages.MESSAGES.headerNameWasNull(); } - if (insideInclude || ignoredFlushPerformed) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG | IGNORED_FLUSH_PERFORMED_FLAG)) { return; } if(name.equals(Headers.CONTENT_TYPE)) { @@ -254,7 +263,7 @@ public void addHeader(final HttpString name, final String value) { if(name == null) { throw UndertowServletMessages.MESSAGES.headerNameWasNull(); } - if (insideInclude || ignoredFlushPerformed || treatAsCommitted || contentFullyWritten) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG | IGNORED_FLUSH_PERFORMED_FLAG | TREAT_AS_COMMITTED_FLAG | CONTENT_FULLY_WRITTEN_FLAG)) { return; } if(name.equals(Headers.CONTENT_TYPE) && !exchange.getResponseHeaders().contains(Headers.CONTENT_TYPE)) { @@ -276,7 +285,7 @@ public void addIntHeader(final String name, final int value) { @Override public void setStatus(final int sc) { - if (insideInclude || treatAsCommitted) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG | TREAT_AS_COMMITTED_FLAG)) { return; } if (responseStarted()) { @@ -334,7 +343,7 @@ public String getCharacterEncoding() { @Override public String getContentType() { if (contentType != null) { - if (charsetSet) { + if (Bits.anyAreSet(flags, CHARSET_SET_FLAG)) { return contentType + ";charset=" + getCharacterEncoding(); } else { return contentType; @@ -356,7 +365,7 @@ public ServletOutputStream getOutputStream() { @Override public PrintWriter getWriter() throws IOException { if (writer == null) { - if (!charsetSet) { + if (!Bits.anyAreSet(flags, CHARSET_SET_FLAG)) { //servet 5.5 setCharacterEncoding(getCharacterEncoding()); } @@ -383,10 +392,14 @@ private void createOutputStream() { @Override public void setCharacterEncoding(final String charset) { - if (insideInclude || responseStarted() || writer != null || isCommitted()) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG) || responseStarted() || writer != null || isCommitted()) { return; } - charsetSet = charset != null; + if (charset != null) { + flags |= CHARSET_SET_FLAG; + } else { + flags &= ~CHARSET_SET_FLAG; + } this.charset = charset; if (contentType != null) { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, getContentType()); @@ -400,7 +413,7 @@ public void setContentLength(final int len) { @Override public void setContentLengthLong(final long len) { - if (insideInclude || responseStarted()) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG) || responseStarted()) { return; } if(len >= 0) { @@ -412,20 +425,24 @@ public void setContentLengthLong(final long len) { } boolean isIgnoredFlushPerformed() { - return ignoredFlushPerformed; + return Bits.anyAreSet(flags, IGNORED_FLUSH_PERFORMED_FLAG); } void setIgnoredFlushPerformed(boolean ignoredFlushPerformed) { - this.ignoredFlushPerformed = ignoredFlushPerformed; + if (ignoredFlushPerformed) { + flags |= IGNORED_FLUSH_PERFORMED_FLAG; + } else { + flags &= ~IGNORED_FLUSH_PERFORMED_FLAG; + } } private boolean responseStarted() { - return exchange.isResponseStarted() || ignoredFlushPerformed || treatAsCommitted; + return exchange.isResponseStarted() || Bits.anyAreSet(flags, IGNORED_FLUSH_PERFORMED_FLAG | TREAT_AS_COMMITTED_FLAG); } @Override public void setContentType(final String type) { - if (type == null || insideInclude || responseStarted()) { + if (type == null || Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG) || responseStarted()) { return; } ContentTypeInfo ct = servletContext.parseContentType(type); @@ -433,10 +450,10 @@ public void setContentType(final String type) { boolean useCharset = false; if(ct.getCharset() != null && writer == null && !isCommitted()) { charset = ct.getCharset(); - charsetSet = true; + flags |= CHARSET_SET_FLAG; useCharset = true; } - if(useCharset || !charsetSet) { + if(useCharset || !Bits.anyAreSet(flags, CHARSET_SET_FLAG)) { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ct.getHeader()); } else if(ct.getCharset() == null) { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ct.getHeader() + "; charset=" + charset); @@ -474,7 +491,7 @@ public void flushBuffer() throws IOException { } public void closeStreamAndWriter() throws IOException { - if(treatAsCommitted) { + if(Bits.anyAreSet(flags, TREAT_AS_COMMITTED_FLAG)) { return; } if (writer != null) { @@ -527,18 +544,17 @@ public void reset() { responseState = ResponseState.NONE; exchange.getResponseHeaders().clear(); exchange.setStatusCode(StatusCodes.OK); - treatAsCommitted = false; - contentFullyWritten = false; + flags &= ~(TREAT_AS_COMMITTED_FLAG | CONTENT_FULLY_WRITTEN_FLAG); } @Override public void setLocale(final Locale loc) { - if (insideInclude || responseStarted()) { + if (Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG) || responseStarted()) { return; } this.locale = loc; exchange.getResponseHeaders().put(Headers.CONTENT_LANGUAGE, loc.getLanguage() + "-" + loc.getCountry()); - if (!charsetSet && writer == null) { + if (!Bits.anyAreSet(flags, CHARSET_SET_FLAG) && writer == null) { final Map localeCharsetMapping = servletContext.getDeployment().getDeploymentInfo().getLocaleCharsetMapping(); // first try DD provided mappings String charset = null; @@ -575,10 +591,10 @@ public Locale getLocale() { } public void responseDone() { - if (responseDone || treatAsCommitted) { + if (Bits.anyAreSet(flags, RESPONSE_DONE_FLAG | TREAT_AS_COMMITTED_FLAG)) { return; } - responseDone = true; + flags |= RESPONSE_DONE_FLAG; try { closeStreamAndWriter(); } catch (IOException e) { @@ -589,11 +605,15 @@ public void responseDone() { } public boolean isInsideInclude() { - return insideInclude; + return Bits.anyAreSet(flags, INSIDE_INCLUDE_FLAG); } public void setInsideInclude(final boolean insideInclude) { - this.insideInclude = insideInclude; + if (insideInclude) { + this.flags |= INSIDE_INCLUDE_FLAG; + } else { + this.flags &= ~INSIDE_INCLUDE_FLAG; + } } public void setServletContext(final ServletContextImpl servletContext) { @@ -782,7 +802,7 @@ private static String escapeHtml(String msg) { } public boolean isTreatAsCommitted() { - return treatAsCommitted; + return Bits.anyAreSet(flags, TREAT_AS_COMMITTED_FLAG); } @Override @@ -817,7 +837,7 @@ public Supplier> getTrailerFields() { * Marks this response as closed for writing extra bytes, including the addition of headers. */ void setContentFullyWritten() { - this.contentFullyWritten = true; + this.flags |= CONTENT_FULLY_WRITTEN_FLAG; } }