Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-9.4.x-ewyk
This commit is contained in:
commit
01349ac935
|
@ -14,6 +14,36 @@
|
|||
<excludes>
|
||||
<exclude>**/META-INF/**</exclude>
|
||||
<exclude>*-config.jar</exclude>
|
||||
<!-- common OS detritus -->
|
||||
<exclude>**/.DS_Store</exclude>
|
||||
<exclude>**/Thumbs.db</exclude>
|
||||
<exclude>**/desktop.ini</exclude>
|
||||
<!-- common temp files -->
|
||||
<exclude>**/*~</exclude>
|
||||
<exclude>**/*.bak</exclude>
|
||||
<exclude>**/*.backup</exclude>
|
||||
<exclude>**/*.old</exclude>
|
||||
<exclude>**/*.swp</exclude>
|
||||
<exclude>**/*.debug</exclude>
|
||||
<exclude>**/*.dump</exclude>
|
||||
<exclude>**/*.log</exclude>
|
||||
<exclude>**/~*</exclude>
|
||||
<!-- common git/scm files -->
|
||||
<exclude>**/*.orig</exclude>
|
||||
<exclude>**/*.diff</exclude>
|
||||
<exclude>**/*.patch</exclude>
|
||||
<exclude>**/.gitignore</exclude>
|
||||
<!-- various editor files -->
|
||||
<exclude>**/*.iml</exclude>
|
||||
<exclude>**/*.ipr</exclude>
|
||||
<exclude>**/*.iws</exclude>
|
||||
<exclude>**/*.idea</exclude>
|
||||
<exclude>**/.classpath</exclude>
|
||||
<exclude>**/.project</exclude>
|
||||
<exclude>**/.settings</exclude>
|
||||
<!-- maven dust -->
|
||||
<exclude>**/*.versionsBackup</exclude>
|
||||
<exclude>**/*.releaseBackup</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
|
|
@ -12,6 +12,36 @@
|
|||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/target/**</exclude>
|
||||
<!-- common OS detritus -->
|
||||
<exclude>**/.DS_Store</exclude>
|
||||
<exclude>**/Thumbs.db</exclude>
|
||||
<exclude>**/desktop.ini</exclude>
|
||||
<!-- common temp files -->
|
||||
<exclude>**/*~</exclude>
|
||||
<exclude>**/*.bak</exclude>
|
||||
<exclude>**/*.backup</exclude>
|
||||
<exclude>**/*.old</exclude>
|
||||
<exclude>**/*.swp</exclude>
|
||||
<exclude>**/*.debug</exclude>
|
||||
<exclude>**/*.dump</exclude>
|
||||
<exclude>**/*.log</exclude>
|
||||
<exclude>**/~*</exclude>
|
||||
<!-- common git/scm files -->
|
||||
<exclude>**/*.orig</exclude>
|
||||
<exclude>**/*.diff</exclude>
|
||||
<exclude>**/*.patch</exclude>
|
||||
<exclude>**/.gitignore</exclude>
|
||||
<!-- various editor files -->
|
||||
<exclude>**/*.iml</exclude>
|
||||
<exclude>**/*.ipr</exclude>
|
||||
<exclude>**/*.iws</exclude>
|
||||
<exclude>**/*.idea</exclude>
|
||||
<exclude>**/.classpath</exclude>
|
||||
<exclude>**/.project</exclude>
|
||||
<exclude>**/.settings</exclude>
|
||||
<!-- maven dust -->
|
||||
<exclude>**/*.versionsBackup</exclude>
|
||||
<exclude>**/*.releaseBackup</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
|
|
@ -98,6 +98,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
public static final String EXPIRY = "expiry";
|
||||
public static final String MAXINACTIVE = "maxInactive";
|
||||
public static final String ATTRIBUTES = "attributes";
|
||||
public static final String LASTSAVED = "lastSaved";
|
||||
|
||||
public static final String KIND = "GCloudSession";
|
||||
protected String _kind = KIND;
|
||||
|
@ -107,6 +108,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
protected String _accessed = ACCESSED;
|
||||
protected String _lastAccessed = LASTACCESSED;
|
||||
protected String _lastNode = LASTNODE;
|
||||
protected String _lastSaved = LASTSAVED;
|
||||
protected String _createTime = CREATETIME;
|
||||
protected String _cookieSetTime = COOKIESETTIME;
|
||||
protected String _expiry = EXPIRY;
|
||||
|
@ -302,6 +304,23 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
_attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lastSaved
|
||||
*/
|
||||
public String getLastSaved()
|
||||
{
|
||||
return _lastSaved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastSaved the lastSaved to set
|
||||
*/
|
||||
public void setLastSaved(String lastSaved)
|
||||
{
|
||||
checkNotNull(lastSaved);
|
||||
_lastSaved = lastSaved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
@ -868,6 +887,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
.set(_model.getLastNode(),session.getLastNode())
|
||||
.set(_model.getExpiry(), session.getExpiry())
|
||||
.set(_model.getMaxInactive(), session.getMaxInactiveMs())
|
||||
.set(_model.getLastSaved(), session.getLastSaved())
|
||||
.set(_model.getAttributes(), BlobValue.newBuilder(Blob.copyFrom(baos.toByteArray())).setExcludeFromIndexes(true).build()).build();
|
||||
|
||||
|
||||
|
@ -902,6 +922,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
long createTime = entity.getLong(_model.getCreateTime());
|
||||
long cookieSet = entity.getLong(_model.getCookieSetTime());
|
||||
String lastNode = entity.getString(_model.getLastNode());
|
||||
|
||||
long lastSaved = 0;
|
||||
//for compatibility with previously saved sessions, lastSaved may not be present
|
||||
try
|
||||
{
|
||||
lastSaved = entity.getLong(_model.getLastSaved());
|
||||
}
|
||||
catch (DatastoreException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
long expiry = entity.getLong(_model.getExpiry());
|
||||
long maxInactive = entity.getLong(_model.getMaxInactive());
|
||||
Blob blob = (Blob) entity.getBlob(_model.getAttributes());
|
||||
|
@ -912,6 +943,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
session.setVhost(vhost);
|
||||
session.setCookieSet(cookieSet);
|
||||
session.setLastNode(lastNode);
|
||||
session.setLastSaved(lastSaved);
|
||||
session.setExpiry(expiry);
|
||||
try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream()))
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
/**
|
||||
* The compliance for Cookie handling.
|
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.http;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Collection of Syntax validation methods.
|
||||
* <p>
|
||||
* Use in a similar way as you would {@link java.util.Objects#requireNonNull(Object)}
|
||||
* </p>
|
||||
*/
|
||||
public final class Syntax
|
||||
{
|
||||
|
||||
/**
|
||||
* Per RFC2616: Section 2.2, a token follows these syntax rules
|
||||
* <pre>
|
||||
* token = 1*<any CHAR except CTLs or separators>
|
||||
* CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
* CTL = <any US-ASCII control character
|
||||
* (octets 0 - 31) and DEL (127)>
|
||||
* separators = "(" | ")" | "<" | ">" | "@"
|
||||
* | "," | ";" | ":" | "\" | <">
|
||||
* | "/" | "[" | "]" | "?" | "="
|
||||
* | "{" | "}" | SP | HT
|
||||
* </pre>
|
||||
*
|
||||
* @param value the value to test
|
||||
* @param msg the message to be prefixed if an {@link IllegalArgumentException} is thrown.
|
||||
* @throws IllegalArgumentException if the value is invalid per spec
|
||||
*/
|
||||
public static void requireValidRFC2616Token(String value, String msg)
|
||||
{
|
||||
Objects.requireNonNull(msg, "msg cannot be null");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int valueLen = value.length();
|
||||
if (valueLen == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueLen; i++)
|
||||
{
|
||||
char c = value.charAt(i);
|
||||
|
||||
// 0x00 - 0x1F are low order control characters
|
||||
// 0x7F is the DEL control character
|
||||
if ((c <= 0x1F) || (c == 0x7F))
|
||||
throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain control characters");
|
||||
if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@'
|
||||
|| c == ',' || c == ';' || c == ':' || c == '\\' || c == '"'
|
||||
|| c == '/' || c == '[' || c == ']' || c == '?' || c == '='
|
||||
|| c == '{' || c == '}' || c == ' ')
|
||||
{
|
||||
throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain separator character: [" + c + "]");
|
||||
}
|
||||
if (c >= 0x80)
|
||||
throw new IllegalArgumentException(msg + ": RFC2616 tokens characters restricted to US-ASCII: 0x" + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Per RFC6265, Cookie.value follows these syntax rules
|
||||
* <pre>
|
||||
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
|
||||
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
||||
* ; US-ASCII characters excluding CTLs,
|
||||
* ; whitespace DQUOTE, comma, semicolon,
|
||||
* ; and backslash
|
||||
* </pre>
|
||||
*
|
||||
* @param value the value to test
|
||||
* @throws IllegalArgumentException if the value is invalid per spec
|
||||
*/
|
||||
public static void requireValidRFC6265CookieValue(String value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int valueLen = value.length();
|
||||
if (valueLen == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
if (value.charAt(0) == '"')
|
||||
{
|
||||
// Has starting DQUOTE
|
||||
if (valueLen <= 1 || (value.charAt(valueLen - 1) != '"'))
|
||||
{
|
||||
throw new IllegalArgumentException("RFC6265 Cookie values must have balanced DQUOTES (if used)");
|
||||
}
|
||||
|
||||
// adjust search range to exclude DQUOTES
|
||||
i++;
|
||||
valueLen--;
|
||||
}
|
||||
for (; i < valueLen; i++)
|
||||
{
|
||||
char c = value.charAt(i);
|
||||
|
||||
// 0x00 - 0x1F are low order control characters
|
||||
// 0x7F is the DEL control character
|
||||
if ((c <= 0x1F) || (c == 0x7F))
|
||||
throw new IllegalArgumentException("RFC6265 Cookie values may not contain control characters");
|
||||
if ((c == ' ' /* 0x20 */) ||
|
||||
(c == '"' /* 0x2C */) ||
|
||||
(c == ';' /* 0x3B */) ||
|
||||
(c == '\\' /* 0x5C */))
|
||||
{
|
||||
throw new IllegalArgumentException("RFC6265 Cookie values may not contain character: [" + c + "]");
|
||||
}
|
||||
if (c >= 0x80)
|
||||
throw new IllegalArgumentException("RFC6265 Cookie values characters restricted to US-ASCII: 0x" + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.http;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SyntaxTest
|
||||
{
|
||||
@Test
|
||||
public void testRequireValidRFC2616Token_Good()
|
||||
{
|
||||
String tokens[] = {
|
||||
"name",
|
||||
"",
|
||||
null,
|
||||
"n.a.m.e",
|
||||
"na-me",
|
||||
"+name",
|
||||
"na*me",
|
||||
"na$me",
|
||||
"#name"
|
||||
};
|
||||
|
||||
for (String token : tokens)
|
||||
{
|
||||
Syntax.requireValidRFC2616Token(token, "Test Based");
|
||||
// No exception should occur here
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidRFC2616Token_Bad()
|
||||
{
|
||||
String tokens[] = {
|
||||
"\"name\"",
|
||||
"name\t",
|
||||
"na me",
|
||||
"name\u0082",
|
||||
"na\tme",
|
||||
"na;me",
|
||||
"{name}",
|
||||
"[name]",
|
||||
"\""
|
||||
};
|
||||
|
||||
for (String token : tokens)
|
||||
{
|
||||
try
|
||||
{
|
||||
Syntax.requireValidRFC2616Token(token, "Test Based");
|
||||
fail("RFC2616 Token [" + token + "] Should have thrown " + IllegalArgumentException.class.getName());
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
assertThat("Testing Bad RFC2616 Token [" + token + "]", e.getMessage(),
|
||||
allOf(containsString("Test Based"),
|
||||
containsString("RFC2616")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidRFC6265CookieValue_Good()
|
||||
{
|
||||
String values[] = {
|
||||
"value",
|
||||
"",
|
||||
null,
|
||||
"val=ue",
|
||||
"val-ue",
|
||||
"\"value\"",
|
||||
"val/ue",
|
||||
"v.a.l.u.e"
|
||||
};
|
||||
|
||||
for (String value : values)
|
||||
{
|
||||
Syntax.requireValidRFC6265CookieValue(value);
|
||||
// No exception should occur here
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidRFC6265CookieValue_Bad()
|
||||
{
|
||||
String values[] = {
|
||||
"va\tlue",
|
||||
"\t",
|
||||
"value\u0000",
|
||||
"val\u0082ue",
|
||||
"va lue",
|
||||
"va;lue",
|
||||
"\"value",
|
||||
"value\"",
|
||||
"val\\ue",
|
||||
"val\"ue",
|
||||
"\""
|
||||
};
|
||||
|
||||
for (String value : values)
|
||||
{
|
||||
try
|
||||
{
|
||||
Syntax.requireValidRFC6265CookieValue(value);
|
||||
fail("RFC6265 Cookie Value [" + value + "] Should have thrown " + IllegalArgumentException.class.getName());
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
assertThat("Testing Bad RFC6265 Cookie Value [" + value + "]", e.getMessage(), containsString("RFC6265"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -117,6 +117,12 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
*/
|
||||
public final static String __VERSION = __METADATA + ".version";
|
||||
|
||||
|
||||
public final static String __LASTSAVED = __METADATA + ".lastSaved";
|
||||
|
||||
|
||||
public final static String __LASTNODE = __METADATA + ".lastNode";
|
||||
|
||||
/**
|
||||
* Last access time of session
|
||||
*/
|
||||
|
@ -202,8 +208,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
if (valid == null || !valid)
|
||||
return;
|
||||
|
||||
|
||||
Object version = getNestedValue(sessionDocument, getContextSubfield(__VERSION));
|
||||
Long lastSaved = (Long)getNestedValue(sessionDocument, getContextSubfield(__LASTSAVED));
|
||||
String lastNode = (String)getNestedValue(sessionDocument, getContextSubfield(__LASTNODE));
|
||||
|
||||
Long created = (Long)sessionDocument.get(__CREATED);
|
||||
Long accessed = (Long)sessionDocument.get(__ACCESSED);
|
||||
|
@ -228,6 +235,8 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
data.setExpiry(expiry);
|
||||
data.setContextPath(_context.getCanonicalContextPath());
|
||||
data.setVhost(_context.getVhost());
|
||||
data.setLastSaved(lastSaved);
|
||||
data.setLastNode(lastNode);
|
||||
|
||||
HashMap<String, Object> attributes = new HashMap<>();
|
||||
for (String name : sessionSubDocumentForContext.keySet())
|
||||
|
@ -449,12 +458,16 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
sets.put(__CREATED,nsqd.getCreated());
|
||||
sets.put(__VALID,true);
|
||||
sets.put(getContextSubfield(__VERSION),version);
|
||||
sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved());
|
||||
sets.put(getContextSubfield(__LASTNODE), data.getLastNode());
|
||||
sets.put(__MAX_IDLE, nsqd.getMaxInactiveMs());
|
||||
sets.put(__EXPIRY, nsqd.getExpiry());
|
||||
nsqd.setVersion(version);
|
||||
}
|
||||
else
|
||||
{
|
||||
sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved());
|
||||
sets.put(getContextSubfield(__LASTNODE), data.getLastNode());
|
||||
version = new Long(((Number)version).longValue() + 1);
|
||||
nsqd.setVersion(version);
|
||||
update.put("$inc",_version_1);
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
<Set name="maxErrorDispatches"><Property name="jetty.httpConfig.maxErrorDispatches" default="10"/></Set>
|
||||
<Set name="blockingTimeout"><Property name="jetty.httpConfig.blockingTimeout" default="-1"/></Set>
|
||||
<Set name="persistentConnectionsEnabled"><Property name="jetty.httpConfig.persistentConnectionsEnabled" default="true"/></Set>
|
||||
<Set name="cookieCompliance"><Call class="org.eclipse.jetty.server.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.cookieCompliance" default="RFC6265"/></Arg></Call></Set>
|
||||
<Set name="cookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.cookieCompliance" default="RFC6265"/></Arg></Call></Set>
|
||||
</New>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.eclipse.jetty.http.CookieCompliance;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
|
|
|
@ -35,6 +35,7 @@ import javax.servlet.http.Cookie;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.eclipse.jetty.http.CookieCompliance;
|
||||
import org.eclipse.jetty.http.DateGenerator;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
|
@ -50,6 +51,7 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.Syntax;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
|
@ -172,6 +174,11 @@ public class Response implements HttpServletResponse
|
|||
|
||||
public void addCookie(HttpCookie cookie)
|
||||
{
|
||||
if (StringUtil.isBlank(cookie.getName()))
|
||||
{
|
||||
throw new IllegalArgumentException("Cookie.name cannot be blank/null");
|
||||
}
|
||||
|
||||
if (getHttpChannel().getHttpConfiguration().isCookieCompliance(CookieCompliance.RFC2965))
|
||||
addSetRFC2965Cookie(
|
||||
cookie.getName(),
|
||||
|
@ -212,6 +219,11 @@ public class Response implements HttpServletResponse
|
|||
}
|
||||
}
|
||||
|
||||
if (StringUtil.isBlank(cookie.getName()))
|
||||
{
|
||||
throw new IllegalArgumentException("Cookie.name cannot be blank/null");
|
||||
}
|
||||
|
||||
if (getHttpChannel().getHttpConfiguration().isCookieCompliance(CookieCompliance.RFC2965))
|
||||
addSetRFC2965Cookie(cookie.getName(),
|
||||
cookie.getValue(),
|
||||
|
@ -259,10 +271,9 @@ public class Response implements HttpServletResponse
|
|||
|
||||
// Name is checked for legality by servlet spec, but can also be passed directly so check again for quoting
|
||||
// Per RFC6265, Cookie.name follows RFC2616 Section 2.2 token rules
|
||||
if(isQuoteNeededForCookie(name))
|
||||
throw new IllegalArgumentException("Cookie name not RFC6265 compliant");
|
||||
Syntax.requireValidRFC2616Token(name, "RFC6265 Cookie name");
|
||||
// Ensure that Per RFC6265, Cookie.value follows syntax rules
|
||||
assertRFC6265CookieValue(value);
|
||||
Syntax.requireValidRFC6265CookieValue(value);
|
||||
|
||||
// Format value and params
|
||||
StringBuilder buf = __cookieBuilder.get();
|
||||
|
@ -306,64 +317,6 @@ public class Response implements HttpServletResponse
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Per RFC6265, Cookie.value follows these syntax rules
|
||||
* <pre>
|
||||
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
|
||||
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
||||
* ; US-ASCII characters excluding CTLs,
|
||||
* ; whitespace DQUOTE, comma, semicolon,
|
||||
* ; and backslash
|
||||
* </pre>
|
||||
* @param value the value to test
|
||||
* @throws IllegalArgumentException if the value is invalid per spec
|
||||
*/
|
||||
public static void assertRFC6265CookieValue(String value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int valueLen = value.length();
|
||||
if (valueLen == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
if (value.charAt(0) == '"')
|
||||
{
|
||||
// Has starting DQUOTE
|
||||
if (valueLen <= 1 || (value.charAt(valueLen - 1) != '"'))
|
||||
{
|
||||
throw new IllegalArgumentException("RFC6265 Cookie value must have balanced DQUOTES (if used)");
|
||||
}
|
||||
|
||||
// adjust search range to exclude DQUOTES
|
||||
i++;
|
||||
valueLen--;
|
||||
}
|
||||
for(; i<valueLen; i++)
|
||||
{
|
||||
char c = value.charAt(i);
|
||||
|
||||
// 0x00 - 0x1F are low order control characters
|
||||
// 0x7F is the DEL control character
|
||||
if ((c <= 0x1F) || (c == 0x7F))
|
||||
throw new IllegalArgumentException("Control characters not allowed in RFC6265 Cookie value");
|
||||
if ((c == ' ' /* 0x20 */) ||
|
||||
(c == '"' /* 0x2C */) ||
|
||||
(c == ';' /* 0x3B */) ||
|
||||
(c == '\\' /* 0x5C */))
|
||||
{
|
||||
throw new IllegalArgumentException("RFC6265 Cookie value may not contain character: [" + c + "]");
|
||||
}
|
||||
if (c >= 0x80)
|
||||
throw new IllegalArgumentException("RFC6265 Cookie value characters restricted to US-ASCII range: 0x" + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a set cookie value
|
||||
*
|
||||
|
|
|
@ -196,6 +196,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
try (FileInputStream in = new FileInputStream(file))
|
||||
{
|
||||
SessionData data = load(in);
|
||||
data.setLastSaved(file.lastModified());
|
||||
//delete restored file
|
||||
file.delete();
|
||||
reference.set(data);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
@ -29,19 +31,18 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -56,7 +57,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.eclipse.jetty.http.HttpCompliance;
|
||||
import org.eclipse.jetty.http.CookieCompliance;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -69,8 +70,8 @@ import org.eclipse.jetty.io.RuntimeIOException;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
|
||||
import org.eclipse.jetty.server.session.DefaultSessionCache;
|
||||
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
|
||||
import org.eclipse.jetty.server.session.NullSessionDataStore;
|
||||
import org.eclipse.jetty.server.session.Session;
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
|
@ -178,6 +179,7 @@ public class ResponseTest
|
|||
_server.join();
|
||||
}
|
||||
|
||||
@SuppressWarnings("InjectedReferences") // to allow for invalid encoding strings in this testcase
|
||||
@Test
|
||||
public void testContentType() throws Exception
|
||||
{
|
||||
|
@ -1185,15 +1187,31 @@ public class ResponseTest
|
|||
assertEquals("everything=value;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
fields.clear();
|
||||
String badNameExamples[] = {
|
||||
"\"name\"",
|
||||
"name\t",
|
||||
"na me",
|
||||
"name\u0082",
|
||||
"na\tme",
|
||||
"na;me",
|
||||
"{name}",
|
||||
"[name]",
|
||||
"\""
|
||||
};
|
||||
|
||||
for (String badNameExample : badNameExamples)
|
||||
{
|
||||
fields.clear();
|
||||
try
|
||||
{
|
||||
response.addSetRFC6265Cookie("ev erything","va lue","do main","pa th",1,true,true);
|
||||
response.addSetRFC6265Cookie(badNameExample, "value", null, "/", 1, true, true);
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
assertThat(ex.getMessage(),Matchers.containsString("RFC6265"));
|
||||
// System.err.printf("%s: %s%n", ex.getClass().getSimpleName(), ex.getMessage());
|
||||
assertThat("Testing bad name: [" + badNameExample + "]", ex.getMessage(),
|
||||
allOf(containsString("RFC6265"), containsString("RFC2616")));
|
||||
}
|
||||
}
|
||||
|
||||
String badValueExamples[] = {
|
||||
|
@ -1219,11 +1237,27 @@ public class ResponseTest
|
|||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
// System.err.printf("%s: %s%n", ex.getClass().getSimpleName(), ex.getMessage());
|
||||
assertThat("Testing bad value [" + badValueExample + "]", ex.getMessage(), Matchers.containsString("RFC6265"));
|
||||
}
|
||||
}
|
||||
|
||||
String goodNameExamples[] = {
|
||||
"name",
|
||||
"n.a.m.e",
|
||||
"na-me",
|
||||
"+name",
|
||||
"na*me",
|
||||
"na$me",
|
||||
"#name"
|
||||
};
|
||||
|
||||
for (String goodNameExample : goodNameExamples)
|
||||
{
|
||||
fields.clear();
|
||||
response.addSetRFC6265Cookie(goodNameExample, "value", null, "/", 1, true, true);
|
||||
// should not throw an exception
|
||||
}
|
||||
|
||||
String goodValueExamples[] = {
|
||||
"value",
|
||||
|
@ -1239,6 +1273,7 @@ public class ResponseTest
|
|||
{
|
||||
fields.clear();
|
||||
response.addSetRFC6265Cookie("name", goodValueExample, null, "/", 1, true, true);
|
||||
// should not throw an exception
|
||||
}
|
||||
|
||||
fields.clear();
|
||||
|
|
Loading…
Reference in New Issue