From 62b61107461c6d846544f3f8f3f7e3a2e1ecb5e1 Mon Sep 17 00:00:00 2001 From: Arjan Tijms Date: Mon, 27 May 2024 23:39:09 +0200 Subject: [PATCH] Updates for Servlet 6.1 compatibility Signed-off-by: Arjan Tijms --- .../grizzly/http/server/Response.java | 73 ++++++------------- .../servlet/HttpServletResponseImpl.java | 11 ++- .../http/util/CookieHeaderGenerator.java | 17 +++-- .../grizzly/http/util/CookieHeaderParser.java | 32 ++++---- 4 files changed, 59 insertions(+), 74 deletions(-) diff --git a/modules/http-server/src/main/java/org/glassfish/grizzly/http/server/Response.java b/modules/http-server/src/main/java/org/glassfish/grizzly/http/server/Response.java index d29ff9d1e6..9fb64caf75 100755 --- a/modules/http-server/src/main/java/org/glassfish/grizzly/http/server/Response.java +++ b/modules/http-server/src/main/java/org/glassfish/grizzly/http/server/Response.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 Contributors to the Eclipse Foundation * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved. * Copyright 2004 The Apache Software Foundation * @@ -18,16 +19,13 @@ package org.glassfish.grizzly.http.server; import static org.glassfish.grizzly.http.util.Constants.DEFAULT_HTTP_CHARACTER_ENCODING; +import static org.glassfish.grizzly.http.util.Constants.DEFAULT_HTTP_CHARSET; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.LinkedList; @@ -38,7 +36,6 @@ import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; - import org.glassfish.grizzly.CloseListener; import org.glassfish.grizzly.CloseType; import org.glassfish.grizzly.Closeable; @@ -673,7 +670,7 @@ public boolean isCommitted() { /** * Flush the current buffered content to the network. - * + * * @throws IOException if an occur occurs flushing to the wire. */ public void flush() throws IOException { @@ -954,17 +951,7 @@ public void addCookie(final Cookie cookie) { final StringBuilder sb = new StringBuilder(); // web application code can receive a IllegalArgumentException // from the appendCookieValue invokation - if (System.getSecurityManager() != null) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - CookieSerializerUtils.serializeServerCookie(sb, cookie); - return null; - } - }); - } else { - CookieSerializerUtils.serializeServerCookie(sb, cookie); - } + CookieSerializerUtils.serializeServerCookie(sb, cookie); // if we reached here, no exception, cookie is valid // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 ) @@ -988,17 +975,7 @@ protected void addSessionCookieInternal(final Cookie cookie) { final StringBuilder sb = new StringBuilder(); // web application code can receive a IllegalArgumentException // from the appendCookieValue invokation - if (System.getSecurityManager() != null) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - CookieSerializerUtils.serializeServerCookie(sb, cookie); - return null; - } - }); - } else { - CookieSerializerUtils.serializeServerCookie(sb, cookie); - } + CookieSerializerUtils.serializeServerCookie(sb, cookie); final String cookieString = sb.toString(); @@ -1279,7 +1256,18 @@ public void sendError(final int status, final String message) throws IOException * @exception java.io.IOException if an input/output error occurs */ public void sendRedirect(String location) throws IOException { + sendRedirect(location, 302, appCommitted); + } + /** + * Send a temporary redirect to the specified redirect location URL. + * + * @param location Location URL to redirect to + * + * @exception IllegalStateException if this response has already been committed + * @exception java.io.IOException if an input/output error occurs + */ + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { if (isCommitted()) { throw new IllegalStateException("Illegal attempt to redirect the response as the response has been committed."); } @@ -1291,7 +1279,7 @@ public void sendRedirect(String location) throws IOException { try { String absolute = toAbsolute(location, true); // END RIMOD 4642650 - setStatus(HttpStatus.FOUND_302); + setStatus(HttpStatus.getHttpStatus(sc)); setHeader(Header.Location, absolute); // According to RFC2616 section 10.3.3 302 Found, @@ -1317,7 +1305,7 @@ public void sendRedirect(String location) throws IOException { getWriter().flush(); } catch (IllegalStateException ise1) { try { - getOutputStream().write(sb.toString().getBytes(org.glassfish.grizzly.http.util.Constants.DEFAULT_HTTP_CHARSET)); + getOutputStream().write(sb.toString().getBytes(DEFAULT_HTTP_CHARSET)); } catch (IllegalStateException ise2) { // ignore; the RFC says "SHOULD" so it is acceptable // to omit the body in case of an error @@ -1505,12 +1493,12 @@ public void setStatus(int status, String message) { /** * Set the HTTP status and message to be returned with this response. - * + * * @param status {@link HttpStatus} to set */ public void setStatus(HttpStatus status) { - checkResponse(); + if (isCommitted()) { return; } @@ -1563,22 +1551,7 @@ protected String toAbsolute(final String location, final boolean normalize) { final int pos = relativePath.lastIndexOf('/'); relativePath = relativePath.substring(0, pos); - final String encodedURI; - if (System.getSecurityManager() != null) { - try { - final String frelativePath = relativePath; - encodedURI = AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public String run() throws IOException { - return urlEncoder.encodeURL(frelativePath); - } - }); - } catch (PrivilegedActionException pae) { - throw new IllegalArgumentException(location, pae.getCause()); - } - } else { - encodedURI = urlEncoder.encodeURL(relativePath); - } + final String encodedURI = urlEncoder.encodeURL(relativePath); cc.append(encodedURI, 0, encodedURI.length()); cc.append('/'); @@ -1699,7 +1672,7 @@ public SuspendContext getSuspendContext() { /** * Return true if that {@link Response#suspend()} has been * invoked and set to true - * + * * @return true if that {@link Response#suspend()} has been * invoked and set to true */ @@ -1924,7 +1897,7 @@ protected synchronized boolean markCancelled(final int expectedModCount) { /** * Marks {@link Response} as cancelled, but doesn't resume associated {@link FilterChainContext} invocation. - * + * * @deprecated */ @Deprecated diff --git a/modules/http-servlet/src/main/java/org/glassfish/grizzly/servlet/HttpServletResponseImpl.java b/modules/http-servlet/src/main/java/org/glassfish/grizzly/servlet/HttpServletResponseImpl.java index 094982b6cd..531d19694c 100644 --- a/modules/http-servlet/src/main/java/org/glassfish/grizzly/servlet/HttpServletResponseImpl.java +++ b/modules/http-servlet/src/main/java/org/glassfish/grizzly/servlet/HttpServletResponseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved. * Copyright 2004 The Apache Software Foundation * @@ -459,7 +459,14 @@ public void sendError(int sc) throws IOException { */ @Override public void sendRedirect(String location) throws IOException { + if (isCommitted()) { + throw new IllegalStateException("Illegal attempt to redirect the response after it has been committed."); + } + response.sendRedirect(location); + } + @Override + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { if (isCommitted()) { throw new IllegalStateException("Illegal attempt to redirect the response after it has been committed."); } @@ -639,4 +646,6 @@ public void setTrailerFields(final Supplier> supplier) { public Supplier> getTrailerFields() { return response.getTrailers(); } + + } diff --git a/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderGenerator.java b/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderGenerator.java index 78560c9035..6ca04b4b86 100644 --- a/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderGenerator.java +++ b/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright 2004, 2022 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -89,8 +89,13 @@ public static String generateHeader(String name, String value, int maxAge, Strin // RFC 6265 prefers Max-Age to Expires but... (see below) if (maxAge > -1) { // Negative Max-Age is equivalent to no Max-Age - header.append("; Max-Age="); - header.append(maxAge); + + // Max age 0 is omit Max-Age itself, but conditionally (see below) + // add Expires + if (maxAge > 0) { + header.append("; Max-Age="); + header.append(maxAge); + } if (CookieUtils.ALWAYS_ADD_EXPIRES) { // Microsoft IE and Microsoft Edge don't understand Max-Age so send @@ -149,8 +154,10 @@ public static String generateHeader(String name, String value, int maxAge, Strin validateAttribute(entry.getKey(), entry.getValue()); header.append("; "); header.append(entry.getKey()); - header.append('='); - header.append(entry.getValue()); + if (!"".equals(entry.getValue())) { + header.append('='); + header.append(entry.getValue()); + } } } } diff --git a/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderParser.java b/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderParser.java index b6ea633b18..eea8681c96 100644 --- a/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderParser.java +++ b/modules/http/src/main/java/org/glassfish/grizzly/http/util/CookieHeaderParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright 2004, 2022 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -194,26 +194,22 @@ private static SkipResult skipByte(ByteBuffer byteBuffer, byte target) { */ private static ByteBuffer readCookieValueRfc6265(ByteBuffer byteBuffer) { boolean quoted = false; - if (byteBuffer.hasRemaining()) { - if (byteBuffer.get() == QUOTE_BYTE) { - quoted = true; - } else { - byteBuffer.rewind(); - } - } - int start = byteBuffer.position(); - int end = byteBuffer.limit(); + int cookieValueStart = byteBuffer.position(); + int cookieValueEnd = byteBuffer.limit(); + while (byteBuffer.hasRemaining()) { - byte b = byteBuffer.get(); - if (isCookieOctet[(b & 0xFF)]) { + byte byteFromBuffer = byteBuffer.get(); + if (isCookieOctet[(byteFromBuffer & 0xFF)]) { // NO-OP - } else if (b == SEMICOLON_BYTE || b == SPACE_BYTE || b == TAB_BYTE) { - end = byteBuffer.position() - 1; - byteBuffer.position(end); + } else if (byteFromBuffer == SEMICOLON_BYTE || byteFromBuffer == SPACE_BYTE || byteFromBuffer == TAB_BYTE) { + cookieValueEnd = byteBuffer.position() - 1; + byteBuffer.position(cookieValueEnd); break; - } else if (quoted && b == QUOTE_BYTE) { - end = byteBuffer.position() - 1; + } else if (byteFromBuffer == QUOTE_BYTE && cookieValueStart == byteBuffer.position() -1) { + quoted = true; + } else if (quoted && byteFromBuffer == QUOTE_BYTE) { + cookieValueEnd = byteBuffer.position(); break; } else { // Invalid cookie @@ -221,7 +217,7 @@ private static ByteBuffer readCookieValueRfc6265(ByteBuffer byteBuffer) { } } - return new ByteBuffer(byteBuffer.bytes, start, end - start); + return new ByteBuffer(byteBuffer.bytes, cookieValueStart, cookieValueEnd - cookieValueStart); }