| // |
| // ======================================================================== |
| // Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.websocket.client; |
| |
| import java.net.CookieStore; |
| import java.net.URI; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| import java.util.concurrent.ThreadLocalRandom; |
| |
| import org.eclipse.jetty.client.HttpClient; |
| import org.eclipse.jetty.http.HttpField; |
| import org.eclipse.jetty.http.HttpFields; |
| import org.eclipse.jetty.util.B64Code; |
| import org.eclipse.jetty.util.MultiMap; |
| import org.eclipse.jetty.util.StringUtil; |
| import org.eclipse.jetty.util.UrlEncoded; |
| import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; |
| import org.eclipse.jetty.websocket.common.UpgradeRequestAdapter; |
| |
| /** |
| * Allowing a generate from a UpgradeRequest |
| */ |
| public class ClientUpgradeRequest extends UpgradeRequestAdapter |
| { |
| private static final Set<String> FORBIDDEN_HEADERS; |
| |
| static |
| { |
| // Headers not allowed to be set in ClientUpgradeRequest.headers. |
| FORBIDDEN_HEADERS = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); |
| // Cookies are handled explicitly, avoid to add them twice. |
| FORBIDDEN_HEADERS.add("cookie"); |
| // Headers that cannot be set by applications. |
| FORBIDDEN_HEADERS.add("upgrade"); |
| FORBIDDEN_HEADERS.add("host"); |
| FORBIDDEN_HEADERS.add("connection"); |
| FORBIDDEN_HEADERS.add("sec-websocket-key"); |
| FORBIDDEN_HEADERS.add("sec-websocket-extensions"); |
| FORBIDDEN_HEADERS.add("sec-websocket-accept"); |
| FORBIDDEN_HEADERS.add("sec-websocket-protocol"); |
| FORBIDDEN_HEADERS.add("sec-websocket-version"); |
| FORBIDDEN_HEADERS.add("pragma"); |
| FORBIDDEN_HEADERS.add("cache-control"); |
| } |
| |
| private final String key; |
| private Object localEndpoint; |
| |
| public ClientUpgradeRequest() |
| { |
| super(); |
| this.key = genRandomKey(); |
| } |
| |
| protected ClientUpgradeRequest(URI requestURI) |
| { |
| super(requestURI); |
| this.key = genRandomKey(); |
| } |
| |
| public ClientUpgradeRequest(WebSocketUpgradeRequest wsRequest) |
| { |
| this(wsRequest.getURI()); |
| // cookies |
| this.setCookies(wsRequest.getCookies()); |
| // headers |
| Map<String, List<String>> headers = new HashMap<>(); |
| HttpFields fields = wsRequest.getHeaders(); |
| for (HttpField field : fields) |
| { |
| String key = field.getName(); |
| List<String> values = headers.get(key); |
| if (values == null) |
| { |
| values = new ArrayList<>(); |
| } |
| values.addAll(Arrays.asList(field.getValues())); |
| headers.put(key,values); |
| // sub protocols |
| if(key.equalsIgnoreCase("Sec-WebSocket-Protocol")) |
| { |
| for(String subProtocol: field.getValue().split(",")) |
| { |
| setSubProtocols(subProtocol); |
| } |
| } |
| // extensions |
| if(key.equalsIgnoreCase("Sec-WebSocket-Extensions")) |
| { |
| for(ExtensionConfig ext: ExtensionConfig.parseList(field.getValues())) |
| { |
| addExtensions(ext); |
| } |
| } |
| } |
| super.setHeaders(headers); |
| // sessions |
| setHttpVersion(wsRequest.getVersion().toString()); |
| setMethod(wsRequest.getMethod()); |
| } |
| |
| private final String genRandomKey() |
| { |
| byte[] bytes = new byte[16]; |
| ThreadLocalRandom.current().nextBytes(bytes); |
| return new String(B64Code.encode(bytes)); |
| } |
| |
| public String getKey() |
| { |
| return key; |
| } |
| |
| /** |
| * @param cookieStore the cookie store to use |
| * @deprecated use either {@link WebSocketClient#setCookieStore(CookieStore)} or {@link HttpClient#setCookieStore(CookieStore)} instead |
| */ |
| @Deprecated |
| public void setCookiesFrom(CookieStore cookieStore) |
| { |
| throw new UnsupportedOperationException("Request specific CookieStore no longer supported"); |
| } |
| |
| @Override |
| public void setRequestURI(URI uri) |
| { |
| super.setRequestURI(uri); |
| |
| // parse parameter map |
| Map<String, List<String>> pmap = new HashMap<>(); |
| |
| String query = uri.getQuery(); |
| |
| if (StringUtil.isNotBlank(query)) |
| { |
| MultiMap<String> params = new MultiMap<String>(); |
| UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8); |
| |
| for (String key : params.keySet()) |
| { |
| List<String> values = params.getValues(key); |
| if (values == null) |
| { |
| pmap.put(key,new ArrayList<String>()); |
| } |
| else |
| { |
| // break link to original |
| List<String> copy = new ArrayList<>(); |
| copy.addAll(values); |
| pmap.put(key,copy); |
| } |
| } |
| |
| super.setParameterMap(pmap); |
| } |
| } |
| |
| public void setLocalEndpoint(Object websocket) |
| { |
| this.localEndpoint = websocket; |
| } |
| |
| public Object getLocalEndpoint() |
| { |
| return localEndpoint; |
| } |
| } |