blob: ecfde67ae29b144c5454af829491b918549eaff5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.api.request;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.servlets.HttpConstants;
/**
* Request related utility methods.
* <p>
* This class is not intended to be extended or instantiated because it just
* provides static utility methods not intended to be overwritten.
*
* @since 2.1 (Sling API Bundle 2.1.0)
*/
public class RequestUtil {
/**
* Parses a header of the form:
*
* <pre>
* Header = Token { &quot;,&quot; Token } .
* Token = name { &quot;;&quot; Parameter } .
* Parameter = name [ &quot;=&quot; value ] .
* </pre>
*
* "," and ";" are not allowed within name and value
*
* @param value The header value
* @return A Map indexed by the Token names where the values are Map
* instances indexed by parameter name
*/
public static @NotNull Map<String, Map<String, String>> parserHeader(@NotNull String value) {
Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
String[] tokens = value.split(",");
for (int i = 0; i < tokens.length; i++) {
String[] parameters = tokens[i].split(";");
String name = parameters[0].trim();
Map<String, String> parMap;
if (parameters.length > 0) {
parMap = new HashMap<String, String>();
for (int j = 1; j < parameters.length; j++) {
String[] content = parameters[j].split("=", 2);
if (content.length > 1) {
parMap.put(content[0].trim(), content[1].trim());
} else {
parMap.put(content[0].trim(), content[0].trim());
}
}
} else {
parMap = Collections.emptyMap();
}
result.put(name, parMap);
}
return result;
}
/**
* Parses an <code>Accept-*</code> header of the form:
*
* <pre>
* Header = Token { &quot;,&quot; Token } .
* Token = name { &quot;;&quot; &quot;q&quot; [ &quot;=&quot; value ] } .
* Parameter = .
* </pre>
*
* "," and ";" are not allowed within name and value
*
* @param value The header value
* @return A Map indexed by the Token names where the values are
* <code>Double</code> instances providing the value of the
* <code>q</code> parameter.
*/
public static @NotNull Map<String, Double> parserAcceptHeader(@NotNull String value) {
Map<String, Double> result = new HashMap<String, Double>();
String[] tokens = value.split(",");
for (int i = 0; i < tokens.length; i++) {
String[] parameters = tokens[i].split(";");
String name = parameters[0];
Double qVal = new Double(1.0);
if (parameters.length > 1) {
for (int j = 1; j < parameters.length; j++) {
String[] content = parameters[j].split("=", 2);
if (content.length > 1 && "q".equals(content[0])) {
try {
qVal = Double.valueOf(content[1]);
} catch (NumberFormatException nfe) {
// don't care
}
}
}
}
if (qVal != null) {
result.put(name, qVal);
}
}
return result;
}
/**
* Utility method to return a name for the given servlet. This method
* applies the following algorithm to find a non-<code>null</code>,
* non-empty name:
* <ol>
* <li>If the servlet has a servlet config, the servlet name from the
* servlet config is taken.
* <li>Otherwise check the servlet info
* <li>Otherwise use the fully qualified name of the servlet class
* </ol>
*
* @param servlet The servlet
* @return The name of the servlet.
*/
public static @NotNull String getServletName(@NotNull Servlet servlet) {
String name = null;
if (servlet.getServletConfig() != null) {
name = servlet.getServletConfig().getServletName();
}
if (name == null || name.length() == 0) {
name = servlet.getServletInfo();
}
if (name == null || name.length() == 0) {
name = servlet.getClass().getName();
}
return name;
}
/**
* Sets the named request attribute to the new value and returns the
* previous value.
*
* @param request The request object whose attribute is to be set.
* @param name The name of the attribute to be set.
* @param value The new value of the attribute. If this is <code>null</code>
* the attribte is actually removed from the request.
* @return The previous value of the named request attribute or
* <code>null</code> if it was not set.
*/
public static @Nullable Object setRequestAttribute(@NotNull HttpServletRequest request,
@NotNull String name, Object value) {
Object oldValue = request.getAttribute(name);
if (value == null) {
request.removeAttribute(name);
} else {
request.setAttribute(name, value);
}
return oldValue;
}
/**
* Checks if the request contains a if-last-modified-since header and if the the
* request's underlying resource has a jcr:lastModified property. if the properties were modified
* before the header a 304 is sent otherwise the response last modified header is set.
* @param req the request
* @param resp the response
* @return <code>true</code> if the response was set
*/
public static boolean handleIfModifiedSince(@NotNull SlingHttpServletRequest req, @NotNull HttpServletResponse resp){
boolean responseSet=false;
long lastModified=req.getResource().getResourceMetadata().getModificationTime();
if (lastModified!=-1){
long modifiedTime = lastModified/1000; //seconds
long ims = req.getDateHeader(HttpConstants.HEADER_IF_MODIFIED_SINCE)/1000; //seconds
if (modifiedTime <= ims) {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
responseSet=true;
}
resp.setDateHeader(HttpConstants.HEADER_LAST_MODIFIED, lastModified);
}
return responseSet;
}
}