Package org.xlightweb

Source Code of org.xlightweb.MultipartFormDataRequest

/*
*  Copyright (c) xlightweb.org, 2008 - 2009. All rights reserved.
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xlightweb.org/
*/
package org.xlightweb;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

import org.xsocket.DataConverter;




/**
* A multipart/form-data request, which supports file uploads. Example:
*
* <pre>
*   MultipartFormDataRequest req = new MultipartFormDataRequest(url);
*   req.addPart("file", file);
*   req.addPart("description", "text/plain", "A unsigned ...");
*  
*   IHttpResponse resp = httpClient.call(req);
*   // ...
* </pre>
*
* see <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
*
* @author grro@xlightweb.org
*/
public class MultipartFormDataRequest extends HttpRequest  {
 
    private static final Logger LOG = Logger.getLogger(MultipartFormDataRequest.class.getName());

    private final String boundary;
    private final String dashBoundary;
    private final String closeDelimiter;
    private final Map<String, MultipartFormDataPart> parts = new HashMap<String, MultipartFormDataPart>();
   
    private boolean isModifyable;
    private AtomicBoolean isComplete = new AtomicBoolean(false);
   
   
  /**
   * constructor
   *
   * @param url   the url string
   * @throws MalformedURLException if the url is malformed
   */
  public MultipartFormDataRequest(String url) throws MalformedURLException, IOException {
    this(new HttpRequestHeader("POST", url), UUID.randomUUID().toString(), new InMemoryBodyDataSource(IHttpHeader.DEFAULT_ENCODING,HttpUtils.newMultimodeExecutor(), (ByteBuffer[]) null));
   
    isModifyable = true;
   
    super.setContentType("multipart/form-data; boundary=" + boundary);
        setContentLength(0);
  }
 
 
  private MultipartFormDataRequest(IHttpRequestHeader header, String boundary, NonBlockingBodyDataSource body) throws IOException {
      super(header);     
      setBodyDataSource(body);
     
      this.boundary = boundary;
      this.dashBoundary = "--" + boundary;
      closeDelimiter = "\r\n" + dashBoundary + "--";
  }

 
  /**
     * return true, if all parts is received completly
     * 
     * @return true, if all parts is received completly
     */
    boolean isComplete() {
        return isComplete.get();
    }

 
 
  void addPart(MultipartFormDataPart part) throws IOException {
      synchronized (parts) {
          parts.put(part.getDispositionParam("name"), part);
        }
  }
 
 
 
 
 
  IPart getPart(String name) throws IOException {
      throwExceptionIfnotComplete();
      return parts.get(name);
  }
 
 
  Map<String, IPart> getPartMap() throws IOException {
      throwExceptionIfnotComplete();
     
      HashMap<String, IPart> result = new HashMap<String, IPart>();
      for (Entry<String, MultipartFormDataPart> entry : parts.entrySet()) {
          result.put(entry.getKey(), entry.getValue());
        }
     
      return result;
  }
 
 
  Set<String> getPartnameSet() throws IOException {
      throwExceptionIfnotComplete();
      return Collections.unmodifiableSet(parts.keySet());
  }
 
  private void throwExceptionIfnotComplete() throws IOException {
      if (!isComplete.get()) {
          LOG.warning("request " + getRequestHeader() + " is not received completly (hint: set @InvokeOn(InvokeOn.MESSAGE_RECEIVED) or uses a IBodyCompleteListener)");
            throw new IOException("request is not received completly (hint: set @InvokeOn(InvokeOn.MESSAGE_RECEIVED) or uses a IBodyCompleteListener)");
        }
  }
 
 
  static boolean isMultipartFormDataRequest(IHttpRequest request) {
      if (!request.hasBody()) {
          return false;
      }
         
      String contentType = request.getContentType();
      if ((contentType != null) && (contentType.startsWith("multipart/form-data"))) {
          return true;
      }
     
      return false;
  }
 

 
 
  /**
   * adds a part
   *
   * @param name           the part name
   * @param content        the content
   * @throws IOException   if an exception occurs
   */
  public void addPart(String name, String content) throws IOException {
      addPart(name, content, "text/plain", getNonBlockingBody().getEncoding());
  }
 

  /**
   * adds a part
     *
     * @param name           the part name
   * @param contentType    the content type
     * @param content        the content
     * @throws IOException   if an exception occurs
   */
  public void addPart(String name, String contentType, String content) throws IOException {
        addPart(name, content, contentType, HttpUtils.parseEncoding(contentType, getNonBlockingBody().getEncoding()));
    }
   
 
 
  private void addPart(String name, String content, String contentType, String encoding) throws IOException {

      // create part header
        StringBuilder sb = new StringBuilder();
        sb.append(dashBoundary + "\r\n");
        sb.append("Content-Disposition: form-data; name=\"" + name + "\"\r\n");
        sb.append("Content-Type: " + contentType + "; charset=" + encoding + "\r\n");
        sb.append("\r\n");
       
        byte[] header = sb.toString().getBytes("US-ASCII");
       
       
        // create content
        ByteBuffer buffer = DataConverter.toByteBuffer(content, encoding);

       
        // add part
        addPart(DataConverter.toByteBuffer(header), buffer);
  }
     

 
  /**
   * adds a part
   * 
   * @param name           the part name
   * @param file           the file
   * @throws IOException   if an exception occurs
   */
  public void addPart(String name, File file) throws IOException {

      // create part header
      StringBuilder sb = new StringBuilder();
        sb.append(dashBoundary + "\r\n");
        sb.append("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + file.getName() + "\"\r\n");
        String contentType = HttpUtils.getContentTypeByFileExtension(file);
        if (contentType.startsWith("text")) {
          contentType = contentType + "; charset=" + getCharacterEncoding();
        }
        sb.append("Content-Type: " + contentType + "\r\n");
        sb.append("\r\n");
       
        byte[] header = sb.toString().getBytes("US-ASCII");
       
       
        // create content
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        FileChannel fc = raf.getChannel();

        ByteBuffer buffer = ByteBuffer.allocate((int) fc.size());
        fc.read(buffer);
        fc.close();
        raf.close();
        buffer.flip();
       
        // add part
        addPart(DataConverter.toByteBuffer(header), buffer);
  }
   
 

    private void addPart(ByteBuffer... part) throws IOException {
       
        if (!isModifyable) {
            throw new IOException("modifying a recevied message is not supported");           
        }
   
       
        int size = getNonBlockingBody().available();
        if (size < 0) {
            size = 0;
        }
       
       
        // remove close boundary if exists
        if (size > 0) {
            ByteBuffer[] oldContent = getNonBlockingBody().readByteBufferByLength(size);
           
            size = 0;
            for (int i = 0; i < oldContent.length; i++) {
               
                ByteBuffer buf = null;
               
                if (i == (oldContent.length - 1)) {
                    if ((closeDelimiter + "\r\n").equals(DataConverter.toString(oldContent[i].duplicate(), "US-ASCII"))) {
                        buf = DataConverter.toByteBuffer("\r\n", "US-ASCII");
                    } else {
                        buf = oldContent[i];
                    }
                   
                } else {
                    buf = oldContent[i];
                }
               
                if (buf != null) {
                    size += buf.remaining();
                    getNonBlockingBody().append(buf);
                }
            }
        }
       

        for (ByteBuffer buffer : part) {
            size += buffer.remaining();
        }
        getNonBlockingBody().append(part);
       

        // append close boundary
        StringBuilder sb = new StringBuilder(closeDelimiter + "\r\n");
        byte[] bound = sb.toString().getBytes("US-ASCII");
        getNonBlockingBody().append(ByteBuffer.wrap(bound));
        size = size + bound.length;
       
        // set new content length
        setContentLength(size);
    }
}
TOP

Related Classes of org.xlightweb.MultipartFormDataRequest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.