1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.client;
20
21 import java.net.CookieStore;
22 import java.net.HttpCookie;
23 import java.net.URI;
24 import java.nio.charset.StandardCharsets;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.TreeSet;
31 import java.util.concurrent.ThreadLocalRandom;
32
33 import org.eclipse.jetty.util.B64Code;
34 import org.eclipse.jetty.util.LazyList;
35 import org.eclipse.jetty.util.MultiMap;
36 import org.eclipse.jetty.util.StringUtil;
37 import org.eclipse.jetty.util.UrlEncoded;
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40 import org.eclipse.jetty.websocket.api.UpgradeRequest;
41 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
42
43
44
45
46 public class ClientUpgradeRequest extends UpgradeRequest
47 {
48 private static final Logger LOG = Log.getLogger(ClientUpgradeRequest.class);
49 private static final int MAX_KEYS = -1;
50 private static final Set<String> FORBIDDEN_HEADERS;
51
52 static
53 {
54
55 FORBIDDEN_HEADERS = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
56
57 FORBIDDEN_HEADERS.add("cookie");
58
59 FORBIDDEN_HEADERS.add("upgrade");
60 FORBIDDEN_HEADERS.add("host");
61 FORBIDDEN_HEADERS.add("connection");
62 FORBIDDEN_HEADERS.add("sec-websocket-key");
63 FORBIDDEN_HEADERS.add("sec-websocket-extensions");
64 FORBIDDEN_HEADERS.add("sec-websocket-accept");
65 FORBIDDEN_HEADERS.add("sec-websocket-protocol");
66 FORBIDDEN_HEADERS.add("sec-websocket-version");
67 FORBIDDEN_HEADERS.add("pragma");
68 FORBIDDEN_HEADERS.add("cache-control");
69 }
70
71 private final String key;
72
73 public ClientUpgradeRequest()
74 {
75 super();
76 this.key = genRandomKey();
77 }
78
79 protected ClientUpgradeRequest(URI requestURI)
80 {
81 super(requestURI);
82 this.key = genRandomKey();
83 }
84
85 public String generate()
86 {
87 URI uri = getRequestURI();
88
89 StringBuilder request = new StringBuilder(512);
90 request.append("GET ");
91 if (StringUtil.isBlank(uri.getPath()))
92 {
93 request.append("/");
94 }
95 else
96 {
97 request.append(uri.getPath());
98 }
99 if (StringUtil.isNotBlank(uri.getRawQuery()))
100 {
101 request.append("?").append(uri.getRawQuery());
102 }
103 request.append(" HTTP/1.1\r\n");
104
105 request.append("Host: ").append(uri.getHost());
106 if (uri.getPort() > 0)
107 {
108 request.append(':').append(uri.getPort());
109 }
110 request.append("\r\n");
111
112
113 request.append("Upgrade: websocket\r\n");
114 request.append("Connection: Upgrade\r\n");
115 request.append("Sec-WebSocket-Key: ").append(key).append("\r\n");
116 request.append("Sec-WebSocket-Version: 13\r\n");
117
118
119
120
121
122 request.append("Pragma: no-cache\r\n");
123 request.append("Cache-Control: no-cache\r\n");
124
125
126 if (!getExtensions().isEmpty())
127 {
128 request.append("Sec-WebSocket-Extensions: ");
129 boolean needDelim = false;
130 for (ExtensionConfig ext : getExtensions())
131 {
132 if (needDelim)
133 {
134 request.append(", ");
135 }
136 request.append(ext.getParameterizedName());
137 needDelim = true;
138 }
139 request.append("\r\n");
140 }
141
142
143 if (!getSubProtocols().isEmpty())
144 {
145 request.append("Sec-WebSocket-Protocol: ");
146 boolean needDelim = false;
147 for (String protocol : getSubProtocols())
148 {
149 if (needDelim)
150 {
151 request.append(", ");
152 }
153 request.append(protocol);
154 needDelim = true;
155 }
156 request.append("\r\n");
157 }
158
159
160 List<HttpCookie> cookies = getCookies();
161 if ((cookies != null) && (cookies.size() > 0))
162 {
163 request.append("Cookie: ");
164 boolean needDelim = false;
165 for (HttpCookie cookie : cookies)
166 {
167 if (needDelim)
168 {
169 request.append("; ");
170 }
171 request.append(cookie.toString());
172 needDelim = true;
173 }
174 request.append("\r\n");
175 }
176
177
178 for (String key : getHeaders().keySet())
179 {
180 if (FORBIDDEN_HEADERS.contains(key))
181 {
182 LOG.debug("Skipping forbidden header - {}",key);
183 continue;
184 }
185 request.append(key).append(": ");
186 request.append(getHeader(key));
187 request.append("\r\n");
188 }
189
190
191 request.append("\r\n");
192 return request.toString();
193 }
194
195 private final String genRandomKey()
196 {
197 byte[] bytes = new byte[16];
198 ThreadLocalRandom.current().nextBytes(bytes);
199 return new String(B64Code.encode(bytes));
200 }
201
202 public String getKey()
203 {
204 return key;
205 }
206
207 public void setCookiesFrom(CookieStore cookieStore)
208 {
209 if (cookieStore == null)
210 {
211 return;
212 }
213
214 List<HttpCookie> existing = getCookies();
215 List<HttpCookie> extra = cookieStore.get(getRequestURI());
216
217 List<HttpCookie> cookies = new ArrayList<>();
218 if (LazyList.hasEntry(existing))
219 {
220 cookies.addAll(existing);
221 }
222 if (LazyList.hasEntry(extra))
223 {
224 cookies.addAll(extra);
225 }
226 setCookies(cookies);
227 }
228
229 @Override
230 public void setRequestURI(URI uri)
231 {
232 super.setRequestURI(uri);
233
234
235 Map<String, List<String>> pmap = new HashMap<>();
236
237 String query = uri.getQuery();
238
239 if (StringUtil.isNotBlank(query))
240 {
241 MultiMap<String> params = new MultiMap<String>();
242 UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8,MAX_KEYS);
243
244 for (String key : params.keySet())
245 {
246 List<String> values = params.getValues(key);
247 if (values == null)
248 {
249 pmap.put(key,new ArrayList<String>());
250 }
251 else
252 {
253
254 List<String> copy = new ArrayList<>();
255 copy.addAll(values);
256 pmap.put(key,copy);
257 }
258 }
259
260 super.setParameterMap(pmap);
261 }
262 }
263 }