All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.io.MultipartRequest Maven / Gradle / Ivy

There is a newer version: 7.0.161
Show newest version
/*
 * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Codename One designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *  
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Codename One through http://www.codenameone.com/ if you 
 * need additional information or have any questions.
 */
package com.codename1.io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Vector;

/**
 * 

A multipart post request allows a developer to submit large binary data * files to the server in a multipart mime post request. This is a standard method * for large binary file uploads to webservers and data services.
* The sample code below includes both the client code using the upload capabilities as * well as a simple sample servlet that can accept multipart data: *

* * *

* The sample code below demonstrates uploading to the * filestack.com API.

* * * * @author Shai Almog */ public class MultipartRequest extends ConnectionRequest { /** * Special flag to keep input stream files open after they are read * @return the leaveInputStreamsOpen */ public static boolean isLeaveInputStreamsOpen() { return leaveInputStreamsOpen; } /** * Special flag to keep input stream files open after they are read * @param aLeaveInputStreamsOpen the leaveInputStreamsOpen to set */ public static void setLeaveInputStreamsOpen(boolean aLeaveInputStreamsOpen) { leaveInputStreamsOpen = aLeaveInputStreamsOpen; } private String boundary; private LinkedHashMap args = new LinkedHashMap(); private Hashtable filenames = new Hashtable(); private Hashtable filesizes = new Hashtable(); private Hashtable mimeTypes = new Hashtable(); private static final String CRLF = "\r\n"; private long contentLength = -1L; private boolean manualRedirect = true; private static boolean canFlushStream = true; private Vector ignoreEncoding = new Vector(); /** * Set to true to encode binary data as base 64 */ private boolean base64Binaries = true; /** * Special flag to keep input stream files open after they are read */ private static boolean leaveInputStreamsOpen; /** * Initialize variables */ public MultipartRequest() { setPost(true); setWriteRequest(true); // Just generate some unique random value. boundary = Long.toString(System.currentTimeMillis(), 16); // Line separator required by multipart/form-data. setContentType("multipart/form-data; boundary=" + boundary); } /** * Returns the boundary string which is normally generated based on system time * * @return the multipart boundary string */ public String getBoundary() { return boundary; } /** * Sets the boundary string, normally you don't need this method. Its useful to * workaround server issues only. Notice that this method must be invoked before adding * any elements. * @param boundary the boundary string */ public void setBoundary(String boundary) { this.boundary = boundary; setContentType("multipart/form-data; boundary=" + boundary); } protected void initConnection(Object connection) { contentLength = calculateContentLength(); addRequestHeader("Content-Length", Long.toString(contentLength)); super.initConnection(connection); } /** * Adds a binary argument to the arguments * @param name the name of the data * @param data the data as bytes * @param mimeType the mime type for the content */ public void addData(String name, byte[] data, String mimeType) { args.put(name, data); mimeTypes.put(name, mimeType); if(!filenames.containsKey(name)) { filenames.put(name, name); } filesizes.put(name, String.valueOf(data.length)); } /** * Adds a binary argument to the arguments * * @param name the name of the file data * @param filePath the path of the file to upload * @param mimeType the mime type for the content * @throws IOException if the file cannot be opened */ public void addData(String name, String filePath, String mimeType) throws IOException { addData(name, FileSystemStorage.getInstance().openInputStream(filePath), FileSystemStorage.getInstance().getLength(filePath), mimeType); } /** * Adds a binary argument to the arguments, notice the input stream will be * read only during submission * * @param name the name of the data * @param data the data stream * @param dataSize the byte size of the data stream, if the data stream is a file * the file size can be obtained using the * FileSystemStorage.getInstance().getLength(file) method * @param mimeType the mime type for the content */ public void addData(String name, InputStream data, long dataSize, String mimeType) { args.put(name, data); if(!filenames.containsKey(name)) { filenames.put(name, name); } filesizes.put(name, String.valueOf(dataSize)); mimeTypes.put(name, mimeType); } /** * Sets the filename for the given argument * @param arg the argument name * @param filename the file name */ public void setFilename(String arg, String filename) { filenames.put(arg, filename); } /** * {@inheritDoc} */ public void addArgumentNoEncoding(String key, String value) { args.put(key, value); if(!filenames.containsKey(key)) { filenames.put(key, key); } ignoreEncoding.addElement(key); } /** * {@inheritDoc} */ @Override public void addArgumentNoEncoding(String key, String[] value) { addArgument(key, value); ignoreEncoding.add(key); } /** * {@inheritDoc} */ @Override public void addArgumentNoEncodingArray(String key, String... value) { addArgumentNoEncoding(key, (String[])value); } /** * {@inheritDoc} */ public void addArgument(String name, String[] value) { args.put(name, value); } /** * {@inheritDoc} */ public void addArgument(String name, String value) { args.put(name, value); if(!filenames.containsKey(name)) { filenames.put(name, name); } } protected long calculateContentLength() { long length = 0L; Iterator e = args.keySet().iterator(); long dLength = "Content-Disposition: form-data; name=\"\"; filename=\"\"".length() + 2; // 2 = CRLF long ctLength = "Content-Type: ".length() + 2; // 2 = CRLF long cteLength = "Content-Transfer-Encoding: binary".length() + 4; // 4 = 2 * CRLF long bLength = boundary.length() + 4; // -- + boundary + CRLF long baseBinaryLength = dLength + ctLength + cteLength + bLength + 2; // 2 = CRLF at end of part dLength = "Content-Disposition: form-data; name=\"\"".length() + 2; // 2 = CRLF ctLength = "Content-Type: text/plain; charset=UTF-8".length() + 4; // 4 = 2 * CRLF long baseTextLength = dLength + ctLength + bLength + 2; // 2 = CRLF at end of part while(e.hasNext()) { String key = (String)e.next(); Object value = args.get(key); if(value instanceof String) { length += baseTextLength; length += key.length(); if(ignoreEncoding.contains(key)) { try { length += value.toString().getBytes("UTF-8").length; } catch (UnsupportedEncodingException ex) { length += value.toString().getBytes().length; } } else { if(base64Binaries) { length += Util.encodeBody((String)value).length(); } else { length += ((String)value).length(); } } } else { if(value instanceof String[]) { for(String s : (String[])value) { length += baseTextLength; length += key.length(); if(ignoreEncoding.contains(key)) { try { length += s.toString().getBytes("UTF-8").length; } catch (UnsupportedEncodingException ex) { length += value.toString().getBytes().length; } } else { if(base64Binaries) { length += Util.encodeBody(s).length(); } else { length += s.length(); } } } } else { length += baseBinaryLength; length += key.length(); try { length += ((String)filenames.get(key)).getBytes("UTF-8").length; } catch (UnsupportedEncodingException ex) { length += ((String)filenames.get(key)).getBytes().length; } length += ((String)mimeTypes.get(key)).length(); length += Long.parseLong((String)filesizes.get(key)); } } } length += bLength + 2; // same as part boundaries, suffixed with: -- return length; } /** * {@inheritDoc} */ protected void buildRequestBody(OutputStream os) throws IOException { Writer writer = null; writer = new OutputStreamWriter(os, "UTF-8"); Iterator e = args.keySet().iterator(); while(e.hasNext()) { if (shouldStop()) { break; } String key = (String)e.next(); Object value = args.get(key); writer.write("--"); writer.write(boundary); writer.write(CRLF); if(value instanceof String) { writer.write("Content-Disposition: form-data; name=\""); writer.write(key); writer.write("\""); writer.write(CRLF); writer.write("Content-Type: text/plain; charset=UTF-8"); writer.write(CRLF); writer.write(CRLF); if(canFlushStream){ writer.flush(); } if(ignoreEncoding.contains(key)) { writer.write((String)value); } else { if(base64Binaries) { writer.write(Util.encodeBody((String)value)); } else { writer.write((String)value); } } //writer.write(CRLF); if(canFlushStream){ writer.flush(); } } else { if(value instanceof String[]) { boolean first = true; for(String s : (String[])value) { if(!first) { writer.write(CRLF); writer.write("--"); writer.write(boundary); writer.write(CRLF); } first = false; writer.write("Content-Disposition: form-data; name=\""); writer.write(key); writer.write("\""); writer.write(CRLF); writer.write("Content-Type: text/plain; charset=UTF-8"); writer.write(CRLF); writer.write(CRLF); if(canFlushStream){ writer.flush(); } if(ignoreEncoding.contains(key)) { writer.write(s); } else { if(base64Binaries) { writer.write(Util.encodeBody(s)); } else { writer.write(s); } } //writer.write(CRLF); if(canFlushStream){ writer.flush(); } } } else { writer.write("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + filenames.get(key) +"\""); writer.write(CRLF); writer.write("Content-Type: "); writer.write((String)mimeTypes.get(key)); writer.write(CRLF); writer.write("Content-Transfer-Encoding: binary"); writer.write(CRLF); writer.write(CRLF); if(canFlushStream){ writer.flush(); } InputStream i; if (value instanceof InputStream) { i = (InputStream)value; } else { i = new ByteArrayInputStream((byte[])value); } byte[] buffer = new byte[8192]; int s = i.read(buffer); while(s > -1) { if (shouldStop()) { break; } os.write(buffer, 0, s); if(canFlushStream){ writer.flush(); } s = i.read(buffer); } if (value instanceof InputStream) { if(!leaveInputStreamsOpen) { Util.cleanup(i); } } else { Util.cleanup(i); } //args.remove(key); value = null; if(canFlushStream){ writer.flush(); } } } writer.write(CRLF); if(canFlushStream){ writer.flush(); } } writer.write("--" + boundary + "--"); writer.write(CRLF); writer.close(); } /* (non-Javadoc) * @see com.codename1.io.ConnectionRequest#getContentLength() */ public int getContentLength() { return (int)contentLength; } /* (non-Javadoc) * @see com.codename1.io.ConnectionRequest#onRedirect(java.lang.String) */ public boolean onRedirect(String url) { return manualRedirect; } /** * By default redirect responses (302 etc.) are handled manually in multipart requests * @return the autoRedirect */ public boolean isManualRedirect() { return manualRedirect; } /** * By default redirect responses (302 etc.) are handled manually in multipart requests, set this * to false to handle the redirect. Notice that a redirect converts a post to a get. * @param autoRedirect the autoRedirect to set */ public void setManualRedirect(boolean autoRedirect) { this.manualRedirect = autoRedirect; } /** * Sending large files requires flushing the writer once in a while to prevent * Out Of Memory Errors, Some J2ME implementation are not able to flush the * streams causing the upload to fail. * This method can indicate to the upload to not use the flushing mechanism. */ public static void setCanFlushStream(boolean flush){ canFlushStream = flush; } /** * Set to true to encode binary data as base 64 * @return the base64Binaries */ public boolean isBase64Binaries() { return base64Binaries; } /** * Set to true to encode binary data as base 64 * @param base64Binaries the base64Binaries to set */ public void setBase64Binaries(boolean base64Binaries) { this.base64Binaries = base64Binaries; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy