-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
CookieCompliance.java
198 lines (171 loc) · 6.28 KB
/
CookieCompliance.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Collections.unmodifiableSet;
import static java.util.EnumSet.allOf;
import static java.util.EnumSet.copyOf;
import static java.util.EnumSet.noneOf;
/**
* The compliance mode for Cookie handling.
*/
public class CookieCompliance implements ComplianceViolation.Mode
{
private static final Logger LOG = LoggerFactory.getLogger(CookieCompliance.class);
public enum Violation implements ComplianceViolation
{
/**
* Allow a comma as part of a cookie value
*/
COMMA_NOT_VALID_OCTET("https://tools.ietf.org/html/rfc6265#section-4.1.1", "Comma not valid as cookie-octet or separator"),
/**
* Allow cookies to have $ prefixed reserved parameters
*/
RESERVED_NAMES_NOT_DOLLAR_PREFIXED("https://tools.ietf.org/html/rfc6265#section-4.1.1", "Reserved names no longer use '$' prefix");
private final String url;
private final String description;
Violation(String url, String description)
{
this.url = url;
this.description = description;
}
@Override
public String getName()
{
return name();
}
@Override
public String getURL()
{
return url;
}
@Override
public String getDescription()
{
return description;
}
}
/**
* A CookieCompliance mode that enforces <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a> compliance.
*/
public static final CookieCompliance RFC6265 = new CookieCompliance("RFC6265", noneOf(Violation.class));
/**
* A CookieCompliance mode that allows <a href="https://tools.ietf.org/html/rfc2965">RFC 2965</a> compliance.
*/
public static final CookieCompliance RFC2965 = new CookieCompliance("RFC2965", allOf(Violation.class));
private static final List<CookieCompliance> KNOWN_MODES = Arrays.asList(RFC6265, RFC2965);
private static final AtomicInteger __custom = new AtomicInteger();
public static CookieCompliance valueOf(String name)
{
for (CookieCompliance compliance : KNOWN_MODES)
{
if (compliance.getName().equals(name))
return compliance;
}
return null;
}
/**
* Create compliance set from string.
* <p>
* Format: <BASE>[,[-]<violation>]...
* </p>
* <p>BASE is one of:</p>
* <dl>
* <dt>0</dt><dd>No {@link CookieCompliance.Violation}s</dd>
* <dt>*</dt><dd>All {@link CookieCompliance.Violation}s</dd>
* <dt><name></dt><dd>The name of a static instance of CookieCompliance (e.g. {@link CookieCompliance#RFC6265}).
* </dl>
* <p>
* The remainder of the list can contain then names of {@link CookieCompliance.Violation}s to include them in the mode, or prefixed
* with a '-' to exclude them from the mode. Examples are:
* </p>
* <dl>
* <dt>{@code 0,RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dt><dd>Only allow {@link CookieCompliance.Violation#RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dd>
* <dt>{@code *,-RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dt><dd>Allow all violations, except {@link CookieCompliance.Violation#RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dd>
* <dt>{@code RFC2965,RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dt><dd>Same as RFC2965, but allows {@link CookieCompliance.Violation#RESERVED_NAMES_NOT_DOLLAR_PREFIXED}</dd>
* </dl>
*
* @param spec A string describing the compliance
* @return the compliance from the string spec
*/
public static CookieCompliance from(String spec)
{
Set<Violation> violations;
String[] elements = spec.split("\\s*,\\s*");
switch (elements[0])
{
case "0":
violations = noneOf(Violation.class);
break;
case "*":
violations = allOf(Violation.class);
break;
default:
{
CookieCompliance mode = valueOf(elements[0]);
violations = (mode == null) ? noneOf(Violation.class) : copyOf(mode.getAllowed());
break;
}
}
for (int i = 1; i < elements.length; i++)
{
String element = elements[i];
boolean exclude = element.startsWith("-");
if (exclude)
element = element.substring(1);
Violation section = Violation.valueOf(element);
if (exclude)
violations.remove(section);
else
violations.add(section);
}
CookieCompliance compliance = new CookieCompliance("CUSTOM" + __custom.getAndIncrement(), violations);
if (LOG.isDebugEnabled())
LOG.debug("CookieCompliance from {}->{}", spec, compliance);
return compliance;
}
private final String _name;
private final Set<Violation> _violations;
private CookieCompliance(String name, Set<Violation> violations)
{
_name = name;
_violations = unmodifiableSet(copyOf(Objects.requireNonNull(violations)));
}
@Override
public boolean allows(ComplianceViolation violation)
{
return _violations.contains(violation);
}
@Override
public String getName()
{
return _name;
}
@Override
public Set<Violation> getKnown()
{
return EnumSet.allOf(Violation.class);
}
@Override
public Set<Violation> getAllowed()
{
return _violations;
}
}