summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jdisc_http_service/pom.xml4
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/Cookie.java174
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/CookieTestCase.java7
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java2
-rw-r--r--pom.xml5
-rw-r--r--zkfacade/pom.xml5
6 files changed, 133 insertions, 64 deletions
diff --git a/jdisc_http_service/pom.xml b/jdisc_http_service/pom.xml
index 2dfcb0bd166..0c19f2c3d15 100644
--- a/jdisc_http_service/pom.xml
+++ b/jdisc_http_service/pom.xml
@@ -22,10 +22,6 @@
<classifier>no_aop</classifier>
</dependency>
<dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty</artifactId>
- </dependency>
- <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/Cookie.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/Cookie.java
index 8f04a870dc9..2256a3299a7 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/Cookie.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/Cookie.java
@@ -1,20 +1,22 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.http;
-import org.jboss.netty.handler.codec.http.cookie.ClientCookieDecoder;
-import org.jboss.netty.handler.codec.http.cookie.ClientCookieEncoder;
-import org.jboss.netty.handler.codec.http.cookie.DefaultCookie;
-import org.jboss.netty.handler.codec.http.cookie.ServerCookieDecoder;
-import org.jboss.netty.handler.codec.http.cookie.ServerCookieEncoder;
+import org.eclipse.jetty.server.CookieCutter;
+import org.eclipse.jetty.server.Response;
+import java.net.HttpCookie;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
/**
* A RFC 6265 compliant cookie.
@@ -26,6 +28,8 @@ import java.util.stream.StreamSupport;
*/
public class Cookie {
+ private final static Logger log = Logger.getLogger(Cookie.class.getName());
+
private final Set<Integer> ports = new HashSet<>();
private String name;
private String value;
@@ -214,26 +218,18 @@ public class Cookie {
ret.append(name).append("=").append(value);
return ret.toString();
}
+ // NOTE cookie encoding and decoding:
+ // The implementation uses Jetty for server-side (encoding of Set-Cookie and decoding of Cookie header),
+ // and java.net.HttpCookie for client-side (encoding of Cookie and decoding of Set-Cookie header).
+ //
+ // Implementation is RFC-6265 compliant.
public static String toCookieHeader(Iterable<? extends Cookie> cookies) {
- ClientCookieEncoder encoder = ClientCookieEncoder.STRICT;
- List<org.jboss.netty.handler.codec.http.cookie.Cookie> nettyCookies =
- StreamSupport.stream(cookies.spliterator(), false)
- // NOTE: Only name and value is included in Cookie header as of RFC-6265
- .map(cookie -> new DefaultCookie(cookie.getName(), cookie.getValue()))
- .collect(Collectors.toList());
- return encoder.encode(nettyCookies);
+ return encodeCookieHeaderValue(toCookieList(cookies));
}
public static List<Cookie> fromCookieHeader(String headerVal) {
- if (headerVal == null) return Collections.emptyList();
-
- ServerCookieDecoder decoder = ServerCookieDecoder.STRICT;
- Set<org.jboss.netty.handler.codec.http.cookie.Cookie> nettyCookies = decoder.decode(headerVal);
- return nettyCookies.stream()
- // NOTE: Only name and value is included in Cookie header as of RFC-6265
- .map(nettyCookie -> new Cookie(nettyCookie.name(), nettyCookie.value()))
- .collect(Collectors.toList());
+ return decodeCookieHeaderValue(headerVal);
}
/**
@@ -241,40 +237,124 @@ public class Cookie {
*/
@Deprecated
public static String toSetCookieHeader(Iterable<? extends Cookie> cookies) {
- List<String> encodedCookies = toSetCookieHeaderAll(cookies);
+ List<String> encodedCookies = encodeSetCookieHeaderValue(cookies);
return encodedCookies.isEmpty() ? null : encodedCookies.get(0);
}
// TODO Rename to toSetCookieHeader for Vespa 7
public static List<String> toSetCookieHeaderAll(Iterable<? extends Cookie> cookies) {
- ServerCookieEncoder encoder = ServerCookieEncoder.STRICT;
- List<org.jboss.netty.handler.codec.http.cookie.Cookie> nettyCookies =
- StreamSupport.stream(cookies.spliterator(), false)
- .map(cookie -> {
- org.jboss.netty.handler.codec.http.cookie.Cookie nettyCookie
- = new DefaultCookie(cookie.getName(), cookie.getValue());
- nettyCookie.setPath(cookie.getPath());
- nettyCookie.setMaxAge(cookie.getMaxAge(TimeUnit.SECONDS));
- nettyCookie.setSecure(cookie.isSecure());
- nettyCookie.setHttpOnly(cookie.isHttpOnly());
- nettyCookie.setDomain(cookie.getDomain());
- return nettyCookie;
- })
- .collect(Collectors.toList());
- return encoder.encode(nettyCookies);
+ return encodeSetCookieHeaderValue(cookies);
}
// TODO Change return type to Cookie for Vespa 7
public static List<Cookie> fromSetCookieHeader(String headerVal) {
- if (headerVal == null) return Collections.emptyList();
-
- ClientCookieDecoder encoder = ClientCookieDecoder.STRICT;
- org.jboss.netty.handler.codec.http.cookie.Cookie nettyCookie = encoder.decode(headerVal);
- return Collections.singletonList(new Cookie(nettyCookie.name(), nettyCookie.value())
- .setHttpOnly(nettyCookie.isHttpOnly())
- .setSecure(nettyCookie.isSecure())
- .setMaxAge(nettyCookie.maxAge(), TimeUnit.SECONDS)
- .setPath(nettyCookie.path())
- .setDomain(nettyCookie.domain()));
+ return decodeSetCookieHeaderValue(headerVal);
+ }
+
+
+ private static List<String> encodeSetCookieHeaderValue(Iterable<? extends Cookie> cookies) {
+ // Ugly, bot Jetty does not provide a dedicated cookie parser (will be included in Jetty 10)
+ Response response = new Response(null, null);
+ for (Cookie cookie : cookies) {
+ response.addSetRFC6265Cookie(
+ cookie.getName(),
+ cookie.getValue(),
+ cookie.getDomain(),
+ cookie.getPath(),
+ cookie.getMaxAge(TimeUnit.SECONDS),
+ cookie.isSecure(),
+ cookie.isHttpOnly());
+ }
+ return new ArrayList<>(response.getHeaders("Set-Cookie"));
+ }
+
+ private static String encodeCookieHeaderValue(List<Cookie> cookies) {
+ return cookies.stream()
+ .map(cookie -> {
+ HttpCookie httpCookie = new HttpCookie(cookie.getName(), cookie.getValue());
+ httpCookie.setComment(cookie.getComment());
+ httpCookie.setCommentURL(cookie.getCommentURL());
+ httpCookie.setDiscard(cookie.isDiscard());
+ httpCookie.setDomain(cookie.getDomain());
+ httpCookie.setHttpOnly(cookie.isHttpOnly());
+ httpCookie.setMaxAge(cookie.getMaxAge(TimeUnit.SECONDS));
+ httpCookie.setPath(cookie.getPath());
+ httpCookie.setSecure(cookie.isSecure());
+ httpCookie.setVersion(cookie.getVersion());
+ String portList = cookie.ports().stream()
+ .map(Number::toString)
+ .collect(Collectors.joining(","));
+ httpCookie.setPortlist(portList);
+ return httpCookie.toString();
+ })
+ .collect(Collectors.joining(";"));
+ }
+
+ private static List<Cookie> decodeSetCookieHeaderValue(String headerVal) {
+
+ return HttpCookie.parse(headerVal).stream()
+ .map(httpCookie -> {
+ Cookie cookie = new Cookie();
+ cookie.setName(httpCookie.getName());
+ cookie.setValue(httpCookie.getValue());
+ cookie.setComment(httpCookie.getComment());
+ cookie.setCommentUrl(httpCookie.getCommentURL());
+ cookie.setDiscard(httpCookie.getDiscard());
+ cookie.setDomain(httpCookie.getDomain());
+ cookie.setHttpOnly(httpCookie.isHttpOnly());
+ int maxAge = (int) httpCookie.getMaxAge();
+ cookie.setMaxAge(maxAge != -1 ? maxAge : Integer.MIN_VALUE, TimeUnit.SECONDS);
+ cookie.setPath(httpCookie.getPath());
+ cookie.setSecure(httpCookie.getSecure());
+ cookie.setVersion(httpCookie.getVersion());
+ cookie.ports().addAll(parsePortList(httpCookie.getPortlist()));
+ return cookie;
+ })
+ .collect(Collectors.toList());
+ }
+
+ private static List<Cookie> decodeCookieHeaderValue(String headerVal) {
+ CookieCutter cookieCutter = new CookieCutter();
+ cookieCutter.addCookieField(headerVal);
+ return Arrays.stream(cookieCutter.getCookies())
+ .map(servletCookie -> {
+ Cookie cookie = new Cookie();
+ cookie.setName(servletCookie.getName());
+ cookie.setValue(servletCookie.getValue());
+ cookie.setComment(servletCookie.getComment());
+ cookie.setPath(servletCookie.getPath());
+ cookie.setDomain(servletCookie.getDomain());
+ int maxAge = servletCookie.getMaxAge();
+ cookie.setMaxAge(maxAge != -1 ? maxAge : Integer.MIN_VALUE, TimeUnit.SECONDS);
+ cookie.setSecure(servletCookie.getSecure());
+ cookie.setVersion(servletCookie.getVersion());
+ cookie.setHttpOnly(servletCookie.isHttpOnly());
+ return cookie;
+ })
+ .collect(Collectors.toList());
+ }
+
+ private static List<Integer> parsePortList(String rawPortList) {
+ if (rawPortList == null) return Collections.emptyList();
+
+ List<Integer> ports = new ArrayList<>();
+ StringTokenizer tokenizer = new StringTokenizer(rawPortList, ",");
+ while (tokenizer.hasMoreTokens()) {
+ String rawPort = tokenizer.nextToken().trim();
+ if (!rawPort.isEmpty()) {
+ try {
+ ports.add(Integer.parseInt(rawPort));
+ } catch (NumberFormatException e) {
+ log.log(Level.FINE, "Unable to parse port: " + rawPort, e);
+ }
+ }
+ }
+ return ports;
+ }
+
+ private static ArrayList<Cookie> toCookieList(Iterable<? extends Cookie> cookies) {
+ ArrayList<Cookie> cookieList = new ArrayList<>();
+ cookies.forEach(cookieList::add);
+ return cookieList;
}
}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/CookieTestCase.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/CookieTestCase.java
index 0c98f294c82..ca12de72ec2 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/CookieTestCase.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/CookieTestCase.java
@@ -106,14 +106,14 @@ public class CookieTestCase {
"foo.name=foo.value",
Collections.singletonList(newCookie("foo")));
assertEncodeCookie(
- "foo.name=foo.value; bar.name=bar.value",
+ "foo.name=foo.value;bar.name=bar.value",
Arrays.asList(newCookie("foo"), newCookie("bar")));
}
@Test
public void requireThatSetCookieCanBeEncoded() {
assertEncodeSetCookie(
- Collections.singletonList("foo.name=foo.value; Path=path; Domain=domain; Secure; HTTPOnly"),
+ Collections.singletonList("foo.name=foo.value;Path=path;Domain=domain;Secure;HttpOnly"),
Collections.singletonList(newSetCookie("foo")));
}
@@ -131,6 +131,7 @@ public class CookieTestCase {
}
@Test
+ @SuppressWarnings("deprecation")
public void requireThatSetCookieCanBeDecoded() {
final Cookie foo = new Cookie();
foo.setName("foo.name");
@@ -140,6 +141,7 @@ public class CookieTestCase {
foo.setMaxAge(0, TimeUnit.SECONDS);
foo.setSecure(true);
foo.setHttpOnly(true);
+ foo.setVersion(1);
assertDecodeSetCookie(foo, "foo.name=foo.value;Max-Age=0;Path=path;Domain=domain;Secure;HTTPOnly;");
final Cookie bar = new Cookie();
@@ -148,6 +150,7 @@ public class CookieTestCase {
bar.setPath("path");
bar.setDomain("domain");
bar.setMaxAge(0, TimeUnit.SECONDS);
+ bar.setVersion(1);
assertDecodeSetCookie(bar, "bar.name=bar.value;Max-Age=0;Path=path;Domain=domain;");
}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
index 221a1adc1fe..7ed13decbf6 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
@@ -356,7 +356,7 @@ public class HttpServerTest {
driver.client().get("/status.html")
.expectStatusCode(is(OK))
.expectHeader("Set-Cookie",
- is("foo=bar; Path=/foopath; Domain=.localhost; Secure; HTTPOnly"));
+ is("foo=bar;Path=/foopath;Domain=.localhost;Secure;HttpOnly"));
assertThat(driver.close(), is(true));
}
diff --git a/pom.xml b/pom.xml
index dd7042bf911..f17d424185e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -557,11 +557,6 @@
<version>${curator.version}</version>
</dependency>
<dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty</artifactId>
- <version>3.10.6.Final</version>
- </dependency>
- <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
diff --git a/zkfacade/pom.xml b/zkfacade/pom.xml
index b6dbbe63f71..45ba8c32372 100644
--- a/zkfacade/pom.xml
+++ b/zkfacade/pom.xml
@@ -65,11 +65,6 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
- <!-- Needed to get org.jboss.netty.bootstrap, which zookeeper requires -->
- <dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty</artifactId>
- </dependency>
</dependencies>
<build>
<plugins>