Skip to content

Commit d8f71af

Browse files
authored
Merge commit from fork
WebClient HTTP state management improvements.
2 parents 80fc6a7 + 0e30a9a commit d8f71af

7 files changed

Lines changed: 1446 additions & 258 deletions

File tree

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
package io.vertx.ext.web.client.impl;
2+
3+
import io.netty.handler.codec.http.cookie.Cookie;
4+
import io.vertx.core.internal.net.RFC3986;
5+
import io.vertx.ext.web.client.spi.CookieStore;
6+
7+
import java.util.*;
8+
9+
public class CookieJar {
10+
11+
private final CookieStore store;
12+
13+
public CookieJar(CookieStore store) {
14+
this.store = store;
15+
}
16+
17+
public List<Cookie> cookies(boolean requestSecure, String requestDomain, String requestUri) {
18+
long now = System.currentTimeMillis();
19+
String path = extractPath(requestUri);
20+
Iterable<Cookie> cookies = store.get((Boolean)null, requestDomain, path);
21+
List<Cookie> list = new ArrayList<>();
22+
List<Cookie> expired = null;
23+
for (Cookie cookie : cookies) {
24+
StoreCookie actual = (StoreCookie) cookie;
25+
if (actual.hostOnly && !cookie.domain().equals(requestDomain)) {
26+
// Check exact matching
27+
continue;
28+
}
29+
if (cookie.isSecure() && !requestSecure) {
30+
continue;
31+
}
32+
if (actual.expiryTime != null && actual.expiryTime <= now) {
33+
if (expired == null) {
34+
expired = new ArrayList<>();
35+
}
36+
expired.add(cookie);
37+
continue;
38+
}
39+
list.add(cookie);
40+
}
41+
if (expired != null) {
42+
for (Cookie cookie : expired) {
43+
store.remove(cookie);
44+
}
45+
}
46+
Collections.sort(list, new Comparator<Cookie>() {
47+
@Override
48+
public int compare(Cookie o1, Cookie o2) {
49+
return compare((StoreCookie)o1, (StoreCookie)o2);
50+
}
51+
private int compare(StoreCookie o1, StoreCookie o2) {
52+
int cmp = o1.path().compareTo(o2.path());
53+
if (cmp == 0) {
54+
cmp = Long.compare(o2.creationTime, o1.creationTime);
55+
}
56+
return -cmp;
57+
}
58+
});
59+
return list;
60+
}
61+
62+
public void setCookie(long creationTime, String domain, String requestUri, Cookie cookie) {
63+
if (domain.isEmpty()) {
64+
throw new IllegalArgumentException("Domain must not be empty");
65+
}
66+
67+
// Compute the default-path
68+
String path = extractPath(requestUri);
69+
String defaultPath;
70+
int lastSlashIdx;
71+
if (path.isEmpty() || path.charAt(0) != '/' || path.length() == 1 || ((lastSlashIdx = path.lastIndexOf('/')) < 1)) {
72+
defaultPath = "/";
73+
} else {
74+
defaultPath = path.substring(0, lastSlashIdx);
75+
}
76+
if (cookie.path() == null) {
77+
cookie.setPath(defaultPath);
78+
}
79+
boolean hostOnly;
80+
if (cookie.domain() == null) {
81+
// Set the domain if missing, because we need to send cookies
82+
// only to the domains we received them from.
83+
cookie.setDomain(domain);
84+
hostOnly = true;
85+
} else if (cookie.domain().isEmpty()) {
86+
throw new IllegalArgumentException("Cookie domain must not be empty");
87+
} else if (domain.equals(cookie.domain()) || domain.endsWith("." + cookie.domain())) {
88+
hostOnly = false;
89+
} else {
90+
return;
91+
}
92+
93+
if (cookie.maxAge() == 0L) {
94+
store.remove(cookie);
95+
} else {
96+
97+
Long expiryTime;
98+
if (cookie.maxAge() > 0L) {
99+
expiryTime = creationTime + cookie.maxAge() * 1000;
100+
} else {
101+
expiryTime = null;
102+
}
103+
104+
// Preserve creation time if we reinsert
105+
StoreCookie prev = (StoreCookie) store.get(cookie.name(), cookie.domain(), cookie.path());
106+
if (prev != null) {
107+
creationTime = prev.creationTime;
108+
}
109+
store.put(new StoreCookie(cookie, hostOnly, creationTime, expiryTime));
110+
}
111+
}
112+
113+
static class StoreCookie implements Cookie {
114+
115+
private final Cookie actual;
116+
117+
// Metadata
118+
private final boolean hostOnly;
119+
private final long creationTime;
120+
private final Long expiryTime;
121+
122+
public StoreCookie(Cookie actual, boolean hostOnly, long creationTime, Long expiryTime) {
123+
this.actual = actual;
124+
this.hostOnly = hostOnly;
125+
this.creationTime = creationTime;
126+
this.expiryTime = expiryTime;
127+
}
128+
129+
@Override
130+
public String name() {
131+
return actual.name();
132+
}
133+
134+
@Override
135+
public String value() {
136+
return actual.value();
137+
}
138+
139+
@Override
140+
public void setValue(String value) {
141+
actual.setValue(value);
142+
}
143+
144+
@Override
145+
public boolean wrap() {
146+
return actual.wrap();
147+
}
148+
149+
@Override
150+
public void setWrap(boolean wrap) {
151+
actual.setWrap(wrap);
152+
}
153+
154+
@Override
155+
public String domain() {
156+
return actual.domain();
157+
}
158+
159+
@Override
160+
public void setDomain(String domain) {
161+
actual.setDomain(domain);
162+
}
163+
164+
@Override
165+
public String path() {
166+
return actual.path();
167+
}
168+
169+
@Override
170+
public void setPath(String path) {
171+
actual.setPath(path);
172+
}
173+
174+
@Override
175+
public long maxAge() {
176+
return actual.maxAge();
177+
}
178+
179+
@Override
180+
public void setMaxAge(long maxAge) {
181+
actual.setMaxAge(maxAge);
182+
}
183+
184+
@Override
185+
public boolean isSecure() {
186+
return actual.isSecure();
187+
}
188+
189+
@Override
190+
public void setSecure(boolean secure) {
191+
actual.setSecure(secure);
192+
}
193+
194+
@Override
195+
public boolean isHttpOnly() {
196+
return actual.isHttpOnly();
197+
}
198+
199+
@Override
200+
public void setHttpOnly(boolean httpOnly) {
201+
actual.setHttpOnly(httpOnly);
202+
}
203+
204+
@Override
205+
public int compareTo(Cookie o) {
206+
return actual.compareTo(o);
207+
}
208+
}
209+
210+
private static String extractPath(String requestUri) {
211+
212+
requestUri = RFC3986.removeDotSegments(requestUri);
213+
214+
// Remove query params if present
215+
int pos = requestUri.indexOf('?');
216+
if (pos > -1) {
217+
requestUri = requestUri.substring(0, pos);
218+
}
219+
220+
// Remove fragment identifier if present
221+
pos = requestUri.indexOf('#');
222+
if (pos > -1) {
223+
requestUri = requestUri.substring(0, pos);
224+
}
225+
226+
return requestUri;
227+
}
228+
}

0 commit comments

Comments
 (0)