View Javadoc

1   package org.fosstrak.epcis.repository.capture;
2   
3   import java.io.ByteArrayInputStream;
4   import java.io.IOException;
5   import java.io.InputStream;
6   
7   import javax.servlet.Filter;
8   import javax.servlet.FilterChain;
9   import javax.servlet.FilterConfig;
10  import javax.servlet.ServletException;
11  import javax.servlet.ServletInputStream;
12  import javax.servlet.ServletRequest;
13  import javax.servlet.ServletResponse;
14  import javax.servlet.http.HttpServletRequest;
15  import javax.servlet.http.HttpServletRequestWrapper;
16  
17  import org.apache.commons.fileupload.FileItemIterator;
18  import org.apache.commons.fileupload.FileItemStream;
19  import org.apache.commons.fileupload.servlet.ServletFileUpload;
20  import org.apache.commons.fileupload.util.Streams;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  /**
25   * This Filter implementation modifies the input stream of the servlet request
26   * if the request's contentType is <code>multipart/form-data</code> and removes
27   * the leading and trailing multipart HTML form overhead. Note that this is a
28   * Fosstrak extension and not part of the EPCIS specification.
29   * <p>
30   * The filter can be placed 'in front' of the EPCIS capture interface servlet,
31   * such that the capture interface can also be invoked from HTML pages using
32   * forms. That is, an HTML capture client can send an HTTP POST request using
33   * contentType <code>multipart/form-data</code> instead of the specified
34   * <code>text/xml</code> and this filter takes care of appropriately handling
35   * the request before it reaches the capture interface.
36   * 
37   * @author Marco Steybe
38   */
39  public class MultipartFormDataFilter implements Filter {
40  
41      private static final Log LOG = LogFactory.getLog(CaptureOperationsServlet.class);
42  
43      public void init(FilterConfig filterConfig) throws ServletException {
44          // nothing to do
45      }
46      
47      public void destroy() {
48          // nothing to do
49      }
50  
51      public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
52          // check that we have a file upload request
53          boolean isMultipart = ServletFileUpload.isMultipartContent((HttpServletRequest) req);
54          if (isMultipart) {
55              LOG.info("receiving capture request from an HTML client, replacing 'multipart/form-data' content with xml payload");
56              ServletFileUpload upload = new ServletFileUpload();
57              String event = null;
58              try {
59                  // parse the request
60                  FileItemIterator it = upload.getItemIterator((HttpServletRequest) req);
61                  while (it.hasNext()) {
62                      FileItemStream item = it.next();
63                      InputStream stream = item.openStream();
64                      if ("event".equals(item.getFieldName())) {
65                          LOG.debug("found 'event' multipart/form-data");
66                          event = Streams.asString(stream);
67                          req.setAttribute("xml", event);
68                      } else if (item.isFormField()) {
69                          // preserve the remaining attributes and pass them along as-is
70                          req.setAttribute(item.getFieldName(), Streams.asString(stream));
71                      } else {
72                          LOG.debug("found unexpected uploaded file");
73                      }
74                  }
75              } catch (Throwable e) {
76                  String msg = "unable to parse multipart/form-data, ignoring contents!";
77                  LOG.warn(msg, e);
78              }
79              if (event != null) {
80                  final InputStream xml = new ByteArrayInputStream(event.getBytes());
81                  req = new HttpServletRequestWrapper((HttpServletRequest) req) {
82                      @Override
83                      public ServletInputStream getInputStream() throws IOException {
84                         return new WrappedServletInputStream(xml);
85                      } 
86                   };
87                  chain.doFilter(req, resp);
88              }
89          } else {
90              chain.doFilter(req, resp);
91          }
92      }
93  
94      private class WrappedServletInputStream extends ServletInputStream {
95          private InputStream is;
96          public WrappedServletInputStream(InputStream is) {
97              this.is = is;
98          }
99          @Override
100         public int read() throws IOException {
101             return is.read();
102         }
103         @Override
104         public boolean markSupported() {
105             return false;
106         }
107         @Override
108         public synchronized void mark(int i) {
109             throw new RuntimeException(new IOException("mark not supported"));
110         }
111         @Override
112         public synchronized void reset() throws IOException {
113             throw new IOException("reset not supported");
114         }
115     }
116 }