com.phloc.webscopes.impl.RequestWebScopeNoMultipart Maven / Gradle / Ivy
/**
* Copyright (C) 2006-2014 phloc systems
* http://www.phloc.com
* office[at]phloc[dot]com
*
* 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 com.phloc.webscopes.impl;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.OverrideOnDemand;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.charset.CCharset;
import com.phloc.commons.collections.ArrayHelper;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.equals.EqualsUtils;
import com.phloc.commons.idfactory.GlobalIDFactory;
import com.phloc.commons.io.streams.StreamUtils;
import com.phloc.commons.lang.CGStringHelper;
import com.phloc.commons.mime.CMimeType;
import com.phloc.commons.mime.MimeType;
import com.phloc.commons.mime.MimeTypeParser;
import com.phloc.commons.string.StringHelper;
import com.phloc.commons.string.ToStringGenerator;
import com.phloc.commons.url.ISimpleURL;
import com.phloc.commons.url.SimpleURL;
import com.phloc.json.IJSONObject;
import com.phloc.json.impl.JSONParsingException;
import com.phloc.json.impl.JSONReader;
import com.phloc.scopes.AbstractMapBasedScope;
import com.phloc.scopes.ScopeUtils;
import com.phloc.web.fileupload.IFileItem;
import com.phloc.web.http.EHTTPMethod;
import com.phloc.web.http.EHTTPVersion;
import com.phloc.web.servlet.request.IRequestParamMap;
import com.phloc.web.servlet.request.RequestHelper;
import com.phloc.web.servlet.request.RequestParamMap;
import com.phloc.webscopes.domain.IRequestWebScope;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/**
* A request web scopes that does not parse multi-part requests.
*
* @author Boris Gregorcic
*/
public class RequestWebScopeNoMultipart extends AbstractMapBasedScope implements IRequestWebScope
{
private static final Logger LOG = LoggerFactory.getLogger (RequestWebScopeNoMultipart.class);
// Because of transient field
private static final long serialVersionUID = 78563987233146L;
private static final String REQUEST_ATTR_SCOPE_INITED = "$request.scope.inited"; //$NON-NLS-1$
private static final String REQUEST_ATTR_REQUESTPARAMMAP = "$request.scope.requestparammap"; //$NON-NLS-1$
public static final String REQUEST_ATTR_PARSE_JSON_BODY = "$request.scope.jsonbody"; //$NON-NLS-1$
public static final String REQUEST_ATTR_JSON_BODY_PARSED = "$request.scope.jsonbody.parsed"; //$NON-NLS-1$
protected final transient HttpServletRequest m_aHttpRequest;
protected final transient HttpServletResponse m_aHttpResponse;
@Nonnull
@Nonempty
private static String _createScopeID (@Nonnull final HttpServletRequest aHttpRequest)
{
ValueEnforcer.notNull (aHttpRequest, "HttpRequest"); //$NON-NLS-1$
return GlobalIDFactory.getNewIntID () + "@" + aHttpRequest.getRequestURI (); //$NON-NLS-1$
}
public RequestWebScopeNoMultipart (@Nonnull final HttpServletRequest aHttpRequest,
@Nonnull final HttpServletResponse aHttpResponse)
{
super (_createScopeID (aHttpRequest));
this.m_aHttpRequest = aHttpRequest;
this.m_aHttpResponse = ValueEnforcer.notNull (aHttpResponse, "HttpResponse"); //$NON-NLS-1$
// done initialization
if (ScopeUtils.debugRequestScopeLifeCycle (LOG))
{
LOG.info ("Created request web scope '" + //$NON-NLS-1$
getID () +
"' of class " + //$NON-NLS-1$
CGStringHelper.getClassLocalName (this),
ScopeUtils.getDebugStackTrace ());
}
}
@SuppressWarnings ("static-method")
@OverrideOnDemand
protected boolean addSpecialRequestAttributes ()
{
return false;
}
@OverrideOnDemand
protected void postAttributeInit ()
{
// empty by default
}
@Override
public final void initScope ()
{
// Avoid double initialization of a scope, because for file uploads, the
// parameters can only be extracted once!
// As the parameters are stored directly in the HTTP request, we're not
// loosing any data here!
if (getAndSetAttributeFlag (REQUEST_ATTR_SCOPE_INITED))
{
LOG.warn ("Scope was already inited: " + toString ()); //$NON-NLS-1$
return;
}
propagateDisaptcherErrors ();
// where some extra items (like file items) handled?
final boolean bAddedSpecialRequestAttrs = addSpecialRequestAttributes ();
// set parameters as attributes (handles GET and POST parameters)
final Enumeration > aEnum = this.m_aHttpRequest.getParameterNames ();
while (aEnum.hasMoreElements ())
{
final String sParamName = (String) aEnum.nextElement ();
// Avoid double setting a parameter!
if (bAddedSpecialRequestAttrs && containsAttribute (sParamName))
{
continue;
}
// Check if it is a single value or not
final String [] aParamValues = this.m_aHttpRequest.getParameterValues (sParamName);
if (aParamValues.length == 1)
{
setAttribute (sParamName, aParamValues[0]);
}
else
{
setAttribute (sParamName, aParamValues);
}
}
try
{
RequestInitializerHandler.getInstance ().initRequestScope (this);
}
catch (final Exception aEx)
{
LOG.error ("Exception caught while initializing request scope:", aEx); //$NON-NLS-1$
}
if (getAttributeAsBoolean (REQUEST_ATTR_PARSE_JSON_BODY) &&
getAttributeObject (ERequestDispatcherErrors.ERROR_STATUS_CODE.getID ()) == null)
{
initJSONBody ();
}
postAttributeInit ();
// done initialization
if (ScopeUtils.debugRequestScopeLifeCycle (LOG))
{
LOG.info ("Initialized request web scope '" + //$NON-NLS-1$
getID () +
"' of class " + //$NON-NLS-1$
CGStringHelper.getClassLocalName (this),
ScopeUtils.getDebugStackTrace ());
}
}
/**
* If the request body contains data that is valid JSON, all JSON properties
* will be added as attributes. This mechanism can be used to transfer big
* data.
*/
private void initJSONBody ()
{
LOG.debug ("Performing JSON body initialization..."); //$NON-NLS-1$
try
{
if (this.m_aHttpRequest.getContentLength () > 0)
{
final MimeType aMimeType = MimeTypeParser.parseMimeType (this.m_aHttpRequest.getContentType ());
if (aMimeType != null &&
aMimeType.getAsStringWithoutParameters ()
.equals (CMimeType.APPLICATION_JSON.getAsStringWithoutParameters ()))
{
final String sJSON = StreamUtils.getAllBytesAsString (this.m_aHttpRequest.getInputStream (),
CCharset.CHARSET_UTF_8_OBJ);
if (StringHelper.isEmpty (sJSON))
{
LOG.warn ("Received empty JSON body in request (may be due to previous IO problem)."); //$NON-NLS-1$
return;
}
final IJSONObject aJSON = JSONReader.parseObject (sJSON);
for (final String sProperty : aJSON.getAllPropertyNames ())
{
Object aVal;
// try as list (to really only store the internal list data values)
// aVal = aJSON.getListProperty (sProperty);
// if (aVal == null)
// {
aVal = aJSON.getPropertyValueData (sProperty);
// }
setAttribute (sProperty, aVal);
}
setAttribute (REQUEST_ATTR_JSON_BODY_PARSED, true);
}
}
}
catch (final IOException aEx)
{
LOG.error ("Error reading request body", aEx); //$NON-NLS-1$
}
catch (final JSONParsingException aEx)
{
LOG.error ("Error parsing JSON request body", aEx); //$NON-NLS-1$
}
catch (final UnsupportedOperationException aEx)
{
// for mock requests it is not possible to get the content length
}
}
/**
* Copy error attributes added by the Servlet Container also to the scope
* attributes
*/
private void propagateDisaptcherErrors ()
{
for (final ERequestDispatcherErrors eDispatcherError : ERequestDispatcherErrors.values ())
{
final Object aValue = this.m_aHttpRequest.getAttribute (eDispatcherError.getID ());
if (aValue != null)
{
setAttribute (eDispatcherError.getID (), aValue);
}
}
}
@Override
protected void postDestroy ()
{
if (ScopeUtils.debugRequestScopeLifeCycle (LOG))
{
LOG.info ("Destroyed request web scope '" + //$NON-NLS-1$
getID () +
"' of class " + //$NON-NLS-1$
CGStringHelper.getClassLocalName (this),
ScopeUtils.getDebugStackTrace ());
}
}
@Override
@Nonnull
@Nonempty
public final String getSessionID ()
{
return getSessionID (true);
}
@Override
@Nullable
public final String getSessionID (final boolean bCreateIfNotExisting)
{
final HttpSession aSession = this.m_aHttpRequest.getSession (bCreateIfNotExisting);
return aSession == null ? null : aSession.getId ();
}
@Override
@Nullable
public List getAttributeValues (@Nullable final String sName)
{
return getAttributeValues (sName, null);
}
@Override
@Nullable
public List getAttributeValues (@Nullable final String sName, @Nullable final List aDefault)
{
final Object aValue = getAttributeObject (sName);
if (aValue instanceof String [])
{
// multiple values passed in the request
return ContainerHelper.newList ((String []) aValue);
}
if (aValue instanceof String)
{
// single value passed in the request
return ContainerHelper.newList ((String) aValue);
}
// E.g. for file items
return aDefault;
}
@Override
public boolean hasAttributeValue (@Nullable final String sName, @Nullable final String sDesiredValue)
{
return EqualsUtils.equals (getAttributeAsString (sName), sDesiredValue);
}
@Override
public boolean hasAttributeValue (@Nullable final String sName,
@Nullable final String sDesiredValue,
final boolean bDefault)
{
final String sValue = getAttributeAsString (sName);
return sValue == null ? bDefault : EqualsUtils.equals (sValue, sDesiredValue);
}
/**
* Returns the name of the character encoding used in the body of this
* request. This method returns null
if the request does not
* specify a character encoding
*
* @return a String
containing the name of the character
* encoding, or null
if the request does not specify a
* character encoding
*/
@Nullable
public String getCharacterEncoding ()
{
return this.m_aHttpRequest.getCharacterEncoding ();
}
@Override
@Nonnull
@ReturnsMutableCopy
public Map getAllUploadedFileItems ()
{
final Map ret = new HashMap <> ();
final Enumeration aEnum = getAttributeNames ();
while (aEnum.hasMoreElements ())
{
final String sAttrName = aEnum.nextElement ();
final Object aAttrValue = getAttributeObject (sAttrName);
if (aAttrValue instanceof IFileItem)
{
ret.put (sAttrName, (IFileItem) aAttrValue);
}
}
return ret;
}
@Override
@Nonnull
@ReturnsMutableCopy
public Map getAllUploadedFileItemsComplete ()
{
final Map ret = new HashMap <> ();
final Enumeration aEnum = getAttributeNames ();
while (aEnum.hasMoreElements ())
{
final String sAttrName = aEnum.nextElement ();
final Object aAttrValue = getAttributeObject (sAttrName);
if (aAttrValue instanceof IFileItem)
{
ret.put (sAttrName, new IFileItem [] { (IFileItem) aAttrValue });
}
else
if (aAttrValue instanceof IFileItem [])
{
ret.put (sAttrName, ArrayHelper.getCopy ((IFileItem []) aAttrValue));
}
}
return ret;
}
@Override
@Nonnull
@ReturnsMutableCopy
public List getAllUploadedFileItemValues ()
{
final List ret = new ArrayList <> ();
final Enumeration aEnum = getAttributeNames ();
while (aEnum.hasMoreElements ())
{
final String sAttrName = aEnum.nextElement ();
final Object aAttrValue = getAttributeObject (sAttrName);
if (aAttrValue instanceof IFileItem)
{
ret.add ((IFileItem) aAttrValue);
}
else
if (aAttrValue instanceof IFileItem [])
{
for (final IFileItem aChild : (IFileItem []) aAttrValue)
{
ret.add (aChild);
}
}
}
return ret;
}
@Override
@Nullable
public IFileItem getAttributeAsFileItem (@Nullable final String sAttrName)
{
final Object aObject = getAttributeObject (sAttrName);
return aObject instanceof IFileItem ? (IFileItem) aObject : null;
}
@Override
@Nonnull
public IRequestParamMap getRequestParamMap ()
{
// Check if a value is cached in the scope
IRequestParamMap aValue = getCastedAttribute (REQUEST_ATTR_REQUESTPARAMMAP);
if (aValue == null)
{
// Use all attributes except the internal ones
final Map aAttrs = getAllAttributes ();
aAttrs.remove (REQUEST_ATTR_SCOPE_INITED);
// Request the map and put it in scope
aValue = RequestParamMap.create (aAttrs);
setAttribute (REQUEST_ATTR_REQUESTPARAMMAP, aValue);
}
return aValue;
}
@Override
public String getScheme ()
{
return this.m_aHttpRequest.getScheme ();
}
@Override
public String getServerName ()
{
return this.m_aHttpRequest.getServerName ();
}
/**
* @deprecated Use {@link #getProtocol()} instead
*/
@Override
@Deprecated
public String getServerProtocolVersion ()
{
return getProtocol ();
}
@Override
public String getProtocol ()
{
return this.m_aHttpRequest.getProtocol ();
}
@Override
@Nullable
public EHTTPVersion getHttpVersion ()
{
return RequestHelper.getHttpVersion (this.m_aHttpRequest);
}
@Override
public int getServerPort ()
{
return this.m_aHttpRequest.getServerPort ();
}
@Override
public String getMethod ()
{
return this.m_aHttpRequest.getMethod ();
}
@Override
@Nullable
public EHTTPMethod getHttpMethod ()
{
return RequestHelper.getHttpMethod (this.m_aHttpRequest);
}
@Override
@Nullable
public String getPathInfo ()
{
return RequestHelper.getPathInfo (this.m_aHttpRequest);
}
@Override
@Nonnull
public String getPathWithinServletContext ()
{
return RequestHelper.getPathWithinServletContext (this.m_aHttpRequest);
}
@Override
@Nonnull
public String getPathWithinServlet ()
{
return RequestHelper.getPathWithinServlet (this.m_aHttpRequest);
}
@Override
public String getPathTranslated ()
{
return this.m_aHttpRequest.getPathTranslated ();
}
@Override
public String getQueryString ()
{
return this.m_aHttpRequest.getQueryString ();
}
@Override
public String getRemoteHost ()
{
return this.m_aHttpRequest.getRemoteHost ();
}
@Override
public String getRemoteAddr ()
{
return this.m_aHttpRequest.getRemoteAddr ();
}
@Override
public String getAuthType ()
{
return this.m_aHttpRequest.getAuthType ();
}
@Override
public String getRemoteUser ()
{
return this.m_aHttpRequest.getRemoteUser ();
}
@Override
public String getContentType ()
{
return this.m_aHttpRequest.getContentType ();
}
@Override
public long getContentLength ()
{
return RequestHelper.getContentLength (this.m_aHttpRequest);
}
@Override
@Nonnull
public String getRequestURI ()
{
return RequestHelper.getRequestURI (this.m_aHttpRequest);
}
@Override
@Nonnull
public String getServletPath ()
{
return this.m_aHttpRequest.getServletPath ();
}
@Override
public HttpSession getSession (final boolean bCreateIfNotExisting)
{
return this.m_aHttpRequest.getSession (bCreateIfNotExisting);
}
@Nonnull
private StringBuilder _getFullServerPath ()
{
return RequestHelper.getFullServerName (this.m_aHttpRequest.getScheme (),
this.m_aHttpRequest.getServerName (),
this.m_aHttpRequest.getServerPort ());
}
@Override
@Nonnull
public String getFullServerPath ()
{
return _getFullServerPath ().toString ();
}
@Override
@Nonnull
public String getContextPath ()
{
return this.m_aHttpRequest.getContextPath ();
}
@Override
@Nonnull
public String getFullContextPath ()
{
return _getFullServerPath ().append (getContextPath ()).toString ();
}
/**
* This is a heuristic method to determine whether a request is for a file
* (e.g. x.jsp) or for a servlet. It is assumed that regular servlets don't
* have a '.' in their name!
*
* @param sServletPath
* The non-null
servlet path to check
* @return true
if it is assumed that the request is file based,
* false
if it can be assumed to be a regular servlet.
*/
public static boolean isFileBasedRequest (@Nonnull final String sServletPath)
{
return sServletPath.indexOf ('.') >= 0;
}
@Override
@Nonnull
public String getContextAndServletPath ()
{
final String sServletPath = getServletPath ();
if (isFileBasedRequest (sServletPath))
{
return getContextPath () + sServletPath;
}
// For servlets that are not files, we need to append a trailing slash
return getContextPath () + sServletPath + '/';
}
@Override
@Nonnull
public String getFullContextAndServletPath ()
{
final String sServletPath = getServletPath ();
if (isFileBasedRequest (sServletPath))
{
return getFullContextPath () + sServletPath;
}
// For servlets, we need to append a trailing slash
return getFullContextPath () + sServletPath + '/';
}
@Override
@Nonnull
@Nonempty
public String getURL ()
{
return RequestHelper.getURL (this.m_aHttpRequest);
}
@Override
@Nonnull
public String encodeURL (@Nonnull final String sURL)
{
return this.m_aHttpResponse.encodeURL (sURL);
}
@Override
@Nonnull
public ISimpleURL encodeURL (@Nonnull final ISimpleURL aURL)
{
ValueEnforcer.notNull (aURL, "URL"); //$NON-NLS-1$
// Encode only the path and copy params and anchor
return new SimpleURL (encodeURL (aURL.getPath ()), aURL.getAllParams (), aURL.getAnchor ());
}
@Override
@Nonnull
public String encodeRedirectURL (@Nonnull final String sURL)
{
return this.m_aHttpResponse.encodeRedirectURL (sURL);
}
@Override
@Nonnull
public ISimpleURL encodeRedirectURL (@Nonnull final ISimpleURL aURL)
{
ValueEnforcer.notNull (aURL, "URL"); //$NON-NLS-1$
// Encode only the path and copy params and anchor
return new SimpleURL (encodeRedirectURL (aURL.getPath ()), aURL.getAllParams (), aURL.getAnchor ());
}
@Override
public boolean areCookiesEnabled ()
{
// Just check whether the session ID is appended to the URL or not
return "a".equals (encodeURL ("a")); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
@Nullable
public String getRequestHeader (@Nullable final String sName)
{
return this.m_aHttpRequest.getHeader (sName);
}
@Override
@Nullable
public Enumeration getRequestHeaders (@Nullable final String sName)
{
return RequestHelper.getRequestHeaders (this.m_aHttpRequest, sName);
}
@Override
@Nullable
public Enumeration getRequestHeaderNames ()
{
return RequestHelper.getRequestHeaderNames (this.m_aHttpRequest);
}
@Override
@Nonnull
public HttpServletRequest getRequest ()
{
return this.m_aHttpRequest;
}
@Override
@Nonnull
public HttpServletResponse getResponse ()
{
return this.m_aHttpResponse;
}
@Override
@Nonnull
public OutputStream getOutputStream () throws IOException
{
return this.m_aHttpResponse.getOutputStream ();
}
@Override
public String toString ()
{
return ToStringGenerator.getDerived (super.toString ())
.append ("httpRequest", this.m_aHttpRequest) //$NON-NLS-1$
.append ("httpResponse", this.m_aHttpResponse) //$NON-NLS-1$
.toString ();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy