content: /*
  *  Copyright Beijing 58 Information Technology Co.,Ltd.
  *
  *  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 com.bj58.argo.thirdparty.jetty;
  
  import javax.servlet.*;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletRequestWrapper;
  import javax.servlet.http.Part;
  import java.io.*;
  import java.util.*;
  
  /**
   * source: org.eclipse.jetty.servlets.MultiPartFilter
   * Multipart Form Data Filter.
   * <p>
   * This class decodes the multipart/form-data stream sent by a HTML form that uses a file input
   * item.  Any files sent are stored to a temporary file and a File object added to the request
   * as an attribute.  All other values are made available via the normal getParameter API and
   * the setCharacterEncoding mechanism is respected when converting bytes to Strings.
   * <p>
   * If the init parameter "delete" is set to "true", any files created will be deleted when the
   * current request returns.
   * <p>
   * The init parameter maxFormKeys sets the maximum number of keys that may be present in a
   * form (default set by system property org.eclipse.jetty.server.Request.maxFormKeys or 1000) to protect
   * against DOS attacks by bad hash keys.
   * <p>
   * The init parameter deleteFiles controls if uploaded files are automatically deleted after the request
   * completes.
   *
   * Use init parameter "maxFileSize" to set the max size file that can be uploaded.
   *
   * Use init parameter "maxRequestSize" to limit the size of the multipart request.
   *
   */
  public class JettyMultiPartRequestWrapper {
  
      public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
      private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
  
  
      private File tempdir;
      private boolean _deleteFiles;
      private ServletContext _context;
      private int _fileOutputBuffer = 0;
      private long _maxFileSize = -1L;
      private long _maxRequestSize = -1L;
      private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", 1000);
  
  
      public final static String __UTF8="UTF-8";
  
      public static int bufferSize = 64*1024;
  
  
  
      public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
              throws IOException, ServletException
      {
          HttpServletRequest srequest=(HttpServletRequest)request;
  
          // guard clause
          if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
          {
              return;
          }
  
          InputStream in = new BufferedInputStream(request.getInputStream());
          String content_type=srequest.getContentType();
  
          //Get current parameters so we can merge into them
          MultiMap params = new MultiMap();
          for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet())
          {
              Object value = entry.getValue();
              if (value instanceof String[])
                  params.addValues(entry.getKey(), (String[])value);
              else
                  params.add(entry.getKey(), value);
          }
  
          MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
          MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(in, content_type, config, tempdir);
          mpis.setDeleteOnExit(_deleteFiles);
          request.setAttribute(MULTIPART, mpis);
          try
          {
              Collection<Part> parts = mpis.getParts();
              if (parts != null)
              {
                  Iterator<Part> itor = parts.iterator();
                  while (itor.hasNext() && params.size() < _maxFormKeys)
                  {
                      Part p = itor.next();
                      MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
                      if (mp.getFile() != null)
                      {
                          request.setAttribute(mp.getName(),mp.getFile());
                          if (mp.getContentDispositionFilename() != null)
                          {
                              params.add(mp.getName(), mp.getContentDispositionFilename());
                              if (mp.getContentType() != null)
                                  params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
                          }
                      }
                      else
                      {
                          ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                          IoCopy(p.getInputStream(), bytes);
                          params.add(p.getName(), bytes.toByteArray());
                          if (p.getContentType() != null)
                              params.add(p.getName()+CONTENT_TYPE_SUFFIX, p.getContentType());
                      }
                  }
              }
  
              // handle request
              chain.doFilter(new Wrapper(srequest,params),response);
          }
          finally
          {
              deleteFiles(request);
          }
      }
  
      private void deleteFiles(ServletRequest request)
      {
          if (!_deleteFiles)
              return;
  
          MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)request.getAttribute(MULTIPART);
          if (mpis != null)
          {
              try
              {
                  mpis.deleteParts();
              }
              catch (Exception e)
              {
                  _context.log("Error deleting multipart tmp files", e);
              }
          }
          request.removeAttribute(MULTIPART);
      }
  
          /* ------------------------------------------------------------------- */
      /** Copy Stream in to Stream out until EOF or exception.
       */
      public static void IoCopy(InputStream in, OutputStream out)
              throws IOException
      {
          IoCopy(in, out, -1);
      }
  
          /* ------------------------------------------------------------------- */
      /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
       */
      public static void IoCopy(InputStream in,
                              OutputStream out,
                              long byteCount)
              throws IOException
      {
          byte buffer[] = new byte[bufferSize];
          int len=bufferSize;
  
          if (byteCount>=0)
          {
              while (byteCount>0)
              {
                  int max = byteCount<bufferSize?(int)byteCount:bufferSize;
                  len=in.read(buffer,0,max);
  
                  if (len==-1)
                      break;
  
                  byteCount -= len;
                  out.write(buffer,0,len);
              }
          }
          else
          {
              while (true)
              {
                  len=in.read(buffer,0,bufferSize);
                  if (len<0 )
                      break;
                  out.write(buffer,0,len);
              }
          }
      }
  
      /* ------------------------------------------------------------------------------- */
      /* ------------------------------------------------------------------------------- */
      private static class Wrapper extends HttpServletRequestWrapper
      {
          String _encoding=__UTF8;
          MultiMap<Object> _params;
  
          /* ------------------------------------------------------------------------------- */
          /** Constructor.
           * @param request
           */
          public Wrapper(HttpServletRequest request, MultiMap map)
          {
              super(request);
              this._params=map;
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#getContentLength()
           */
          @Override
          public int getContentLength()
          {
              return 0;
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
           */
          @Override
          public String getParameter(String name)
          {
              Object o=_params.get(name);
              if (!(o instanceof byte[]) && LazyList.size(o)>0)
                  o=LazyList.get(o,0);
  
              if (o instanceof byte[])
              {
                  try
                  {
                      return new String((byte[])o,_encoding);
                  }
                  catch(Exception e)
                  {
                      e.printStackTrace();
                  }
              }
              else if (o!=null)
                  return String.valueOf(o);
              return null;
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#getParameterMap()
           */
          @Override
          public Map<String, String[]> getParameterMap()
          {
              Map<String, String[]> cmap = new HashMap<String,String[]>();
  
              for ( Object key : _params.keySet() )
              {
                  String[] a = LazyList.toStringArray(getParameter((String)key));
                  cmap.put((String)key,a);
  
              }
  
              return Collections.unmodifiableMap(cmap);
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#getParameterNames()
           */
          @Override
          public Enumeration<String> getParameterNames()
          {
              return Collections.enumeration(_params.keySet());
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
           */
          @Override
          public String[] getParameterValues(String name)
          {
              List l=_params.getValues(name);
              if (l==null || l.size()==0)
                  return new String[0];
              String[] v = new String[l.size()];
              for (int i=0;i<l.size();i++)
              {
                  Object o=l.get(i);
                  if (o instanceof byte[])
                  {
                      try
                      {
                          v[i]=new String((byte[])o,_encoding);
                      }
                      catch(Exception e)
                      {
                          throw new RuntimeException(e);
                      }
                  }
                  else if (o instanceof String)
                      v[i]=(String)o;
              }
              return v;
          }
  
          /* ------------------------------------------------------------------------------- */
          /**
           * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
           */
          @Override
          public void setCharacterEncoding(String enc)
                  throws UnsupportedEncodingException
          {
              _encoding=enc;
          }
      }
  }
  