+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *
+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.data; + +/** + * Value of the SameSite cookie attribute (RFC 6265bis), which controls whether a cookie is sent + * with cross-site requests. + * + * @see CookieSetting#setSameSite(SameSite) + */ +public enum SameSite { + + /** The cookie is only sent with same-site requests. */ + STRICT("Strict"), + + /** The cookie is also sent when navigating to the site from another one (browser default). */ + LAX("Lax"), + + /** The cookie is sent with all requests. Requires the Secure attribute. */ + NONE("None"); + + private final String headerValue; + + SameSite(String headerValue) { + this.headerValue = headerValue; + } + + /** + * Returns the value as written in the Set-Cookie header. + * + * @return The header value. + */ + public String getHeaderValue() { + return headerValue; + } + + /** + * Parses a header value, ignoring case. + * + * @param value The header value. + * @return The matching constant, or null if the value is not recognized. + */ + public static SameSite parse(String value) { + if (value != null) { + for (SameSite sameSite : values()) { + if (sameSite.headerValue.equalsIgnoreCase(value.trim())) { + return sameSite; + } + } + } + + return null; + } +} diff --git a/org.restlet/src/main/java/org/restlet/engine/header/CookieReader.java b/org.restlet/src/main/java/org/restlet/engine/header/CookieReader.java index ac95aa4723..2381b89782 100644 --- a/org.restlet/src/main/java/org/restlet/engine/header/CookieReader.java +++ b/org.restlet/src/main/java/org/restlet/engine/header/CookieReader.java @@ -15,16 +15,13 @@ /** * Cookie header reader. * + *
Reads the RFC 6265 format: cookies are separated by semicolons. The pairs of the obsolete RFC
+ * 2109 format ($Version, $Path and $Domain) are silently ignored.
+ *
* @author Jerome Louvel
*/
public class CookieReader extends HeaderReader The commentURL and port attributes are not supported yet.
+ * Reads RFC 6265 cookies. The attributes of the obsolete RFC 2109 and RFC 2965 formats (Version,
+ * Comment, CommentURL, Discard, Port) are silently ignored.
*
* @author Jerome Louvel
*/
@@ -32,10 +34,6 @@ public class CookieSettingReader extends HeaderReader
+ * The content of this file is subject to the terms of the Apache 2.0 open
+ * source license available at https://www.opensource.org/licenses/apache-2.0
+ *
+ * Restlet is a registered trademark of QlikTech International AB.
+ */
+package org.restlet.engine.connector;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.Server;
+import org.restlet.data.Cookie;
+import org.restlet.data.CookieSetting;
+import org.restlet.data.MediaType;
+import org.restlet.data.Protocol;
+import org.restlet.data.SameSite;
+import org.restlet.engine.Engine;
+
+/** Tests the cookie headers on the wire, as written and read by the Netty server connector. */
+class CookieHeadersTestCase {
+
+ private Server server;
+
+ @BeforeEach
+ void setUp() {
+ Engine.clearThreadLocalVariables();
+ Engine.register(false);
+ Engine.getInstance().getRegisteredServers().add(new HttpServerHelper(null));
+ Engine.getInstance().getRegisteredClients().add(new HttpClientHelper(null));
+ }
+
+ @AfterEach
+ void tearDown() throws Exception {
+ if (server != null) {
+ server.stop();
+ }
+ Engine.clearThreadLocalVariables();
+ }
+
+ /** Sends a raw request and returns the raw response head and body. */
+ private String exchange(String requestHeaders) throws Exception {
+ try (Socket socket = new Socket("localhost", server.getActualPort())) {
+ OutputStream out = socket.getOutputStream();
+ out.write(
+ ("GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n"
+ + requestHeaders
+ + "\r\n")
+ .getBytes(StandardCharsets.US_ASCII));
+ out.flush();
+
+ InputStream in = socket.getInputStream();
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ byte[] chunk = new byte[4096];
+ int n;
+ while ((n = in.read(chunk)) != -1) {
+ buffer.write(chunk, 0, n);
+ }
+ return buffer.toString(StandardCharsets.ISO_8859_1);
+ }
+ }
+
+ private static List