From e0e6fc4cf41c7a031f140b9a8bfd8c0ba5fec7e6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Tue, 13 Feb 2018 14:58:33 +0200 Subject: [PATCH] Set no-store headers for error responses (#10628) --- .../com/vaadin/server/VaadinResponse.java | 17 ++++++++++ .../java/com/vaadin/server/VaadinService.java | 33 ++++++++++++++++--- .../java/com/vaadin/server/VaadinServlet.java | 6 ++-- .../server/communication/UIInitHandler.java | 16 +++------ .../communication/UidlRequestHandler.java | 3 +- .../application/CriticalNotifications.java | 2 +- 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/server/src/main/java/com/vaadin/server/VaadinResponse.java b/server/src/main/java/com/vaadin/server/VaadinResponse.java index e3422d1d48..7414b8d97c 100644 --- a/server/src/main/java/com/vaadin/server/VaadinResponse.java +++ b/server/src/main/java/com/vaadin/server/VaadinResponse.java @@ -185,6 +185,23 @@ public interface VaadinResponse extends Serializable { */ public void setContentLength(int len); + /** + * Sets all conceivable headers that might prevent a response from being + * stored in any caches. + * + * @since + */ + public default void setNoCacheHeaders() { + // no-store to disallow storing even if cache would be revalidated + // must-revalidate to not use stored value even if someone asks for it + setHeader("Cache-Control", + "no-cache, no-store, must-revalidate"); + + // Also set legacy values in case of old proxies in between + setHeader("Pragma", "no-cache"); + setHeader("Expires", "0"); + } + /** * Gets the currently processed Vaadin response. The current response is * automatically defined when the request is started. The current response diff --git a/server/src/main/java/com/vaadin/server/VaadinService.java b/server/src/main/java/com/vaadin/server/VaadinService.java index 9b9c7fd913..f995de0b5f 100644 --- a/server/src/main/java/com/vaadin/server/VaadinService.java +++ b/server/src/main/java/com/vaadin/server/VaadinService.java @@ -1635,7 +1635,7 @@ public abstract class VaadinService implements Serializable { SystemMessages ci = getSystemMessages(ServletPortletHelper .findLocale(null, vaadinSession, request), request); try { - writeStringResponse(response, + writeUncachedStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, createCriticalNotificationJSON( ci.getInternalErrorCaption(), @@ -1667,23 +1667,46 @@ public abstract class VaadinService implements Serializable { * The response reference * @param contentType * The content type of the response - * @param reponseString + * @param responseString * The actual response * @throws IOException * If an error occurred while writing the response */ public void writeStringResponse(VaadinResponse response, String contentType, - String reponseString) throws IOException { + String responseString) throws IOException { response.setContentType(contentType); final OutputStream out = response.getOutputStream(); try (PrintWriter outWriter = new PrintWriter( new BufferedWriter(new OutputStreamWriter(out, UTF_8)))) { - outWriter.print(reponseString); + outWriter.print(responseString); } } + /** + * Writes the given string as a response with headers to prevent caching and + * using the given content type. + * + * @param response + * The response reference + * @param contentType + * The content type of the response + * @param responseString + * The actual response + * @throws IOException + * If an error occurred while writing the response + * @since + */ + public void writeUncachedStringResponse(VaadinResponse response, + String contentType, String responseString) throws IOException { + // Response might contain sensitive information, so prevent all forms of + // caching + response.setNoCacheHeaders(); + + writeStringResponse(response, contentType, responseString); + } + /** * Called when the session has expired and the request handling is therefore * aborted. @@ -1802,7 +1825,7 @@ public abstract class VaadinService implements Serializable { public void criticalNotification(VaadinRequest request, VaadinResponse response, String caption, String message, String details, String url) throws IOException { - writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, + writeUncachedStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, createCriticalNotificationJSON(caption, message, details, url)); } diff --git a/server/src/main/java/com/vaadin/server/VaadinServlet.java b/server/src/main/java/com/vaadin/server/VaadinServlet.java index 62bfeb0207..e9b30e9e87 100644 --- a/server/src/main/java/com/vaadin/server/VaadinServlet.java +++ b/server/src/main/java/com/vaadin/server/VaadinServlet.java @@ -578,7 +578,7 @@ public class VaadinServlet extends HttpServlet implements Constants { SystemMessages systemMessages = getService().getSystemMessages( ServletPortletHelper.findLocale(null, null, request), request); - getService().writeStringResponse(response, + getService().writeUncachedStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, VaadinService.createCriticalNotificationJSON( systemMessages.getCookiesDisabledCaption(), @@ -625,7 +625,7 @@ public class VaadinServlet extends HttpServlet implements Constants { if (ServletPortletHelper.isUIDLRequest(request)) { String output = VaadinService.createCriticalNotificationJSON( caption, message, details, url); - getService().writeStringResponse(response, + getService().writeUncachedStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, output); } else { // Create an HTML reponse with the error @@ -649,7 +649,7 @@ public class VaadinServlet extends HttpServlet implements Constants { if (url != null) { output += ""; } - getService().writeStringResponse(response, + getService().writeUncachedStringResponse(response, ApplicationConstants.CONTENT_TYPE_TEXT_HTML_UTF_8, output); } } diff --git a/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java b/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java index 12a04c1509..93356a1519 100644 --- a/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java @@ -109,15 +109,9 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { // The response was produced without errors so write it to the client response.setContentType(JsonConstants.JSON_CONTENT_TYPE); - // Response might contain sensitive information, so prevent caching - // no-store to disallow storing even if cache would be revalidated - // must-revalidate to not use stored value even if someone asks for it - response.setHeader("Cache-Control", - "no-cache, no-store, must-revalidate"); - - // Also set legacy values in case of old proxies in between - response.setHeader("Pragma", "no-cache"); - response.setHeader("Expires", "0"); + // Response might contain sensitive information, so prevent all forms of + // caching + response.setNoCacheHeaders(); byte[] b = json.getBytes(UTF_8); response.setContentLength(b.length); @@ -228,7 +222,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { session.addUI(ui); if (initException != null) { ui.getSession().getCommunicationManager() - .handleConnectorRelatedException(ui, initException); + .handleConnectorRelatedException(ui, initException); } // Warn if the window can't be preserved if (embedId == null @@ -316,7 +310,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { String seckey = session.getCsrfToken(); return "\"" + ApplicationConstants.UIDL_SECURITY_TOKEN_ID + "\":\"" - + seckey + "\","; + + seckey + "\","; } /** diff --git a/server/src/main/java/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/main/java/com/vaadin/server/communication/UidlRequestHandler.java index 3aedcd2472..e7fabf752e 100644 --- a/server/src/main/java/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/UidlRequestHandler.java @@ -164,7 +164,8 @@ public class UidlRequestHandler extends SynchronizedRequestHandler SystemMessages systemMessages = service.getSystemMessages( ServletPortletHelper.findLocale(null, null, request), request); - service.writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, + service.writeUncachedStringResponse(response, + JsonConstants.JSON_CONTENT_TYPE, VaadinService.createCriticalNotificationJSON( systemMessages.getSessionExpiredCaption(), systemMessages.getSessionExpiredMessage(), null, diff --git a/uitest/src/main/java/com/vaadin/tests/application/CriticalNotifications.java b/uitest/src/main/java/com/vaadin/tests/application/CriticalNotifications.java index b0e88b102b..792043eae0 100644 --- a/uitest/src/main/java/com/vaadin/tests/application/CriticalNotifications.java +++ b/uitest/src/main/java/com/vaadin/tests/application/CriticalNotifications.java @@ -96,7 +96,7 @@ public class CriticalNotifications extends AbstractReindeerTestUI { VaadinResponse response = VaadinService.getCurrentResponse(); try { - service.writeStringResponse(response, + service.writeUncachedStringResponse(response, JsonConstants.JSON_CONTENT_TYPE, VaadinService.createCriticalNotificationJSON(caption, message, details, url)); -- 2.39.5