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