package io.mangoo.routing.bindings;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableMap;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;
import io.mangoo.enums.Required;
import io.mangoo.models.JsonWebToken;
import io.mangoo.utils.JsonUtils;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.Cookie;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
/**
*
* @author svenkubiak
*
*/
public class Request extends Validator {
private static final long serialVersionUID = 1901891944955577394L;
private transient HttpServerExchange httpServerExchange;
private transient JsonWebToken jsonWebToken;
private transient Session session;
private transient Authentication authentication;
private Map<String, Cookie> cookies;
private Map<String, Object> attributes = new HashMap<>();
private String body;
private String authenticity;
private Map<String, String> parameter;
public Request(){
//Empty constructor for google guice
}
public Request(HttpServerExchange httpServerExchange) {
Objects.requireNonNull(httpServerExchange, Required.HTTP_SERVER_EXCHANGE.toString());
this.httpServerExchange = httpServerExchange;
this.cookies = (httpServerExchange.getRequestCookies() == null) ? new HashMap<>() : ImmutableMap.copyOf(httpServerExchange.getRequestCookies());
}
public Request withSession(Session session) {
this.session = session;
return this;
}
public Request withAuthenticity(String authenticity) {
this.authenticity = authenticity;
return this;
}
public Request withAuthentication(Authentication authentication) {
this.authentication = authentication;
return this;
}
public Request withParameter(Map<String, String> parameter) {
this.parameter = parameter;
this.setValues(this.parameter);
return this;
}
public Request withBody(String body) {
this.body = body;
return this;
}
/**
* @return The current session
*/
public Session getSession() {
return this.session;
}
/**
*
* @return The request body
*/
public String getBody() {
return this.body;
}
/**
*
* @return The request body as Map object
*/
@SuppressWarnings("unchecked")
public Map<String, Object> getBodyAsJsonMap() {
if (StringUtils.isNotBlank(this.body)) {
return JsonUtils.fromJson(this.body, Map.class);
}
return new HashMap<>();
}
/**
*
* @return The request body as JsonPath object
*/
public ReadContext getBodyAsJsonPath() {
return JsonPath.parse(this.body);
}
/**
* Checks if the session bound authenticity token matches the client sent
* authenticity token
*
* @return True if the token matches, false otherwise
*/
public boolean authenticityMatches() {
return this.session.getAuthenticity().equals(this.authenticity);
}
/**
* @return The current authentication
*/
public Authentication getAuthentication() {
return authentication;
}
/**
* Retrieves a request parameter (request or query parameter) by its name
*
* @param key The key to lookup the parameter
* @return The value for the given or null if none found
*/
public String getParameter(String key) {
return this.parameter.get(key);
}
/**
* Retrieves a map of request parameter (request or query parameter)
*
* @return Map of request and query parameter
*/
public Map<String, String> getParameter() {
return this.parameter;
}
/**
* Retrieves a list of all headers send by the client
*
* @return A HeaderMap of client sent headers
*/
public HeaderMap getHeaders() {
return this.httpServerExchange.getRequestHeaders();
}
/**
* Retrieves a the clients accepted languages
* @author William Dunne
* @return the string value of the clients accepted languages
*/
public String getAcceptLanguage() {
return this.getHeader(Headers.ACCEPT_LANGUAGE);
}
/**
* Retrieves a specific header value by its name
*
* @param headerName The name of the header to retrieve
* @return The value of the header or null if none found
*/
public String getHeader(HttpString headerName) {
return (this.httpServerExchange.getRequestHeaders().get(headerName) == null) ? null : this.httpServerExchange.getRequestHeaders().get(headerName).element();
}
/**
* The original request URI. This will include the host name, protocol etc
* if it was specified by the client.
*
* This is not decoded in any way, and does not include the query string.
*
* Examples:
* GET http://localhost:8080/myFile.jsf?foo=bar HTTP/1.1 -> 'http://localhost:8080/myFile.jsf'
* POST /my+File.jsf?foo=bar HTTP/1.1 -> '/my+File.jsf'
*
* @return The request URI
*/
public String getURI() {
return this.httpServerExchange.getRequestURI();
}
/**
* Reconstructs the complete URL as seen by the user. This includes scheme, host name etc,
* but does not include query string.
*
* This is not decoded.
*
* @return The request URL
*/
public String getURL() {
return this.httpServerExchange.getRequestURL();
}
/**
* @return An immutable map of request cookies
*/
public Map<String, Cookie> getCookies() {
return this.cookies;
}
/**
* Retrieves a single cookie from the request
*
* @param name The name of the cookie
* @return The Cookie
*/
public Cookie getCookie(String name) {
return this.cookies.get(name);
}
/**
* Get the request URI scheme. Normally this is one of {@code http} or {@code https}.
*
* @return the request URI scheme
*/
public String getScheme() {
return this.httpServerExchange.getRequestScheme();
}
/**
* Returns the request charset. If none was explicitly specified it will return
* "ISO-8859-1", which is the default charset for HTTP requests.
*
* @return The character encoding
*/
public String getCharset() {
return this.httpServerExchange.getRequestCharset();
}
/**
* Adds an attribute to the internal attributes map
*
* @param key The key to store the attribute
* @param value The value to store
*/
public void addAttribute(String key, Object value) {
Objects.requireNonNull(key, Required.KEY.toString());
this.attributes.put(key, value);
}
/**
* @return The content length of the request, or <code>-1</code> if it has not been set
*/
public long getContentLength() {
return this.httpServerExchange.getRequestContentLength();
}
/**
* Get the HTTP request method. Normally this is one of the strings listed in {@link io.undertow.util.Methods}.
*
* @return the HTTP request method
*/
public HttpString getMethod() {
return this.httpServerExchange.getRequestMethod();
}
/**
* The request path. This will be decoded by the server, and does not include the query string.
*
* This path is not canonicalised, so care must be taken to ensure that escape attacks are not possible.
*
* Examples:
* GET http://localhost:8080/b/../my+File.jsf?foo=bar HTTP/1.1 -> '/b/../my+File.jsf'
* POST /my+File.jsf?foo=bar HTTP/1.1 -> '/my File.jsf'
*
* @return The request path
*/
public String getPath() {
return this.httpServerExchange.getRequestPath();
}
/**
* Returns an object attribute from a given key
*
* @param key The key the attribute is stored
* @return Object the value from the attribues map
*/
public Object getAttribute(String key) {
Objects.requireNonNull(key, Required.KEY.toString());
return this.attributes.get(key);
}
/**
* @return All attributes of the request
*/
public Map<String, Object> getAttributes() {
return this.attributes;
}
/**
* Set a Json Web Token to the request
* @param jsonWebToken The Json Web Token
*/
public void setJsonWebToken(JsonWebToken jsonWebToken) {
if (this.jsonWebToken == null) {
this.jsonWebToken = jsonWebToken;
}
}
/**
* @return The validated Json Web Token if present
*/
public Optional<JsonWebToken> getJsonWebToken() {
return Optional.ofNullable(this.jsonWebToken);
}
private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
objectOutputStream.writeObject(body);
objectOutputStream.writeObject(authenticity);
}
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
this.body = (String) objectInputStream.readObject();
this.authentication = (Authentication) objectInputStream.readObject();
}
}