mirror of
https://github.com/jetty/jetty.project.git
synced 2025-02-19 04:55:01 +00:00
jetty-9 - HTTP client: implemented cookie functionalities.
This commit is contained in:
parent
3ba074ecc8
commit
8b7e1463a1
@ -36,6 +36,7 @@ import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.CookieStore;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
@ -94,6 +95,7 @@ public class HttpClient extends AggregateLifeCycle
|
||||
|
||||
private final ConcurrentMap<String, Destination> destinations = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Long, HttpConversation> conversations = new ConcurrentHashMap<>();
|
||||
private final CookieStore cookieStore = new HttpCookieStore();
|
||||
private volatile Executor executor;
|
||||
private volatile ByteBufferPool byteBufferPool;
|
||||
private volatile Scheduler scheduler;
|
||||
@ -155,6 +157,11 @@ public class HttpClient extends AggregateLifeCycle
|
||||
LOG.info("Stopped {}", this);
|
||||
}
|
||||
|
||||
public CookieStore getCookieStore()
|
||||
{
|
||||
return cookieStore;
|
||||
}
|
||||
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return idleTimeout;
|
||||
|
@ -18,12 +18,14 @@
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
@ -57,6 +59,11 @@ public class HttpConnection extends AbstractConnection implements Connection
|
||||
return client;
|
||||
}
|
||||
|
||||
public HttpDestination getDestination()
|
||||
{
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
@ -109,7 +116,6 @@ public class HttpConnection extends AbstractConnection implements Connection
|
||||
request.idleTimeout(client.getIdleTimeout());
|
||||
|
||||
// TODO: follow redirects
|
||||
// TODO: cookies
|
||||
|
||||
HttpVersion version = request.version();
|
||||
HttpFields headers = request.headers();
|
||||
@ -136,6 +142,21 @@ public class HttpConnection extends AbstractConnection implements Connection
|
||||
}
|
||||
}
|
||||
|
||||
// Cookies
|
||||
List<HttpCookie> cookies = client.getCookieStore().getCookies(getDestination(), request.path());
|
||||
StringBuilder cookieString = null;
|
||||
for (int i = 0; i < cookies.size(); ++i)
|
||||
{
|
||||
if (cookieString == null)
|
||||
cookieString = new StringBuilder();
|
||||
if (i > 0)
|
||||
cookieString.append("; ");
|
||||
HttpCookie cookie = cookies.get(i);
|
||||
cookieString.append(cookie.getName()).append("=").append(cookie.getValue());
|
||||
}
|
||||
if (cookieString != null)
|
||||
request.header(HttpHeader.COOKIE.asString(), cookieString.toString());
|
||||
|
||||
// TODO: decoder headers
|
||||
|
||||
// If we are HTTP 1.1, add the Host header
|
||||
|
@ -0,0 +1,192 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
|
||||
public class HttpCookieParser
|
||||
{
|
||||
private static final String[] DATE_PATTERNS = new String[]
|
||||
{
|
||||
"EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",
|
||||
"EEE',' dd MMM yyyy HH:mm:ss 'GMT'",
|
||||
"EEE MMM dd yyyy HH:mm:ss 'GMT'Z"
|
||||
};
|
||||
|
||||
private HttpCookieParser()
|
||||
{
|
||||
}
|
||||
|
||||
public static List<HttpCookie> parseCookies(String headerValue)
|
||||
{
|
||||
if (headerValue.toLowerCase().contains("expires="))
|
||||
{
|
||||
HttpCookie cookie = parseCookie(headerValue, 0);
|
||||
if (cookie != null)
|
||||
return Collections.singletonList(cookie);
|
||||
else
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<HttpCookie> result = new ArrayList<>();
|
||||
List<String> cookieStrings = splitCookies(headerValue);
|
||||
for (String cookieString : cookieStrings)
|
||||
{
|
||||
HttpCookie cookie = parseCookie(cookieString, 1);
|
||||
if (cookie != null)
|
||||
result.add(cookie);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> splitCookies(String headerValue)
|
||||
{
|
||||
// The comma is the separator, but only if it's outside double quotes
|
||||
List<String> result = new ArrayList<>();
|
||||
int start = 0;
|
||||
int quotes = 0;
|
||||
for (int i = 0; i < headerValue.length(); ++i)
|
||||
{
|
||||
char c = headerValue.charAt(i);
|
||||
if (c == ',' && quotes % 2 == 0)
|
||||
{
|
||||
result.add(headerValue.substring(start, i));
|
||||
start = i + 1;
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
++quotes;
|
||||
}
|
||||
}
|
||||
result.add(headerValue.substring(start));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static HttpCookie parseCookie(String cookieString, int version)
|
||||
{
|
||||
String[] cookieParts = cookieString.split(";");
|
||||
|
||||
String nameValue = cookieParts[0];
|
||||
int equal = nameValue.indexOf('=');
|
||||
if (equal < 1)
|
||||
return null;
|
||||
|
||||
String name = nameValue.substring(0, equal).trim();
|
||||
String value = nameValue.substring(equal + 1);
|
||||
String domain = null;
|
||||
String path = "/";
|
||||
long maxAge = -1;
|
||||
boolean httpOnly = false;
|
||||
boolean secure = false;
|
||||
String comment = null;
|
||||
for (int i = 1; i < cookieParts.length; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
String[] attributeParts = cookieParts[i].split("=", 2);
|
||||
String attributeName = attributeParts[0].trim().toLowerCase();
|
||||
String attributeValue = attributeParts.length < 2 ? "" : attributeParts[1].trim();
|
||||
switch (attributeName)
|
||||
{
|
||||
case "domain":
|
||||
{
|
||||
domain = attributeValue;
|
||||
break;
|
||||
}
|
||||
case "path":
|
||||
{
|
||||
path = attributeValue;
|
||||
break;
|
||||
}
|
||||
case "max-age":
|
||||
{
|
||||
maxAge = Long.parseLong(attributeValue);
|
||||
break;
|
||||
}
|
||||
case "expires":
|
||||
{
|
||||
maxAge = parseDate(attributeValue);
|
||||
break;
|
||||
}
|
||||
case "secure":
|
||||
{
|
||||
secure = true;
|
||||
break;
|
||||
}
|
||||
case "httponly":
|
||||
{
|
||||
httpOnly = true;
|
||||
}
|
||||
case "comment":
|
||||
{
|
||||
comment = attributeValue;
|
||||
break;
|
||||
}
|
||||
case "version":
|
||||
{
|
||||
version = Integer.parseInt(attributeValue);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException x)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return new HttpCookie(name, value, domain, path, maxAge, httpOnly, secure, comment, version);
|
||||
}
|
||||
|
||||
private static long parseDate(String attributeValue)
|
||||
{
|
||||
for (String pattern : DATE_PATTERNS)
|
||||
{
|
||||
try
|
||||
{
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
long result = TimeUnit.MILLISECONDS.toSeconds(dateFormat.parse(attributeValue).getTime() - System.currentTimeMillis());
|
||||
if (result < 0)
|
||||
return 0;
|
||||
}
|
||||
catch (ParseException x)
|
||||
{
|
||||
// Ignore and continue
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.eclipse.jetty.client.api.CookieStore;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
|
||||
public class HttpCookieStore implements CookieStore
|
||||
{
|
||||
private final ConcurrentMap<String, Map<String, HttpCookie>> allCookies = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> getCookies(Destination destination, String path)
|
||||
{
|
||||
List<HttpCookie> result = new ArrayList<>();
|
||||
|
||||
String host = destination.host();
|
||||
int port = destination.port();
|
||||
String key = host + ":" + port + path;
|
||||
|
||||
// First lookup: direct hit
|
||||
Map<String, HttpCookie> cookies = allCookies.get(key);
|
||||
if (cookies != null)
|
||||
accumulateCookies(destination, cookies, result);
|
||||
|
||||
// Second lookup: root path
|
||||
if (!"/".equals(path))
|
||||
{
|
||||
key = host + ":" + port + "/";
|
||||
cookies = allCookies.get(key);
|
||||
if (cookies != null)
|
||||
accumulateCookies(destination, cookies, result);
|
||||
}
|
||||
|
||||
// Third lookup: parent domains
|
||||
int domains = host.split("\\.").length - 1;
|
||||
for (int i = 2; i <= domains; ++i)
|
||||
{
|
||||
String[] hostParts = host.split("\\.", i);
|
||||
host = hostParts[hostParts.length - 1];
|
||||
key = host + ":" + port + "/";
|
||||
cookies = allCookies.get(key);
|
||||
if (cookies != null)
|
||||
accumulateCookies(destination, cookies, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void accumulateCookies(Destination destination, Map<String, HttpCookie> cookies, List<HttpCookie> result)
|
||||
{
|
||||
for (Iterator<HttpCookie> iterator = cookies.values().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
HttpCookie cookie = iterator.next();
|
||||
if (cookie.isExpired(System.nanoTime()))
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!"https".equalsIgnoreCase(destination.scheme()) && cookie.isSecure())
|
||||
continue;
|
||||
result.add(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addCookie(Destination destination, HttpCookie cookie)
|
||||
{
|
||||
String destinationDomain = destination.host() + ":" + destination.port();
|
||||
|
||||
// Check whether it is the same domain
|
||||
String domain = cookie.getDomain();
|
||||
if (domain == null)
|
||||
domain = destinationDomain;
|
||||
|
||||
if (domain.indexOf(':') < 0)
|
||||
domain += ":" + ("https".equalsIgnoreCase(destination.scheme()) ? 443 : 80);
|
||||
|
||||
// Cookie domains may start with a ".", like ".domain.com"
|
||||
// This also avoids that a request to sub.domain.com sets a cookie for domain.com
|
||||
if (!domain.endsWith(destinationDomain))
|
||||
return false;
|
||||
|
||||
// Normalize the path
|
||||
String path = cookie.getPath();
|
||||
if (path == null || path.length() == 0)
|
||||
path = "/";
|
||||
|
||||
String key = destination.host() + ":" + destination.port() + path;
|
||||
Map<String, HttpCookie> cookies = allCookies.get(key);
|
||||
if (cookies == null)
|
||||
{
|
||||
cookies = new ConcurrentHashMap<>();
|
||||
Map<String, HttpCookie> existing = allCookies.putIfAbsent(key, cookies);
|
||||
if (existing != null)
|
||||
cookies = existing;
|
||||
}
|
||||
cookies.put(path, cookie);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -21,10 +21,13 @@ package org.eclipse.jetty.client;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.client.api.CookieStore;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
@ -115,6 +118,25 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
|
||||
{
|
||||
HttpExchange exchange = connection.getExchange();
|
||||
exchange.response().headers().put(name, value);
|
||||
|
||||
switch (name.toLowerCase())
|
||||
{
|
||||
case "set-cookie":
|
||||
case "set-cookie2":
|
||||
{
|
||||
CookieStore cookieStore = connection.getHttpClient().getCookieStore();
|
||||
HttpDestination destination = connection.getDestination();
|
||||
List<HttpCookie> cookies = HttpCookieParser.parseCookies(value);
|
||||
for (HttpCookie cookie : cookies)
|
||||
cookieStore.addCookie(destination, cookie);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
|
||||
public interface CookieStore
|
||||
{
|
||||
List<HttpCookie> getCookies(Destination destination, String path);
|
||||
|
||||
boolean addCookie(Destination destination, HttpCookie cookie);
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpCookieParserTest
|
||||
{
|
||||
@Test
|
||||
public void testParseCookie1() throws Exception
|
||||
{
|
||||
String value = "wd=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com; httponly; secure";
|
||||
List<HttpCookie> cookies = HttpCookieParser.parseCookies(value);
|
||||
Assert.assertEquals(1, cookies.size());
|
||||
HttpCookie cookie = cookies.get(0);
|
||||
Assert.assertEquals("wd", cookie.getName());
|
||||
Assert.assertEquals("deleted", cookie.getValue());
|
||||
Assert.assertEquals(".domain.com", cookie.getDomain());
|
||||
Assert.assertEquals("/", cookie.getPath());
|
||||
Assert.assertTrue(cookie.isHttpOnly());
|
||||
Assert.assertTrue(cookie.isSecure());
|
||||
Assert.assertTrue(cookie.isExpired(System.nanoTime()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCookie2() throws Exception
|
||||
{
|
||||
String value = "wd=deleted; max-Age=0; path=/; domain=.domain.com; httponly; version=3";
|
||||
List<HttpCookie> cookies = HttpCookieParser.parseCookies(value);
|
||||
Assert.assertEquals(1, cookies.size());
|
||||
HttpCookie cookie = cookies.get(0);
|
||||
Assert.assertEquals("wd", cookie.getName());
|
||||
Assert.assertEquals("deleted", cookie.getValue());
|
||||
Assert.assertEquals(".domain.com", cookie.getDomain());
|
||||
Assert.assertEquals("/", cookie.getPath());
|
||||
Assert.assertTrue(cookie.isHttpOnly());
|
||||
Assert.assertEquals(3, cookie.getVersion());
|
||||
Assert.assertTrue(cookie.isExpired(System.nanoTime()));
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.client.api.CookieStore;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpCookieStoreTest
|
||||
{
|
||||
private HttpClient client = new HttpClient();
|
||||
|
||||
@Test
|
||||
public void testCookieStoredIsRetrieved() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1")));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(1, result.size());
|
||||
HttpCookie cookie = result.get(0);
|
||||
Assert.assertEquals("a", cookie.getName());
|
||||
Assert.assertEquals("1", cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieWithChildDomainIsStored() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", "child.localhost", "/")));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(1, result.size());
|
||||
HttpCookie cookie = result.get(0);
|
||||
Assert.assertEquals("a", cookie.getName());
|
||||
Assert.assertEquals("1", cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieWithParentDomainIsNotStored() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "child.localhost", 80);
|
||||
Assert.assertFalse(cookies.addCookie(destination, new HttpCookie("a", "1", "localhost", "/")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithPathIsNotRetrievedWithRootPath() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", null, "/path")));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithRootPathIsRetrievedWithPath() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", null, "/")));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/path");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(1, result.size());
|
||||
HttpCookie cookie = result.get(0);
|
||||
Assert.assertEquals("a", cookie.getName());
|
||||
Assert.assertEquals("1", cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithParentDomainIsRetrievedWithChildDomain() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination parentDestination = new HttpDestination(client, "http", "localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(parentDestination, new HttpCookie("a", "1", null, "/")));
|
||||
|
||||
Destination childDestination = new HttpDestination(client, "http", "child.localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(childDestination, new HttpCookie("b", "2", null, "/")));
|
||||
|
||||
Destination grandChildDestination = new HttpDestination(client, "http", "grand.child.localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(grandChildDestination, new HttpCookie("b", "2", null, "/")));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(grandChildDestination, "/path");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(2, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpiredCookieIsNotRetrieved() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", null, "/", 0, false, false)));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureCookieIsNotRetrieved() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", null, "/", 0, false, true)));
|
||||
|
||||
List<HttpCookie> result = cookies.getCookies(destination, "/");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpCookieTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@Test
|
||||
public void test_CookieIsStored() throws Exception
|
||||
{
|
||||
final String name = "foo";
|
||||
final String value = "bar";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
response.addCookie(new Cookie(name, value));
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
|
||||
String scheme = "http";
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
String path = "/path";
|
||||
Response response = client.GET(scheme + "://" + host + ":" + port + path).get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(200, response.status());
|
||||
|
||||
Destination destination = client.getDestination(scheme, host, port);
|
||||
List<HttpCookie> cookies = client.getCookieStore().getCookies(destination, path);
|
||||
Assert.assertNotNull(cookies);
|
||||
Assert.assertEquals(1, cookies.size());
|
||||
HttpCookie cookie = cookies.get(0);
|
||||
Assert.assertEquals(name, cookie.getName());
|
||||
Assert.assertEquals(value, cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CookieIsSent() throws Exception
|
||||
{
|
||||
final String name = "foo";
|
||||
final String value = "bar";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
Cookie[] cookies = request.getCookies();
|
||||
Assert.assertEquals(1, cookies.length);
|
||||
Cookie cookie = cookies[0];
|
||||
Assert.assertEquals(name, cookie.getName());
|
||||
Assert.assertEquals(value, cookie.getValue());
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
|
||||
String scheme = "http";
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
String path = "/path";
|
||||
Destination destination = client.getDestination(scheme, host, port);
|
||||
client.getCookieStore().addCookie(destination, new HttpCookie(name, value, null, path));
|
||||
|
||||
Response response = client.GET(scheme + "://" + host + ":" + port + path).get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(200, response.status());
|
||||
}
|
||||
}
|
@ -130,21 +130,22 @@ public class HttpDestinationTest extends AbstractHttpClientServerTest
|
||||
client.setIdleTimeout(idleTimeout);
|
||||
|
||||
HttpDestination destination = new HttpDestination(client, "http", "localhost", connector.getLocalPort());
|
||||
destination.acquire();
|
||||
|
||||
// There are no queued requests, so the newly created connection will be idle
|
||||
Connection connection1 = null;
|
||||
long start = System.nanoTime();
|
||||
while (connection1 == null && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start) < 5)
|
||||
Connection connection1 = destination.acquire();
|
||||
if (connection1 == null)
|
||||
{
|
||||
connection1 = destination.idleConnections().peek();
|
||||
TimeUnit.MILLISECONDS.sleep(50);
|
||||
// There are no queued requests, so the newly created connection will be idle
|
||||
long start = System.nanoTime();
|
||||
while (connection1 == null && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start) < 5)
|
||||
{
|
||||
connection1 = destination.idleConnections().peek();
|
||||
TimeUnit.MILLISECONDS.sleep(50);
|
||||
}
|
||||
Assert.assertNotNull(connection1);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(2 * idleTimeout);
|
||||
|
||||
connection1 = destination.idleConnections().poll();
|
||||
Assert.assertNull(connection1);
|
||||
}
|
||||
Assert.assertNotNull(connection1);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(2 * idleTimeout);
|
||||
|
||||
connection1 = destination.idleConnections().poll();
|
||||
Assert.assertNull(connection1);
|
||||
}
|
||||
}
|
||||
|
@ -18,174 +18,147 @@
|
||||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HttpCookie
|
||||
{
|
||||
private final String _name;
|
||||
private final String _value;
|
||||
private final String _comment;
|
||||
private final String _domain;
|
||||
private final int _maxAge;
|
||||
private final long _maxAge;
|
||||
private final String _path;
|
||||
private final boolean _secure;
|
||||
private final int _version;
|
||||
private final boolean _httpOnly;
|
||||
private final long _expiration;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpCookie(String name, String value)
|
||||
{
|
||||
super();
|
||||
_name = name;
|
||||
_value = value;
|
||||
_comment = null;
|
||||
_domain = null;
|
||||
_httpOnly = false;
|
||||
_maxAge = -1;
|
||||
_path = null;
|
||||
_secure = false;
|
||||
_version = 0;
|
||||
this(name, value, -1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpCookie(String name, String value, String domain, String path)
|
||||
{
|
||||
super();
|
||||
this(name, value, domain, path, -1, false, false);
|
||||
}
|
||||
|
||||
public HttpCookie(String name, String value, long maxAge)
|
||||
{
|
||||
this(name, value, null, null, maxAge, false, false);
|
||||
}
|
||||
|
||||
public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure)
|
||||
{
|
||||
this(name, value, domain, path, maxAge, httpOnly, secure, null, 0);
|
||||
}
|
||||
|
||||
public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version)
|
||||
{
|
||||
_name = name;
|
||||
_value = value;
|
||||
_comment = null;
|
||||
_domain = domain;
|
||||
_httpOnly = false;
|
||||
_maxAge = -1;
|
||||
_path = path;
|
||||
_secure = false;
|
||||
_version = 0;
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpCookie(String name, String value, int maxAge)
|
||||
{
|
||||
super();
|
||||
_name = name;
|
||||
_value = value;
|
||||
_comment = null;
|
||||
_domain = null;
|
||||
_httpOnly = false;
|
||||
_maxAge = maxAge;
|
||||
_path = null;
|
||||
_secure = false;
|
||||
_version = 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpCookie(String name, String value, String domain, String path, int maxAge, boolean httpOnly, boolean secure)
|
||||
{
|
||||
super();
|
||||
_comment = null;
|
||||
_domain = domain;
|
||||
_httpOnly = httpOnly;
|
||||
_maxAge = maxAge;
|
||||
_name = name;
|
||||
_path = path;
|
||||
_secure = secure;
|
||||
_value = value;
|
||||
_version = 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpCookie(String name, String value, String domain, String path, int maxAge, boolean httpOnly, boolean secure, String comment, int version)
|
||||
{
|
||||
super();
|
||||
_comment = comment;
|
||||
_domain = domain;
|
||||
_httpOnly = httpOnly;
|
||||
_maxAge = maxAge;
|
||||
_name = name;
|
||||
_path = path;
|
||||
_secure = secure;
|
||||
_value = value;
|
||||
_version = version;
|
||||
_expiration = maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(maxAge);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the name.
|
||||
* @return the name
|
||||
/**
|
||||
* @return the cookie name
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the value.
|
||||
* @return the value
|
||||
/**
|
||||
* @return the cookie value
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the comment.
|
||||
* @return the comment
|
||||
/**
|
||||
* @return the cookie comment
|
||||
*/
|
||||
public String getComment()
|
||||
{
|
||||
return _comment;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the domain.
|
||||
* @return the domain
|
||||
/**
|
||||
* @return the cookie domain
|
||||
*/
|
||||
public String getDomain()
|
||||
{
|
||||
return _domain;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the maxAge.
|
||||
* @return the maxAge
|
||||
/**
|
||||
* @return the cookie max age in seconds
|
||||
*/
|
||||
public int getMaxAge()
|
||||
public long getMaxAge()
|
||||
{
|
||||
return _maxAge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the path.
|
||||
* @return the path
|
||||
/**
|
||||
* @return the cookie path
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the secure.
|
||||
* @return the secure
|
||||
/**
|
||||
* @return whether the cookie is valid for secure domains
|
||||
*/
|
||||
public boolean isSecure()
|
||||
{
|
||||
return _secure;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the version.
|
||||
* @return the version
|
||||
/**
|
||||
* @return the cookie version
|
||||
*/
|
||||
public int getVersion()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the isHttpOnly.
|
||||
* @return the isHttpOnly
|
||||
/**
|
||||
* @return whether the cookie is valid for the http protocol only
|
||||
*/
|
||||
public boolean isHttpOnly()
|
||||
{
|
||||
return _httpOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeNanos the time to check for cookie expiration, in nanoseconds
|
||||
* @return whether the cookie is expired by the given time
|
||||
*/
|
||||
public boolean isExpired(long timeNanos)
|
||||
{
|
||||
return _expiration >= 0 && timeNanos >= _expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a string representation of this cookie
|
||||
*/
|
||||
public String asString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getName()).append("=").append(getValue());
|
||||
if (getDomain() != null)
|
||||
builder.append(";$Domain=").append(getDomain());
|
||||
if (getPath() != null)
|
||||
builder.append(";$Path=").append(getPath());
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user