001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.internal.services;
014
015import org.apache.tapestry5.ioc.internal.util.InternalUtils;
016import org.apache.tapestry5.services.Request;
017import org.apache.tapestry5.services.Session;
018
019import javax.servlet.http.HttpServletRequest;
020import java.io.UnsupportedEncodingException;
021import java.util.List;
022import java.util.Locale;
023
024/**
025 * Basic implementation of {@link org.apache.tapestry5.services.Request} that wraps around an
026 * {@link javax.servlet.http.HttpServletRequest}. This is not threadsafe, nor should it need to be (each Request is
027 * handled by its own Thread).
028 */
029public class RequestImpl implements Request
030{
031    static final String REQUESTED_WITH_HEADER = "X-Requested-With";
032
033    static final String XML_HTTP_REQUEST = "XMLHttpRequest";
034
035    static final String X_FORWARDED_PROTO_HEADER = "X-Forwarded-Proto";
036    static final String X_FORWARDED_PROTO_HTTPS = "https";
037
038    private final HttpServletRequest request;
039
040    private final String applicationCharset;
041
042    private final TapestrySessionFactory sessionFactory;
043
044    private boolean encodingSet;
045
046    private Session session;
047
048    public RequestImpl(
049            HttpServletRequest request,
050            String applicationCharset,
051            TapestrySessionFactory sessionFactory)
052    {
053        this.request = request;
054        this.applicationCharset = applicationCharset;
055        this.sessionFactory = sessionFactory;
056    }
057
058    public List<String> getParameterNames()
059    {
060        setupEncoding();
061
062        return InternalUtils.toList(request.getParameterNames());
063    }
064
065    public List<String> getHeaderNames()
066    {
067        return InternalUtils.toList(request.getHeaderNames());
068    }
069
070    public String getParameter(String name)
071    {
072        setupEncoding();
073
074        return request.getParameter(name);
075    }
076
077    public String[] getParameters(String name)
078    {
079        setupEncoding();
080
081        return request.getParameterValues(name);
082    }
083
084    public String getHeader(String name)
085    {
086        return request.getHeader(name);
087    }
088
089    public String getPath()
090    {
091        String pathInfo = request.getPathInfo();
092
093        if (pathInfo == null)
094            return request.getServletPath();
095
096        // Websphere 6.1 is a bit wonky (see TAPESTRY-1713), and tends to return the empty string
097        // for the servlet path, and return the true path in pathInfo.
098
099        return pathInfo.length() == 0 ? "/" : pathInfo;
100    }
101
102    public String getContextPath()
103    {
104        return request.getContextPath();
105    }
106
107
108    public boolean isSessionInvalidated()
109    {
110        // Double check to ensure that the session exists, but don't create it.
111        if (session == null)
112        {
113            session = sessionFactory.getSession(false);
114        }
115
116        return session != null && session.isInvalidated();
117    }
118
119    public Session getSession(boolean create)
120    {
121        if (session != null && session.isInvalidated())
122        {
123            session = null;
124        }
125
126        if (session == null)
127        {
128            // TAP5-1489 - Re-storage of session attributes at end of request should be configurable
129            session = sessionFactory.getSession(create);
130        }
131
132        return session;
133    }
134
135    public Locale getLocale()
136    {
137        return request.getLocale();
138    }
139
140    public long getDateHeader(String name)
141    {
142        return request.getDateHeader(name);
143    }
144
145    private void setupEncoding()
146    {
147        if (encodingSet)
148        {
149            return;
150        }
151
152        // The request may specify an encoding, which is better than the application, which can only
153        // guess at what the client is doing!
154
155        String requestEncoding = request.getCharacterEncoding();
156
157        try
158        {
159            request.setCharacterEncoding(requestEncoding != null ? requestEncoding : applicationCharset);
160        } catch (UnsupportedEncodingException ex)
161        {
162            throw new RuntimeException(ex);
163        }
164
165        encodingSet = true;
166    }
167
168    public boolean isXHR()
169    {
170        return XML_HTTP_REQUEST.equals(request.getHeader(REQUESTED_WITH_HEADER));
171    }
172
173    public boolean isSecure()
174    {
175        return request.isSecure() ||
176                X_FORWARDED_PROTO_HTTPS.equals(request.getHeader(X_FORWARDED_PROTO_HEADER));
177    }
178
179    public boolean isRequestedSessionIdValid()
180    {
181        return request.isRequestedSessionIdValid();
182    }
183
184    public Object getAttribute(String name)
185    {
186        return request.getAttribute(name);
187    }
188
189    public List<String> getAttributeNames()
190    {
191        setupEncoding();
192
193        return InternalUtils.toList(request.getAttributeNames());
194    }
195
196    public void setAttribute(String name, Object value)
197    {
198        request.setAttribute(name, value);
199    }
200
201    public String getMethod()
202    {
203        return request.getMethod();
204    }
205
206    public String getServerName()
207    {
208        return request.getServerName();
209    }
210
211    public int getLocalPort()
212    {
213        return request.getLocalPort();
214    }
215
216    /**
217     * @since 5.2.5
218     */
219    public int getServerPort()
220    {
221        return request.getServerPort();
222    }
223
224    public String getRemoteHost()
225    {
226        return request.getRemoteHost();
227    }
228
229}