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.MultiMap;
35 import org.eclipse.jetty.util.StringUtil;
36 import org.eclipse.jetty.util.UrlEncoded;
37 import org.eclipse.jetty.util.log.Log;
38 import org.eclipse.jetty.util.log.Logger;
39 import org.eclipse.jetty.websocket.api.UpgradeRequest;
40 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
41
42
43
44
45 public class ClientUpgradeRequest extends UpgradeRequest
46 {
47 private static final Logger LOG = Log.getLogger(ClientUpgradeRequest.class);
48 private static final int MAX_KEYS = -1;
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 request.append(cookie.toString());
171 needDelim = true;
172 }
173 request.append("\r\n");
174 }
175
176
177 for (String key : getHeaders().keySet())
178 {
179 if (FORBIDDEN_HEADERS.contains(key))
180 {
181 LOG.debug("Skipping forbidden header - {}",key);
182 continue;
183 }
184 request.append(key).append(": ");
185 request.append(getHeader(key));
186 request.append("\r\n");
187 }
188
189
190 request.append("\r\n");
191 return request.toString();
192 }
193
194 private final String genRandomKey()
195 {
196 byte[] bytes = new byte[16];
197 ThreadLocalRandom.current().nextBytes(bytes);
198 return new String(B64Code.encode(bytes));
199 }
200
201 public String getKey()
202 {
203 return key;
204 }
205
206 public void setCookiesFrom(CookieStore cookieStore)
207 {
208 if (cookieStore == null)
209 {
210 return;
211 }
212
213 setCookies(cookieStore.get(getRequestURI()));
214 }
215
216 @Override
217 public void setRequestURI(URI uri)
218 {
219 super.setRequestURI(uri);
220
221
222 Map<String, List<String>> pmap = new HashMap<>();
223
224 String query = uri.getQuery();
225
226 if (StringUtil.isNotBlank(query))
227 {
228 MultiMap<String> params = new MultiMap<String>();
229 UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8,MAX_KEYS);
230
231 for (String key : params.keySet())
232 {
233 List<String> values = params.getValues(key);
234 if (values == null)
235 {
236 pmap.put(key,new ArrayList<String>());
237 }
238 else
239 {
240
241 List<String> copy = new ArrayList<>();
242 copy.addAll(values);
243 pmap.put(key,copy);
244 }
245 }
246
247 super.setParameterMap(pmap);
248 }
249 }
250 }