jdk/src/java.httpclient/share/classes/java/net/http/WSBuilder.java
author prappo
Mon, 09 May 2016 23:33:09 +0100
changeset 37874 02589df0999a
child 39133 b5641ce64cf7
permissions -rw-r--r--
8087113: Websocket API and implementation Reviewed-by: chegar
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
37874
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     1
/*
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     2
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     4
 *
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    10
 *
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    15
 * accompanied this code).
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    16
 *
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    20
 *
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    23
 * questions.
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    24
 */
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    25
package java.net.http;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    26
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    27
import java.net.URI;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    28
import java.util.ArrayList;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    29
import java.util.Collection;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    30
import java.util.Collections;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    31
import java.util.LinkedHashMap;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    32
import java.util.LinkedHashSet;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    33
import java.util.LinkedList;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    34
import java.util.List;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    35
import java.util.Map;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    36
import java.util.Set;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    37
import java.util.TreeSet;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    38
import java.util.concurrent.CompletableFuture;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    39
import java.util.concurrent.TimeUnit;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    40
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    41
import static java.lang.String.format;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    42
import static java.util.Objects.requireNonNull;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    43
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    44
final class WSBuilder implements WebSocket.Builder {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    45
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    46
    private static final Set<String> FORBIDDEN_HEADERS =
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    47
            new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    48
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    49
    static {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    50
        List<String> headers = List.of("Connection", "Upgrade",
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    51
                "Sec-WebSocket-Accept", "Sec-WebSocket-Extensions",
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    52
                "Sec-WebSocket-Key", "Sec-WebSocket-Protocol",
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    53
                "Sec-WebSocket-Version");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    54
        FORBIDDEN_HEADERS.addAll(headers);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    55
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    56
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    57
    private final URI uri;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    58
    private final HttpClient client;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    59
    private final LinkedHashMap<String, List<String>> headers = new LinkedHashMap<>();
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    60
    private final WebSocket.Listener listener;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    61
    private Collection<String> subprotocols = Collections.emptyList();
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    62
    private long timeout;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    63
    private TimeUnit timeUnit;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    64
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    65
    WSBuilder(URI uri, HttpClient client, WebSocket.Listener listener) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    66
        checkURI(requireNonNull(uri, "uri"));
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    67
        requireNonNull(client, "client");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    68
        requireNonNull(listener, "listener");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    69
        this.uri = uri;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    70
        this.listener = listener;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    71
        this.client = client;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    72
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    73
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    74
    @Override
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    75
    public WebSocket.Builder header(String name, String value) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    76
        requireNonNull(name, "name");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    77
        requireNonNull(value, "value");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    78
        if (FORBIDDEN_HEADERS.contains(name)) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    79
            throw new IllegalArgumentException(
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    80
                    format("Header '%s' is used in the WebSocket Protocol", name));
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    81
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    82
        List<String> values = headers.computeIfAbsent(name, n -> new LinkedList<>());
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    83
        values.add(value);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    84
        return this;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    85
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    86
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    87
    @Override
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    88
    public WebSocket.Builder subprotocols(String mostPreferred, String... lesserPreferred) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    89
        requireNonNull(mostPreferred, "mostPreferred");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    90
        requireNonNull(lesserPreferred, "lesserPreferred");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    91
        this.subprotocols = checkSubprotocols(mostPreferred, lesserPreferred);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    92
        return this;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    93
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    94
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    95
    @Override
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    96
    public WebSocket.Builder connectTimeout(long timeout, TimeUnit unit) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    97
        if (timeout < 0) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    98
            throw new IllegalArgumentException("Negative timeout: " + timeout);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
    99
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   100
        requireNonNull(unit, "unit");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   101
        this.timeout = timeout;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   102
        this.timeUnit = unit;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   103
        return this;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   104
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   105
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   106
    @Override
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   107
    public CompletableFuture<WebSocket> buildAsync() {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   108
        return WS.newInstanceAsync(this);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   109
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   110
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   111
    private static URI checkURI(URI uri) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   112
        String s = uri.getScheme();
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   113
        if (!("ws".equalsIgnoreCase(s) || "wss".equalsIgnoreCase(s))) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   114
            throw new IllegalArgumentException
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   115
                    ("URI scheme not ws or wss (RFC 6455 3.): " + s);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   116
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   117
        String fragment = uri.getFragment();
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   118
        if (fragment != null) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   119
            throw new IllegalArgumentException(format
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   120
                    ("Fragment not allowed in a WebSocket URI (RFC 6455 3.): '%s'",
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   121
                            fragment));
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   122
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   123
        return uri;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   124
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   125
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   126
    URI getUri() { return uri; }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   127
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   128
    HttpClient getClient() { return client; }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   129
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   130
    Map<String, List<String>> getHeaders() {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   131
        LinkedHashMap<String, List<String>> copy = new LinkedHashMap<>(headers.size());
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   132
        headers.forEach((name, values) -> copy.put(name, new LinkedList<>(values)));
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   133
        return copy;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   134
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   135
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   136
    WebSocket.Listener getListener() { return listener; }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   137
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   138
    Collection<String> getSubprotocols() {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   139
        return new ArrayList<>(subprotocols);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   140
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   141
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   142
    long getTimeout() { return timeout; }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   143
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   144
    TimeUnit getTimeUnit() { return timeUnit; }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   145
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   146
    private static Collection<String> checkSubprotocols(String mostPreferred,
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   147
                                                        String... lesserPreferred) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   148
        checkSubprotocolSyntax(mostPreferred, "mostPreferred");
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   149
        LinkedHashSet<String> sp = new LinkedHashSet<>(1 + lesserPreferred.length);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   150
        sp.add(mostPreferred);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   151
        for (int i = 0; i < lesserPreferred.length; i++) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   152
            String p = lesserPreferred[i];
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   153
            String location = format("lesserPreferred[%s]", i);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   154
            requireNonNull(p, location);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   155
            checkSubprotocolSyntax(p, location);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   156
            if (!sp.add(p)) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   157
                throw new IllegalArgumentException(format(
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   158
                        "Duplicate subprotocols (RFC 6455 4.1.): '%s'", p));
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   159
            }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   160
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   161
        return sp;
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   162
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   163
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   164
    private static void checkSubprotocolSyntax(String subprotocol, String location) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   165
        if (subprotocol.isEmpty()) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   166
            throw new IllegalArgumentException
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   167
                    ("Subprotocol name is empty (RFC 6455 4.1.): " + location);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   168
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   169
        if (!subprotocol.chars().allMatch(c -> 0x21 <= c && c <= 0x7e)) {
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   170
            throw new IllegalArgumentException
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   171
                    ("Subprotocol name contains illegal characters (RFC 6455 4.1.): "
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   172
                            + location);
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   173
        }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   174
    }
02589df0999a 8087113: Websocket API and implementation
prappo
parents:
diff changeset
   175
}