Class LockssMultipartHttpServletRequest

java.lang.Object
jakarta.servlet.ServletRequestWrapper
jakarta.servlet.http.HttpServletRequestWrapper
org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest
org.lockss.laaws.rs.multipart.LockssMultipartHttpServletRequest
All Implemented Interfaces:
jakarta.servlet.http.HttpServletRequest, jakarta.servlet.ServletRequest, org.springframework.web.multipart.MultipartHttpServletRequest, org.springframework.web.multipart.MultipartRequest

public class LockssMultipartHttpServletRequest extends org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest
Portions of this class were copied from Spring's StandardMultipartHttpServletRequest and Tomcat's Request, and adapted to workaround issues in those implementations that prevent us from supporting features necessary for the operation of LOCKSS Repository Service:

1. Computing part digests should ideally be done as they're read from the network stream, but it is not possible to do this early enough: StandardMultipartHttpServletRequest wraps an HttpServletRequest from the servlet framework and calls HttpServletRequest.getParts() in its parsing of the request. The Tomcat implementation (Request), is hardcoded to use DiskFileItemFactory and FileUpload which write parts (over a size threshold) to temporary files, prior to making them available to controller methods through StandardMultipartHttpServletRequest.StandardMultipartFile. Jetty appears to use its own multipart parsing logic that is similarly hardcoded. I did not check Undertow.

To work around this, Tomcat's Request.getParts() and Request.parseParts(boolean)} implementations were copied here and adapted to parse the wrapped HttpServletRequest using a DigestFileItemFactory. Since Tomcat's ApplicationPart does not allow access to its wrapped FileItem, and there is no getDigest() or similar in the Part API, it was also necessary to introduce LockssMultipartHttpServletRequest.LockssApplicationPart. Those are in turn used to construct LockssMultipartHttpServletRequest.LockssMultipartFiles, which are the objects ultimately returned to the REST controller method.

2.Malformed part Content-Type header handling: We've chosen to transmit the content-type of an artifact in the part's Content-Type header. Malformed content types were found to cause problems during the serialization of a multipart request (and previously, multipart responses). To work around this, the content type is transmitted via a custom header and falls back to the usual Content-Type if it is not present. Support for receiving a part employing this workaround and returning the intended, malformed type was added to LockssMultipartHttpServletRequest.LockssMultipartFile.getContentType().

See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    LOCKSS implementation of a Spring MultipartFile adapter, wrapping a LOCKSS Servlet Part object (see LockssMultipartHttpServletRequest.LockssApplicationPart).
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    protected Exception
     

    Fields inherited from interface jakarta.servlet.http.HttpServletRequest

    BASIC_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH, FORM_AUTH
  • Constructor Summary

    Constructors
    Constructor
    Description
    LockssMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest request)
    Create a new LockssMultipartHttpServletRequest wrapper for the given request, immediately parsing the multipart content.
    LockssMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest request, boolean lazyParsing)
    Create a new LockssMultipartHttpServletRequest wrapper for the given request.
  • Method Summary

    Modifier and Type
    Method
    Description
    Taken unmodified from Request.getCharset().
    boolean
     
    int
     
    int
     
    jakarta.servlet.MultipartConfigElement
     
    Taken unmodified from StandardMultipartHttpServletRequest.getMultipartContentType(String).
    org.springframework.http.HttpHeaders
    getMultipartHeaders(String paramOrFileName)
    Taken unmodified from StandardMultipartHttpServletRequest.getMultipartHeaders(String).
    Taken unmodified from StandardMultipartHttpServletRequest.getParameterMap().
    Taken unmodified from StandardMultipartHttpServletRequest.getParameterNames().
    Adapted from ServletRequestWrapper.getParameterValues(String), a parent class of StandardMultipartHttpServletRequest.
    jakarta.servlet.http.Part
    Taken unmodified from Request.getPart(String).
    Collection<jakarta.servlet.http.Part>
    Taken unmodified from Request.getParts().
    protected void
    Taken unmodified from StandardMultipartHttpServletRequest.handleParseFailure(Throwable).
    protected void
    Taken unmodified from StandardMultipartHttpServletRequest.initializeMultipart().
    void
    setCreateUploadTargets(boolean createUploadTargets)
     
    void
    setMaxParameterCount(int maxParameterCount)
     
    void
    setMaxPostSize(int maxPostSize)
     
    setMultipartConfigElement(jakarta.servlet.MultipartConfigElement mce)
     

    Methods inherited from class org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest

    getFile, getFileMap, getFileNames, getFiles, getMultiFileMap, getMultipartFiles, getRequest, getRequestHeaders, getRequestMethod, isResolved, setMultipartFiles

    Methods inherited from class jakarta.servlet.http.HttpServletRequestWrapper

    authenticate, changeSessionId, getAuthType, getContextPath, getCookies, getDateHeader, getHeader, getHeaderNames, getHeaders, getHttpServletMapping, getIntHeader, getMethod, getPathInfo, getPathTranslated, getQueryString, getRemoteUser, getRequestedSessionId, getRequestURI, getRequestURL, getServletPath, getSession, getSession, getTrailerFields, getUserPrincipal, isRequestedSessionIdFromCookie, isRequestedSessionIdFromURL, isRequestedSessionIdValid, isTrailerFieldsReady, isUserInRole, login, logout, newPushBuilder, upgrade

    Methods inherited from class jakarta.servlet.ServletRequestWrapper

    getAsyncContext, getAttribute, getAttributeNames, getCharacterEncoding, getContentLength, getContentLengthLong, getContentType, getDispatcherType, getInputStream, getLocalAddr, getLocale, getLocales, getLocalName, getLocalPort, getParameter, getProtocol, getProtocolRequestId, getReader, getRemoteAddr, getRemoteHost, getRemotePort, getRequestDispatcher, getRequestId, getScheme, getServerName, getServerPort, getServletConnection, getServletContext, isAsyncStarted, isAsyncSupported, isSecure, isWrapperFor, isWrapperFor, removeAttribute, setAttribute, setCharacterEncoding, setRequest, startAsync, startAsync

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface jakarta.servlet.http.HttpServletRequest

    authenticate, changeSessionId, getAuthType, getContextPath, getCookies, getDateHeader, getHeader, getHeaderNames, getHeaders, getHttpServletMapping, getIntHeader, getMethod, getPathInfo, getPathTranslated, getQueryString, getRemoteUser, getRequestedSessionId, getRequestURI, getRequestURL, getServletPath, getSession, getSession, getTrailerFields, getUserPrincipal, isRequestedSessionIdFromCookie, isRequestedSessionIdFromURL, isRequestedSessionIdValid, isTrailerFieldsReady, isUserInRole, login, logout, newPushBuilder, upgrade

    Methods inherited from interface jakarta.servlet.ServletRequest

    getAsyncContext, getAttribute, getAttributeNames, getCharacterEncoding, getContentLength, getContentLengthLong, getContentType, getDispatcherType, getInputStream, getLocalAddr, getLocale, getLocales, getLocalName, getLocalPort, getParameter, getProtocol, getProtocolRequestId, getReader, getRemoteAddr, getRemoteHost, getRemotePort, getRequestDispatcher, getRequestId, getScheme, getServerName, getServerPort, getServletConnection, getServletContext, isAsyncStarted, isAsyncSupported, isSecure, removeAttribute, setAttribute, setCharacterEncoding, startAsync, startAsync
  • Field Details

    • partsParseException

      protected Exception partsParseException
  • Constructor Details

    • LockssMultipartHttpServletRequest

      public LockssMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest request) throws org.springframework.web.multipart.MultipartException
      Create a new LockssMultipartHttpServletRequest wrapper for the given request, immediately parsing the multipart content.
      Parameters:
      request - the servlet request to wrap
      Throws:
      org.springframework.web.multipart.MultipartException - if parsing failed
    • LockssMultipartHttpServletRequest

      public LockssMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest request, boolean lazyParsing) throws org.springframework.web.multipart.MultipartException
      Create a new LockssMultipartHttpServletRequest wrapper for the given request.
      Parameters:
      request - the servlet request to wrap
      lazyParsing - whether multipart parsing should be triggered lazily on first access of multipart files or parameters
      Throws:
      org.springframework.web.multipart.MultipartException - if an immediate parsing attempt failed
  • Method Details

    • setMaxParameterCount

      public void setMaxParameterCount(int maxParameterCount)
    • getMaxParameterCount

      public int getMaxParameterCount()
    • setMaxPostSize

      public void setMaxPostSize(int maxPostSize)
    • getMaxPostSize

      public int getMaxPostSize()
    • setCreateUploadTargets

      public void setCreateUploadTargets(boolean createUploadTargets)
    • getCreateUploadTargets

      public boolean getCreateUploadTargets()
    • setMultipartConfigElement

      public LockssMultipartHttpServletRequest setMultipartConfigElement(jakarta.servlet.MultipartConfigElement mce)
    • getMultipartConfigElement

      public jakarta.servlet.MultipartConfigElement getMultipartConfigElement()
    • getCharset

      public Charset getCharset() throws UnsupportedEncodingException
      Taken unmodified from Request.getCharset().
      Throws:
      UnsupportedEncodingException
    • getParts

      public Collection<jakarta.servlet.http.Part> getParts() throws IOException, IllegalStateException, jakarta.servlet.ServletException
      Taken unmodified from Request.getParts().
      Specified by:
      getParts in interface jakarta.servlet.http.HttpServletRequest
      Overrides:
      getParts in class jakarta.servlet.http.HttpServletRequestWrapper
      Throws:
      IOException
      IllegalStateException
      jakarta.servlet.ServletException
    • handleParseFailure

      protected void handleParseFailure(Throwable ex)
      Taken unmodified from StandardMultipartHttpServletRequest.handleParseFailure(Throwable).
    • initializeMultipart

      protected void initializeMultipart()
      Taken unmodified from StandardMultipartHttpServletRequest.initializeMultipart().
      Overrides:
      initializeMultipart in class org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest
    • getParameterNames

      public Enumeration<String> getParameterNames()
      Taken unmodified from StandardMultipartHttpServletRequest.getParameterNames().
      Specified by:
      getParameterNames in interface jakarta.servlet.ServletRequest
      Overrides:
      getParameterNames in class jakarta.servlet.ServletRequestWrapper
    • getParameterValues

      public String[] getParameterValues(String name)
      Adapted from ServletRequestWrapper.getParameterValues(String), a parent class of StandardMultipartHttpServletRequest.
      Specified by:
      getParameterValues in interface jakarta.servlet.ServletRequest
      Overrides:
      getParameterValues in class jakarta.servlet.ServletRequestWrapper
    • getParameterMap

      public Map<String,String[]> getParameterMap()
      Taken unmodified from StandardMultipartHttpServletRequest.getParameterMap().
      Specified by:
      getParameterMap in interface jakarta.servlet.ServletRequest
      Overrides:
      getParameterMap in class jakarta.servlet.ServletRequestWrapper
    • getMultipartContentType

      public String getMultipartContentType(String paramOrFileName)
      Taken unmodified from StandardMultipartHttpServletRequest.getMultipartContentType(String).
    • getMultipartHeaders

      public org.springframework.http.HttpHeaders getMultipartHeaders(String paramOrFileName)
      Taken unmodified from StandardMultipartHttpServletRequest.getMultipartHeaders(String).
    • getPart

      public jakarta.servlet.http.Part getPart(String name) throws IOException, IllegalStateException, jakarta.servlet.ServletException
      Taken unmodified from Request.getPart(String).
      Specified by:
      getPart in interface jakarta.servlet.http.HttpServletRequest
      Overrides:
      getPart in class jakarta.servlet.http.HttpServletRequestWrapper
      Throws:
      IOException
      IllegalStateException
      jakarta.servlet.ServletException