001/*
002 * Copyright 2002-2014 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.socket.server.support;
018
019import java.util.Collection;
020import java.util.Collections;
021import java.util.Enumeration;
022import java.util.Map;
023import javax.servlet.http.HttpSession;
024
025import org.springframework.http.server.ServerHttpRequest;
026import org.springframework.http.server.ServerHttpResponse;
027import org.springframework.http.server.ServletServerHttpRequest;
028import org.springframework.web.socket.WebSocketHandler;
029import org.springframework.web.socket.WebSocketSession;
030import org.springframework.web.socket.server.HandshakeInterceptor;
031
032/**
033 * An interceptor to copy information from the HTTP session to the "handshake
034 * attributes" map to made available via{@link WebSocketSession#getAttributes()}.
035 *
036 * <p>Copies a subset or all HTTP session attributes and/or the HTTP session id
037 * under the key {@link #HTTP_SESSION_ID_ATTR_NAME}.
038 *
039 * @author Rossen Stoyanchev
040 * @since 4.0
041 */
042public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
043
044        /**
045         * The name of the attribute under which the HTTP session id is exposed when
046         * {@link #setCopyHttpSessionId(boolean) copyHttpSessionId} is "true".
047         */
048        public static final String HTTP_SESSION_ID_ATTR_NAME = "HTTP.SESSION.ID";
049
050
051        private final Collection<String> attributeNames;
052
053        private boolean copyAllAttributes;
054
055        private boolean copyHttpSessionId = true;
056
057        private boolean createSession;
058
059
060        /**
061         * Default constructor for copying all HTTP session attributes and the HTTP
062         * session id.
063         * @see #setCopyAllAttributes
064         * @see #setCopyHttpSessionId
065         */
066        public HttpSessionHandshakeInterceptor() {
067                this.attributeNames = Collections.emptyList();
068                this.copyAllAttributes = true;
069        }
070
071        /**
072         * Constructor for copying specific HTTP session attributes and the HTTP
073         * session id.
074         * @param attributeNames session attributes to copy
075         * @see #setCopyAllAttributes
076         * @see #setCopyHttpSessionId
077         */
078        public HttpSessionHandshakeInterceptor(Collection<String> attributeNames) {
079                this.attributeNames = Collections.unmodifiableCollection(attributeNames);
080                this.copyAllAttributes = false;
081        }
082
083
084        /**
085         * Return the configured attribute names to copy (read-only).
086         */
087        public Collection<String> getAttributeNames() {
088                return this.attributeNames;
089        }
090
091        /**
092         * Whether to copy all attributes from the HTTP session. If set to "true",
093         * any explicitly configured attribute names are ignored.
094         * <p>By default this is set to either "true" or "false" depending on which
095         * constructor was used (default or with attribute names respectively).
096         * @param copyAllAttributes whether to copy all attributes
097         */
098        public void setCopyAllAttributes(boolean copyAllAttributes) {
099                this.copyAllAttributes = copyAllAttributes;
100        }
101
102        /**
103         * Whether to copy all HTTP session attributes.
104         */
105        public boolean isCopyAllAttributes() {
106                return this.copyAllAttributes;
107        }
108
109        /**
110         * Whether the HTTP session id should be copied to the handshake attributes
111         * under the key {@link #HTTP_SESSION_ID_ATTR_NAME}.
112         * <p>By default this is "true".
113         * @param copyHttpSessionId whether to copy the HTTP session id.
114         */
115        public void setCopyHttpSessionId(boolean copyHttpSessionId) {
116                this.copyHttpSessionId = copyHttpSessionId;
117        }
118
119        /**
120         * Whether to copy the HTTP session id to the handshake attributes.
121         */
122        public boolean isCopyHttpSessionId() {
123                return this.copyHttpSessionId;
124        }
125
126        /**
127         * Whether to allow the HTTP session to be created while accessing it.
128         * <p>By default set to {@code false}.
129         * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
130         */
131        public void setCreateSession(boolean createSession) {
132                this.createSession = createSession;
133        }
134
135        /**
136         * Whether the HTTP session is allowed to be created.
137         */
138        public boolean isCreateSession() {
139                return this.createSession;
140        }
141
142
143        @Override
144        public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
145                        WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
146
147                HttpSession session = getSession(request);
148                if (session != null) {
149                        if (isCopyHttpSessionId()) {
150                                attributes.put(HTTP_SESSION_ID_ATTR_NAME, session.getId());
151                        }
152                        Enumeration<String> names = session.getAttributeNames();
153                        while (names.hasMoreElements()) {
154                                String name = names.nextElement();
155                                if (isCopyAllAttributes() || getAttributeNames().contains(name)) {
156                                        attributes.put(name, session.getAttribute(name));
157                                }
158                        }
159                }
160                return true;
161        }
162
163        private HttpSession getSession(ServerHttpRequest request) {
164                if (request instanceof ServletServerHttpRequest) {
165                        ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
166                        return serverRequest.getServletRequest().getSession(isCreateSession());
167                }
168                return null;
169        }
170
171        @Override
172        public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
173                        WebSocketHandler wsHandler, Exception ex) {
174        }
175
176}