package com.onelogin.saml2.http;
import static com.onelogin.saml2.util.Preconditions.checkNotNull;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import com.onelogin.saml2.util.Util;
/**
* Framework-agnostic representation of an HTTP request.
*
* @since 2.0.0
*/
public final class HttpRequest {
public static final Map<String, List<String>> EMPTY_PARAMETERS = Collections.<String, List<String>>emptyMap();
private final String requestURL;
private final Map<String, List<String>> parameters;
private final String queryString;
/**
* Creates a new HttpRequest.
*
* @param requestURL the request URL (up to but not including query parameters)
* @throws NullPointerException if requestURL is null
* @deprecated Not providing a queryString can cause HTTP Redirect binding to fail.
*/
@Deprecated
public HttpRequest(String requestURL) {
this(requestURL, EMPTY_PARAMETERS);
}
/**
* Creates a new HttpRequest.
*
* @param requestURL the request URL (up to but not including query parameters)
* @param queryString string that is contained in the request URL after the path
*/
public HttpRequest(String requestURL, String queryString) {
this(requestURL, EMPTY_PARAMETERS, queryString);
}
/**
* Creates a new HttpRequest.
*
* @param requestURL the request URL (up to but not including query parameters)
* @param parameters the request query parameters
* @throws NullPointerException if any of the parameters is null
* @deprecated Not providing a queryString can cause HTTP Redirect binding to fail.
*/
@Deprecated
public HttpRequest(String requestURL, Map<String, List<String>> parameters) {
this(requestURL, parameters, null);
}
/**
* Creates a new HttpRequest.
*
* @param requestURL the request URL (up to but not including query parameters)
* @param parameters the request query parameters
* @param queryString string that is contained in the request URL after the path
* @throws NullPointerException if any of the parameters is null
*/
public HttpRequest(String requestURL, Map<String, List<String>> parameters, String queryString) {
this.requestURL = checkNotNull(requestURL, "requestURL");
this.parameters = unmodifiableCopyOf(checkNotNull(parameters, "queryParams"));
this.queryString = StringUtils.trimToEmpty(queryString);
}
/**
* @param name the query parameter name
* @param value the query parameter value
* @return a new HttpRequest with the given query parameter added
* @throws NullPointerException if any of the parameters is null
*/
public HttpRequest addParameter(String name, String value) {
checkNotNull(name, "name");
checkNotNull(value, "value");
final List<String> oldValues = parameters.containsKey(name) ? parameters.get(name) : new ArrayList<String>();
final List<String> newValues = new ArrayList<>(oldValues);
newValues.add(value);
final Map<String, List<String>> params = new HashMap<>(parameters);
params.put(name, newValues);
return new HttpRequest(requestURL, params, queryString);
}
/**
* @param name the query parameter name
* @return a new HttpRequest with the given query parameter removed
* @throws NullPointerException if any of the parameters is null
*/
public HttpRequest removeParameter(String name) {
checkNotNull(name, "name");
final Map<String, List<String>> params = new HashMap<>(parameters);
params.remove(name);
return new HttpRequest(requestURL, params, queryString);
}
/**
* The URL the client used to make the request. Includes a protocol, server name, port number, and server path, but
* not the query string parameters.
*
* @return the request URL
*/
public String getRequestURL() {
return requestURL;
}
/**
* @param name the query parameter name
* @return the first value for the parameter, or null
*/
public String getParameter(String name) {
List<String> values = getParameters(name);
return values.isEmpty() ? null : values.get(0);
}
/**
* @param name the query parameter name
* @return a List containing all values for the parameter
*/
public List<String> getParameters(String name) {
List<String> values = parameters.get(name);
return values != null ? values : Collections.<String>emptyList();
}
/**
* @return a map of all query parameters
*/
public Map<String, List<String>> getParameters() {
return parameters;
}
/**
* Return an url encoded get parameter value
* Prefer to extract the original encoded value directly from queryString since url
* encoding is not canonical.
*
* @param name
* @return the first value for the parameter, or null
*/
public String getEncodedParameter(String name) {
Matcher matcher = Pattern.compile(Pattern.quote(name) + "=([^]+)").matcher(queryString);
if (matcher.find()) {
return matcher.group(1);
} else {
return Util.urlEncoder(getParameter(name));
}
}
/**
* Return an url encoded get parameter value
* Prefer to extract the original encoded value directly from queryString since url
* encoding is not canonical.
*
* @param name
* @param defaultValue
* @return the first value for the parameter, or url encoded default value
*/
public String getEncodedParameter(String name, String defaultValue) {
String value = getEncodedParameter(name);
return (value != null ? value : Util.urlEncoder(defaultValue));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
HttpRequest that = (HttpRequest) o;
return Objects.equals(requestURL, that.requestURL) &&
Objects.equals(parameters, that.parameters) &&
Objects.equals(queryString, this.queryString);
}
@Override
public int hashCode() {
return Objects.hash(requestURL, parameters, queryString);
}
@Override
public String toString() {
return "HttpRequest{" +
"requestURL='" + requestURL + '\'' +
", parameters=" + parameters +
", queryString=" + queryString +
'}';
}
private static Map<String, List<String>> unmodifiableCopyOf(Map<String, List<String>> orig) {
Map<String, List<String>> copy = new HashMap<>();
for (Map.Entry<String, List<String>> entry : orig.entrySet()) {
copy.put(entry.getKey(), unmodifiableList(new ArrayList<>(entry.getValue())));
}
return unmodifiableMap(copy);
}
}