/* * Copyright 2011- Per Wendel * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package spark; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import spark.QueryParamsMap; import spark.Request; import spark.Session; import spark.route.HttpMethod; import spark.route.RouteMatch; import spark.utils.IOUtils; import spark.utils.SparkUtils; import com.cinchapi.concourse.server.http.HttpRequest; import com.cinchapi.concourse.util.DataServices; import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.gson.JsonElement; /** * Provides information about the HTTP request * * @author Per Wendel */ public class Request implements HttpRequest { private static Map<String, String> getParams(List<String> request, List<String> matched) { Map<String, String> params = new HashMap<String, String>(); for (int i = 0; (i < request.size()) && (i < matched.size()); i++) { String matchedPart = matched.get(i); if(SparkUtils.isParam(matchedPart)) { params.put(matchedPart.toLowerCase(), request.get(i)); } } return Collections.unmodifiableMap(params); } private static List<String> getSplat(List<String> request, List<String> matched) { int nbrOfRequestParts = request.size(); int nbrOfMatchedParts = matched.size(); boolean sameLength = (nbrOfRequestParts == nbrOfMatchedParts); List<String> splat = new ArrayList<String>(); for (int i = 0; (i < nbrOfRequestParts) && (i < nbrOfMatchedParts); i++) { String matchedPart = matched.get(i); if(SparkUtils.isSplat(matchedPart)) { StringBuilder splatParam = new StringBuilder(request.get(i)); if(!sameLength && (i == (nbrOfMatchedParts - 1))) { for (int j = i + 1; j < nbrOfRequestParts; j++) { splatParam.append("/"); splatParam.append(request.get(j)); } } splat.add(splatParam.toString()); } } return Collections.unmodifiableList(splat); } /** * A collection that only contains an empty string, which is used to filter * lists (i.e. {@link List#removeAll(java.util.Collection)} empty strings). */ private static List<String> EMPTY_STRING_COLLECTION = Lists .newArrayList(""); private static final String USER_AGENT = "user-agent"; /* Lazy loaded stuff */ private String body = null; private Set<String> headers = null; private HttpMethod httpMethod; private Map<String, String> params; private QueryParamsMap queryMap; // request.body # request body sent by the client (see below), DONE // request.scheme # "http" DONE // request.path_info # "/foo", DONE // request.port # 80 DONE // request.request_method # "GET", DONE // request.query_string # "", DONE // request.content_length # length of request.body, DONE // request.media_type # media type of request.body DONE, content type? // request.host # "example.com" DONE // request["SOME_HEADER"] # value of SOME_HEADER header, DONE // request.user_agent # user agent (used by :agent condition) DONE // request.url # "http://example.com/example/foo" DONE // request.ip # client IP address DONE // request.env # raw env hash handed in by Rack, DONE // request.get? # true (similar methods for other verbs) // request.secure? # false (would be true over ssl) // request.forwarded? # true (if running behind a reverse proxy) // request.cookies # hash of browser cookies, DONE // request.xhr? # is this an ajax request? // request.script_name # "/example" // request.form_data? # false // request.referrer # the referrer of the client or '/' private HttpServletRequest servletRequest; private Session session = null; private List<String> splat; /** * Constructor */ Request(RouteMatch match, HttpServletRequest request) { this.httpMethod = match.getHttpMethod(); this.servletRequest = request; List<String> requestList = SparkUtils.convertRouteToList(match .getRequestURI()); List<String> matchedList = SparkUtils.convertRouteToList(match .getMatchUri()); params = getParams(requestList, matchedList); splat = getSplat(requestList, matchedList); } protected Request() { // Used by wrapper } /** * Gets the value of the provided attribute * * @param attribute The attribute value or null if not present */ public Object attribute(String attribute) { return servletRequest.getAttribute(attribute); } /** * Sets an attribute on the request (can be fetched in filters/routes later * in the chain) * * @param attribute The attribute * @param value The attribute value */ public void attribute(String attribute, Object value) { servletRequest.setAttribute(attribute, value); } /** * Returns all attributes */ public Set<String> attributes() { Set<String> attrList = new HashSet<String>(); Enumeration<String> attributes = (Enumeration<String>) servletRequest .getAttributeNames(); while (attributes.hasMoreElements()) { attrList.add(attributes.nextElement()); } return attrList; } /** * Returns the request body sent by the client */ public String body() { if(body == null) { try { body = IOUtils.toString(servletRequest.getInputStream()); } catch (Exception e) { throw Throwables.propagate(e); } } return body; } /** * Parse the request body into a {@link JsonElement}. * * @return */ public JsonElement bodyAsJson() { return DataServices.jsonParser().parse(body()); } /** * Returns the length of request.body */ public int contentLength() { return servletRequest.getContentLength(); } /** * Returns the content type of the body */ public String contentType() { return servletRequest.getContentType(); } /** * Returns the context path */ public String contextPath() { return servletRequest.getContextPath(); } /** * Gets cookie by name. * * @param name name of the cookie * @return cookie value or null if the cookie was not found */ public String cookie(String name) { Cookie[] cookies = servletRequest.getCookies(); if(cookies != null) { for (Cookie cookie : cookies) { if(cookie.getName().equals(name)) { return cookie.getValue(); } } } return null; } /** * @return request cookies (or empty Map if cookies dosn't present) */ public Map<String, String> cookies() { Map<String, String> result = new HashMap<String, String>(); Cookie[] cookies = servletRequest.getCookies(); if(cookies != null) { for (Cookie cookie : cookies) { result.put(cookie.getName(), cookie.getValue()); } } return result; } /** * Return a parameter associated with the request being processed. * <p> * Prepend the name of the parameter with {@code ":"} if it is a variable in * the route (i.e. /foo/:id). Otherwise, if the name of the parameter does * not start with {@code ":"} then it is assumed to be a variable in the * query string. (i.e. /foo?id=). * </p> * * @param param * @return the value associated with the param or {@code null} if it is not * provided or not found */ public final String getParamValue(String param) { return param.startsWith(":") ? params(param) : queryParams(param); } /** * Given a list of param aliases, return the first existing value that is * encountered. * <p> * Prepend the name of the parameter with {@code ":"} if it is a variable in * the route (i.e. /foo/:id). Otherwise, if the name of the parameter does * not start with {@code ":"} then it is assumed to be a variable in the * query string. (i.e. /foo?id=). * </p> * * @param aliases * @return the first found value associated with one of the aliases or * {@code null} if none of the aliases are provided with a value. */ public final String getParamValueOrAlias(String... aliases) { for (String alias : aliases) { String value = getParamValue(alias); if(value != null) { return value; } } return null; } /** * Return the list of values mapped from a parameter associated with the * request being processed. This method is only appropriate for query * params and will not work for route variables (because those cannot * contain multiple values). * <p> * <strong>NOTE:</strong> If there are no values for {@code param}, then an * empty list is returned. * </p> * * @param param * @return the (possibly empty) list of values */ public final List<String> getParamValues(String param) { try { List<String> list = Lists.newArrayList(queryMap(param).values()); list.removeAll(EMPTY_STRING_COLLECTION); if(list.size() == 1) { String elt = list.get(0); elt.replaceAll(", ", ","); String[] elts = elt.split(","); list = Lists.newArrayList(elts); } return list; } catch (NullPointerException e) { // the param is not in the map, so // return an empty array return Lists.newArrayListWithCapacity(0); } } /** * Returns all headers */ public Set<String> headers() { if(headers == null) { headers = new TreeSet<String>(); Enumeration<String> enumeration = servletRequest.getHeaderNames(); while (enumeration.hasMoreElements()) { headers.add(enumeration.nextElement()); } } return headers; } /** * Returns the value of the provided header */ public String headers(String header) { return servletRequest.getHeader(header); } /** * Returns the host */ public String host() { return servletRequest.getHeader("host"); } /** * Returns the client's IP address */ public String ip() { return servletRequest.getRemoteAddr(); } /** * Returns the value of the provided route pattern parameter. * Example: parameter 'name' from the following pattern: (get * '/hello/:name') * * @return null if the given param is null or not found */ public String params(String param) { if(param == null) { return null; } if(param.startsWith(":")) { return params.get(param.toLowerCase()); // NOSONAR } else { return params.get(":" + param.toLowerCase()); // NOSONAR } } /** * Returns the path info * Example return: "/example/foo" */ public String pathInfo() { return servletRequest.getPathInfo(); } /** * Returns the server port */ public int port() { return servletRequest.getServerPort(); } public QueryParamsMap queryMap() { initQueryMap(); return queryMap; } public QueryParamsMap queryMap(String key) { return queryMap().get(key); } /** * Returns all query parameters */ public Set<String> queryParams() { return servletRequest.getParameterMap().keySet(); } /** * Returns the value of the provided queryParam * Example: query parameter 'id' from the following request URI: * /hello?id=foo */ public String queryParams(String queryParam) { return servletRequest.getParameter(queryParam); } /** * Returns the query string */ public String queryString() { return servletRequest.getQueryString(); } /** * Gets the raw HttpServletRequest object handed in by Jetty */ public HttpServletRequest raw() { return servletRequest; } /** * Returns request method e.g. GET, POST, PUT, ... */ public String requestMethod() { return httpMethod.name(); } /** * Returns the scheme */ public String scheme() { return servletRequest.getScheme(); } /** * Returns the servlet path */ public String servletPath() { return servletRequest.getServletPath(); } /** * Returns the current session associated with this request, * or if the request does not have a session, creates one. * * @return the session associated with this request */ public Session session() { if(session == null) { session = new Session(servletRequest.getSession()); } return session; } /** * Returns the current session associated with this request, or if there is * no current session and <code>create</code> is true, returns a new * session. * * @param create <code>true</code> to create a new session for this request * if necessary; <code>false</code> to return null if there's no * current session * @return the session associated with this request or <code>null</code> if * <code>create</code> is <code>false</code> and the request has no * valid session */ public Session session(boolean create) { if(session == null) { HttpSession httpSession = servletRequest.getSession(create); if(httpSession != null) { session = new Session(httpSession); } } return session; } /** * Returns an arrat containing the splat (wildcard) parameters */ public String[] splat() { return splat.toArray(new String[splat.size()]); } /** * Returns the URL string */ public String url() { return servletRequest.getRequestURL().toString(); } /** * Returns the user-agent */ public String userAgent() { return servletRequest.getHeader(USER_AGENT); } private void initQueryMap() { if(queryMap == null) { queryMap = new QueryParamsMap(raw()); } } }