    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.http.internal.services;
    014
    015import java.io.UnsupportedEncodingException;
    016import java.util.Collections;
    017import java.util.Enumeration;
    018import java.util.List;
    019import java.util.Locale;
    020
    021import javax.servlet.http.HttpServletRequest;
    022
    023import org.apache.tapestry5.commons.util.CollectionFactory;
    024import org.apache.tapestry5.http.services.Request;
    025import org.apache.tapestry5.http.services.Session;
    026
    027/**
    028 * Basic implementation of {@link org.apache.tapestry5.http.services.Request} that wraps around an
    029 * {@link javax.servlet.http.HttpServletRequest}. This is not threadsafe, nor should it need to be (each Request is
    030 * handled by its own Thread).
    031 */
    032public class RequestImpl implements Request
    033{
    034    /**
    035     * @deprecated Use {@link Request#REQUESTED_WITH_HEADER} instead
    036     */
    037    static final String REQUESTED_WITH_HEADER = Request.REQUESTED_WITH_HEADER;
    038
    039    static final String XML_HTTP_REQUEST = "XMLHttpRequest";
    040
    041    /**
    042     * @deprecated Use {@link Request#X_FORWARDED_PROTO_HEADER} instead
    043     */
    044    static final String X_FORWARDED_PROTO_HEADER = Request.X_FORWARDED_PROTO_HEADER;
    045    static final String X_FORWARDED_PROTO_HTTPS = "https";
    046
    047    private final HttpServletRequest request;
    048
    049    private final String applicationCharset;
    050
    051    private final TapestrySessionFactory sessionFactory;
    052
    053    private boolean encodingSet;
    054
    055    private Session session;
    056
    057    public RequestImpl(
    058            HttpServletRequest request,
    059            String applicationCharset,
    060            TapestrySessionFactory sessionFactory)
    061    {
    062        this.request = request;
    063        this.applicationCharset = applicationCharset;
    064        this.sessionFactory = sessionFactory;
    065    }
    066
    067    public List<String> getParameterNames()
    068    {
    069        setupEncoding();
    070
    071        return toList(request.getParameterNames());
    072    }
    073
    074    public List<String> getHeaderNames()
    075    {
    076        return toList(request.getHeaderNames());
    077    }
    078
    079    public String getParameter(String name)
    080    {
    081        setupEncoding();
    082
    083        return request.getParameter(name);
    084    }
    085
    086    public String[] getParameters(String name)
    087    {
    088        setupEncoding();
    089
    090        return request.getParameterValues(name);
    091    }
    092
    093    public String getHeader(String name)
    094    {
    095        return request.getHeader(name);
    096    }
    097
    098    public String getPath()
    099    {
    100        String pathInfo = request.getPathInfo();
    101
    102        if (pathInfo == null)
    103            return request.getServletPath();
    104
    105        // Websphere 6.1 is a bit wonky (see TAPESTRY-1713), and tends to return the empty string
    106        // for the servlet path, and return the true path in pathInfo.
    107
    108        return pathInfo.length() == 0 ? "/" : pathInfo;
    109    }
    110
    111    public String getContextPath()
    112    {
    113        return request.getContextPath();
    114    }
    115
    116
    117    public boolean isSessionInvalidated()
    118    {
    119        // Double check to ensure that the session exists, but don't create it.
    120        if (session == null)
    121        {
    122            session = sessionFactory.getSession(false);
    123        }
    124
    125        return session != null && session.isInvalidated();
    126    }
    127
    128    public Session getSession(boolean create)
    129    {
    130        if (session != null && session.isInvalidated())
    131        {
    132            session = null;
    133        }
    134
    135        if (session == null)
    136        {
    137            // TAP5-1489 - Re-storage of session attributes at end of request should be configurable
    138            session = sessionFactory.getSession(create);
    139        }
    140
    141        return session;
    142    }
    143
    144    public Locale getLocale()
    145    {
    146        return request.getLocale();
    147    }
    148
    149    public long getDateHeader(String name)
    150    {
    151        return request.getDateHeader(name);
    152    }
    153
    154    private void setupEncoding()
    155    {
    156        if (encodingSet)
    157        {
    158            return;
    159        }
    160
    161        // The request may specify an encoding, which is better than the application, which can only
    162        // guess at what the client is doing!
    163
    164        String requestEncoding = request.getCharacterEncoding();
    165
    166        try
    167        {
    168            request.setCharacterEncoding(requestEncoding != null ? requestEncoding : applicationCharset);
    169        } catch (UnsupportedEncodingException ex)
    170        {
    171            throw new RuntimeException(ex);
    172        }
    173
    174        encodingSet = true;
    175    }
    176
    177    public boolean isXHR()
    178    {
    179        return XML_HTTP_REQUEST.equals(request.getHeader(Request.REQUESTED_WITH_HEADER));
    180    }
    181
    182    public boolean isSecure()
    183    {
    184        return request.isSecure() ||
    185                X_FORWARDED_PROTO_HTTPS.equals(request.getHeader(Request.X_FORWARDED_PROTO_HEADER));
    186    }
    187
    188    public boolean isRequestedSessionIdValid()
    189    {
    190        return request.isRequestedSessionIdValid();
    191    }
    192
    193    public Object getAttribute(String name)
    194    {
    195        return request.getAttribute(name);
    196    }
    197
    198    public List<String> getAttributeNames()
    199    {
    200        setupEncoding();
    201
    202        return toList(request.getAttributeNames());
    203    }
    204
    205    public void setAttribute(String name, Object value)
    206    {
    207        request.setAttribute(name, value);
    208    }
    209
    210    public String getMethod()
    211    {
    212        return request.getMethod();
    213    }
    214
    215    public String getServerName()
    216    {
    217        return request.getServerName();
    218    }
    219
    220    public int getLocalPort()
    221    {
    222        return request.getLocalPort();
    223    }
    224
    225    /**
    226     * @since 5.2.5
    227     */
    228    public int getServerPort()
    229    {
    230        return request.getServerPort();
    231    }
    232
    233    public String getRemoteHost()
    234    {
    235        return request.getRemoteHost();
    236    }
    237
    238    /**
    239     * Converts an enumeration (of Strings) into a sorted list of Strings.
    240     */
    241    @SuppressWarnings("rawtypes")
    242    private static List<String> toList(Enumeration e)
    243    {
    244        List<String> result = CollectionFactory.newList();
    245
    246        while (e.hasMoreElements())
    247        {
    248            String name = (String) e.nextElement();
    249
    250            result.add(name);
    251        }
    252
    253        Collections.sort(result);
    254
    255        return result;
    256    }
    257
    258
    259}