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