001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.reactive.socket;
018
019import java.net.InetSocketAddress;
020import java.net.URI;
021import java.security.Principal;
022import java.util.Collections;
023import java.util.Map;
024
025import reactor.core.publisher.Mono;
026
027import org.springframework.http.HttpHeaders;
028import org.springframework.lang.Nullable;
029import org.springframework.util.Assert;
030
031/**
032 * Simple container of information related to the handshake request that started
033 * the {@link WebSocketSession} session.
034 *
035 * @author Rossen Stoyanchev
036 * @since 5.0
037 * @see WebSocketSession#getHandshakeInfo()
038 */
039public class HandshakeInfo {
040
041        private final URI uri;
042
043        private final Mono<Principal> principalMono;
044
045        private final HttpHeaders headers;
046
047        @Nullable
048        private final String protocol;
049
050        @Nullable
051        private final InetSocketAddress remoteAddress;
052
053        private final Map<String, Object> attributes;
054
055        @Nullable
056        private final String logPrefix;
057
058
059        /**
060         * Constructor with basic information about the handshake.
061         * @param uri the endpoint URL
062         * @param headers request headers for server or response headers or client
063         * @param principal the principal for the session
064         * @param protocol the negotiated sub-protocol (may be {@code null})
065         */
066        public HandshakeInfo(URI uri, HttpHeaders headers, Mono<Principal> principal, @Nullable String protocol) {
067                this(uri, headers, principal, protocol, null, Collections.emptyMap(), null);
068        }
069
070        /**
071         * Constructor targetting server-side use with extra information about the
072         * handshake, the remote address, and a pre-existing log prefix for
073         * correlation.
074         * @param uri the endpoint URL
075         * @param headers request headers for server or response headers or client
076         * @param principal the principal for the session
077         * @param protocol the negotiated sub-protocol (may be {@code null})
078         * @param remoteAddress the remote address where the handshake came from
079         * @param attributes initial attributes to use for the WebSocket session
080         * @param logPrefix log prefix used during the handshake for correlating log
081         * messages, if any.
082         * @since 5.1
083         */
084        public HandshakeInfo(URI uri, HttpHeaders headers, Mono<Principal> principal,
085                        @Nullable String protocol, @Nullable InetSocketAddress remoteAddress,
086                        Map<String, Object> attributes, @Nullable String logPrefix) {
087
088                Assert.notNull(uri, "URI is required");
089                Assert.notNull(headers, "HttpHeaders are required");
090                Assert.notNull(principal, "Principal is required");
091                Assert.notNull(attributes, "'attributes' is required");
092
093                this.uri = uri;
094                this.headers = headers;
095                this.principalMono = principal;
096                this.protocol = protocol;
097                this.remoteAddress = remoteAddress;
098                this.attributes = attributes;
099                this.logPrefix = logPrefix;
100        }
101
102
103        /**
104         * Return the URL for the WebSocket endpoint.
105         */
106        public URI getUri() {
107                return this.uri;
108        }
109
110        /**
111         * Return the handshake HTTP headers. Those are the request headers for a
112         * server session and the response headers for a client session.
113         */
114        public HttpHeaders getHeaders() {
115                return this.headers;
116        }
117
118        /**
119         * Return the principal associated with the handshake HTTP request.
120         */
121        public Mono<Principal> getPrincipal() {
122                return this.principalMono;
123        }
124
125        /**
126         * The sub-protocol negotiated at handshake time, or {@code null} if none.
127         * @see <a href="https://tools.ietf.org/html/rfc6455#section-1.9">
128         * https://tools.ietf.org/html/rfc6455#section-1.9</a>
129         */
130        @Nullable
131        public String getSubProtocol() {
132                return this.protocol;
133        }
134
135        /**
136         * For a server-side session this is the remote address where the handshake
137         * request came from.
138         * @since 5.1
139         */
140        @Nullable
141        public InetSocketAddress getRemoteAddress() {
142                return this.remoteAddress;
143        }
144
145        /**
146         * Attributes extracted from the handshake request to be added to the
147         * WebSocket session.
148         * @since 5.1
149         */
150        public Map<String, Object> getAttributes() {
151                return this.attributes;
152        }
153
154        /**
155         * A log prefix used in the handshake to correlate log messages, if any.
156         * @return a log prefix, or {@code null} if not specified
157         * @since 5.1
158         */
159        @Nullable
160        public String getLogPrefix() {
161                return this.logPrefix;
162        }
163
164
165        @Override
166        public String toString() {
167                return "HandshakeInfo[uri=" + this.uri + ", headers=" + this.headers + "]";
168        }
169
170}