org.eclipse.rdf4j.common.webapp.util.HttpServerUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rdf4j-http-server-spring Show documentation
Show all versions of rdf4j-http-server-spring Show documentation
HTTP server implementing a REST-style protocol
/*******************************************************************************
* Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.common.webapp.util;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
public class HttpServerUtil {
/**
* Extracts the MIME type from the specified content type string. This method parses the content type string and
* returns just the MIME type, ignoring any parameters that are included.
*
* @param contentType A content type string, e.g. application/xml; charset=utf-8 .
* @return The MIME type part of the specified content type string, or null if the specified content type
* string was null.
*/
public static String getMIMEType(String contentType) {
if (contentType == null) {
return null;
}
return HeaderElement.parse(contentType).getValue();
}
/**
* Selects from a set of MIME types, the MIME type that has the highest quality score when matched with the Accept
* headers in the supplied request.
*
* @param mimeTypes The set of available MIME types.
* @param request The request to match the MIME types against.
* @return The MIME type that best matches the types that the client finds acceptable, or null in case no
* acceptable MIME type could be found.
*/
public static String selectPreferredMIMEType(Iterator mimeTypes, HttpServletRequest request) {
List acceptElements = getHeaderElements(request, "Accept");
if (acceptElements.isEmpty()) {
// Client does not specify any requirements, return first MIME type
// from the list
if (mimeTypes.hasNext()) {
return mimeTypes.next();
} else {
return null;
}
}
String result = null;
HeaderElement matchingAcceptType = null;
double highestQuality = 0.0;
while (mimeTypes.hasNext()) {
String mimeType = mimeTypes.next();
HeaderElement acceptType = matchAcceptHeader(mimeType, acceptElements);
if (acceptType != null) {
// quality defaults to 1.0
double quality = 1.0;
String qualityStr = acceptType.getParameterValue("q");
if (qualityStr != null) {
try {
quality = Double.parseDouble(qualityStr);
} catch (NumberFormatException e) {
// Illegal quality value, assume it has a different meaning
// and ignore it
}
}
if (quality > highestQuality) {
result = mimeType;
matchingAcceptType = acceptType;
highestQuality = quality;
} else if (quality == highestQuality) {
// found a match with equal quality preference. check if the
// accept type is more specific
// than the previous match.
if (isMoreSpecificType(acceptType, matchingAcceptType)) {
result = mimeType;
matchingAcceptType = acceptType;
}
}
}
}
return result;
}
/**
* Checks if the first supplied MIME type is more specific than the second supplied MIME type.
*
* @param leftMimeTypeElem
* @param rightMimeTypeElem
* @return true iff leftMimeTypeElem is a more specific MIME type spec than rightMimeTypeElem, false otherwise.
*/
private static boolean isMoreSpecificType(HeaderElement leftMimeTypeElem, HeaderElement rightMimeTypeElem) {
String[] leftMimeType = splitMIMEType(leftMimeTypeElem.getValue());
String[] rightMimeType = splitMIMEType(rightMimeTypeElem.getValue());
if (rightMimeType != null) {
if (rightMimeType[1].equals("*")) {
if (!leftMimeType[1].equals("*")) {
return true;
}
}
if (rightMimeType[0].equals("*")) {
if (!leftMimeType[0].equals("*")) {
return true;
}
}
return false;
} else {
return true;
}
}
private static String[] splitMIMEType(String mimeTypeString) {
int slashIdx = mimeTypeString.indexOf('/');
if (slashIdx > 0) {
String type = mimeTypeString.substring(0, slashIdx);
String subType = mimeTypeString.substring(slashIdx + 1);
return new String[] { type, subType };
} else {
// invalid mime type
return null;
}
}
/**
* Gets the elements of the request header with the specified name.
*
* @param request The request to get the header from.
* @param headerName The name of the header to get the elements of.
* @return A List of {@link HeaderElement} objects.
*/
public static List getHeaderElements(HttpServletRequest request, String headerName) {
List elemList = new ArrayList<>(8);
@SuppressWarnings("unchecked")
Enumeration headerValues = request.getHeaders(headerName);
while (headerValues.hasMoreElements()) {
String value = headerValues.nextElement();
List subValues = splitHeaderString(value, ',');
for (String subValue : subValues) {
// Ignore any empty header elements
subValue = subValue.trim();
if (subValue.length() > 0) {
elemList.add(HeaderElement.parse(subValue));
}
}
}
return elemList;
}
/**
* Splits the supplied string into sub parts using the specified splitChar as a separator, ignoring occurrences of
* this character inside quoted strings.
*
* @param s The header string to split into sub parts.
* @param splitChar The character to use as separator.
* @return A List of Strings.
*/
public static List splitHeaderString(String s, char splitChar) {
List result = new ArrayList<>(8);
boolean parsingQuotedString = false;
int i, startIdx = 0;
for (i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == splitChar && !parsingQuotedString) {
result.add(s.substring(startIdx, i));
startIdx = i + 1;
} else if (c == '"') {
parsingQuotedString = !parsingQuotedString;
}
}
if (startIdx < s.length()) {
result.add(s.substring(startIdx));
}
return result;
}
/**
* Tries to match the specified MIME type spec against the list of Accept header elements, returning the applicable
* header element if available.
*
* @param mimeTypeSpec The MIME type to determine the quality for, e.g. "text/plain" or "application/xml;
* charset=utf-8".
* @param acceptElements A List of {@link HeaderElement} objects.
* @return The Accept header element that matches the MIME type spec most closely, or null if no such
* header element could be found.
*/
public static HeaderElement matchAcceptHeader(String mimeTypeSpec, List acceptElements) {
HeaderElement mimeTypeElem = HeaderElement.parse(mimeTypeSpec);
while (mimeTypeElem != null) {
for (HeaderElement acceptElem : acceptElements) {
if (matchesAcceptHeader(mimeTypeElem, acceptElem)) {
return acceptElem;
}
}
// No match found, generalize the MIME type spec and try again
mimeTypeElem = generalizeMIMEType(mimeTypeElem);
}
return null;
}
private static boolean matchesAcceptHeader(HeaderElement mimeTypeElem, HeaderElement acceptElem) {
if (!mimeTypeElem.getValue().equals(acceptElem.getValue())) {
return false;
}
// Values match, check parameters
if (mimeTypeElem.getParameterCount() > acceptElem.getParameterCount()) {
return false;
}
for (int i = 0; i < mimeTypeElem.getParameterCount(); i++) {
if (!mimeTypeElem.getParameter(i).equals(acceptElem.getParameter(i))) {
return false;
}
}
return true;
}
/**
* Generalizes a MIME type element. The following steps are taken for generalization:
*
* - If the MIME type element has one or more parameters, the last parameter is removed.
*
- Otherwise, if the MIME type element's subtype is not equal to '*' then it is set to this value.
*
- Otherwise, if the MIME type element's type is not equal to '*' then it is set to this value.
*
- Otherwise, the MIME type is equal to "*&slash;*" and cannot be generalized any further; null is
* returned.
*
*
* Example generalizations:
*
*
*
* input
* result
*
*
* application/xml; charset=utf-8
* application/xml
*
*
* application/xml
* application/*
*
*
* application/*
* &slash;*
*
*
* &slash;*
* null
*
*
*
* @param mimeTypeElem The MIME type element that should be generalized.
* @return The generalized MIME type element, or null if it could not be generalized any further.
*/
private static HeaderElement generalizeMIMEType(HeaderElement mimeTypeElem) {
int parameterCount = mimeTypeElem.getParameterCount();
if (parameterCount > 0) {
// remove last parameter
mimeTypeElem.removeParameter(parameterCount - 1);
} else {
String mimeType = mimeTypeElem.getValue();
int slashIdx = mimeType.indexOf('/');
if (slashIdx > 0) {
String type = mimeType.substring(0, slashIdx);
String subType = mimeType.substring(slashIdx + 1);
if (!subType.equals("*")) {
// generalize subtype
mimeTypeElem.setValue(type + "/*");
} else if (!type.equals("*")) {
// generalize type
mimeTypeElem.setValue("*/*");
} else {
// Cannot generalize any further
mimeTypeElem = null;
}
} else {
// invalid MIME type
mimeTypeElem = null;
}
}
return mimeTypeElem;
}
/**
* Gets the trimmed value of a request parameter as a String.
*
* @return The trimmed value, or null if the parameter does not exist.
*/
public static String getPostDataParameter(Map formData, String name) {
String result = null;
try {
Object param = formData.get(name);
if (param instanceof String[]) {
String[] paramArray = (String[]) param;
if (paramArray.length > 0) {
result = paramArray[0];
}
} else if (param instanceof String) {
result = (String) param;
}
if (result != null) {
result = result.trim();
}
} catch (ClassCastException cce) {
// ignore, return null
}
return result;
}
/**
* @return true if the string is either null or equal to ""
*/
public static boolean isEmpty(String string) {
boolean result = false;
if (string == null || string.trim().isEmpty()) {
result = true;
}
return result;
}
/**
* @return true if the string is !isEmpty and equal to "true"
*/
public static boolean isTrue(String string) {
boolean result = false;
if (!isEmpty(string) && (string.equalsIgnoreCase("true") || string.equalsIgnoreCase("on"))) {
result = true;
}
return result;
}
/**
* @return true if the string is !isEmpty and equal to "false"
*/
public static boolean isFalse(String string) {
boolean result = false;
if (!isEmpty(string) && (string.equalsIgnoreCase("false") || string.equalsIgnoreCase("off"))) {
result = true;
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy