Mercurial Hosting > luan
changeset 725:a741a3a33423
add url support for multipart/form-data
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 08 Jun 2016 23:13:10 -0600 |
parents | 4f8e30a3ffd0 |
children | 14f136a4641f |
files | core/src/luan/modules/IoLuan.java core/src/luan/modules/LuanUrl.java core/src/luan/modules/url/LuanUrl.java core/src/luan/modules/url/MultiPartOutputStream.java core/src/luan/modules/url/MultipartClient.java http/src/luan/modules/http/HttpServicer.java |
diffstat | 6 files changed, 512 insertions(+), 269 deletions(-) [+] |
line wrap: on
line diff
--- a/core/src/luan/modules/IoLuan.java Tue Jun 07 16:00:41 2016 -0600 +++ b/core/src/luan/modules/IoLuan.java Wed Jun 08 23:13:10 2016 -0600 @@ -36,6 +36,7 @@ import luan.LuanFunction; import luan.LuanJavaFunction; import luan.LuanException; +import luan.modules.url.LuanUrl; public final class IoLuan { @@ -167,7 +168,7 @@ public static abstract class LuanIn { - abstract InputStream inputStream() throws IOException, LuanException; + public abstract InputStream inputStream() throws IOException, LuanException; public abstract String to_string(); public abstract String to_uri_string(); @@ -241,7 +242,7 @@ public static final LuanIn defaultStdin = new LuanIn() { - @Override InputStream inputStream() { + @Override public InputStream inputStream() { return System.in; } @@ -324,7 +325,7 @@ @Override public void write(int b) {} }; - @Override InputStream inputStream() { + @Override public InputStream inputStream() { return in; } @@ -349,7 +350,7 @@ this.s = s; } - @Override InputStream inputStream() { + @Override public InputStream inputStream() { throw new UnsupportedOperationException(); } @@ -407,7 +408,7 @@ this.file = file; } - @Override InputStream inputStream() throws IOException { + @Override public InputStream inputStream() throws IOException { return new FileInputStream(file); } @@ -621,7 +622,7 @@ this.socket = socket; } - @Override InputStream inputStream() throws IOException { + @Override public InputStream inputStream() throws IOException { return socket.getInputStream(); }
--- a/core/src/luan/modules/LuanUrl.java Tue Jun 07 16:00:41 2016 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -package luan.modules; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; -import java.net.HttpURLConnection; -import java.net.URLEncoder; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.Base64; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class LuanUrl extends IoLuan.LuanIn { - private static enum Method { GET, POST, DELETE } - - private URL url; - private Method method = Method.GET; - private Map headers; - private String content; - - LuanUrl(LuanState luan,URL url,LuanTable options) throws LuanException { - this.url = url; - if( options != null ) { - Map map = options.asMap(luan); - String methodStr = getString(map,"method"); - if( methodStr != null ) { - methodStr = methodStr.toUpperCase(); - try { - this.method = Method.valueOf(methodStr); - } catch(IllegalArgumentException e) { - throw new LuanException( "invalid method: "+methodStr ); - } - } - Map headerMap = getMap(luan,map,"headers"); - if( headerMap != null ) { - headers = new HashMap(); - for( Object hack : headerMap.entrySet() ) { - Map.Entry entry = (Map.Entry)hack; - String key = (String)entry.getKey(); - Object val = entry.getValue(); - String name = toHttpHeaderName(key); - if( val instanceof String ) { - headers.put(name,val); - } else { - if( !(val instanceof LuanTable) ) - throw new LuanException( "header '"+key+"' must be string or table" ); - LuanTable t = (LuanTable)val; - if( !t.isList() ) - throw new LuanException( "header '"+key+"' table must be list" ); - headers.put(name,t.asList()); - } - } - } - Map auth = getMap(luan,map,"authorization"); - if( auth != null ) { - if( headers!=null && headers.containsKey("Authorization") ) - throw new LuanException( "can't define authorization with header 'Authorization' defined" ); - String user = getString(auth,"user"); - String password = getString(auth,"password"); - if( !auth.isEmpty() ) - throw new LuanException( "unrecognized authorization options: "+auth ); - StringBuilder sb = new StringBuilder(); - if( user != null ) - sb.append(user); - sb.append(':'); - if( password != null ) - sb.append(password); - String val = "Basic " + Base64.getEncoder().encodeToString(sb.toString().getBytes()); - if( headers == null ) - headers = new HashMap(); - headers.put("Authorization",val); - } - Map params = getMap(luan,map,"parameters"); - if( params != null ) { - StringBuilder sb = new StringBuilder(); - for( Object hack : params.entrySet() ) { - Map.Entry entry = (Map.Entry)hack; - String key = (String)entry.getKey(); - Object val = entry.getValue(); - String keyEnc = encode(key); - if( val instanceof String ) { - and(sb); - sb.append( keyEnc ).append( '=' ).append( encode((String)val) ); - } else { - if( !(val instanceof LuanTable) ) - throw new LuanException( "parameter '"+key+"' must be string or table" ); - LuanTable t = (LuanTable)val; - if( !t.isList() ) - throw new LuanException( "parameter '"+key+"' table must be list" ); - for( Object obj : t.asList() ) { - if( !(obj instanceof String) ) - throw new LuanException( "parameter '"+key+"' values must be strings" ); - and(sb); - sb.append( keyEnc ).append( '=' ).append( encode((String)obj) ); - } - } - } - if( this.method==Method.DELETE ) - throw new LuanException( "the DELETE method cannot take parameters" ); - if( this.method==Method.POST ) { - content = sb.toString(); - } else { // GET - String urlS = this.url.toString(); - if( urlS.indexOf('?') == -1 ) { - urlS += '?'; - } else { - urlS += '&'; - } - urlS += sb; - try { - this.url = new URL(urlS); - } catch(IOException e) { - throw new RuntimeException(e); - } - } - } - if( !map.isEmpty() ) - throw new LuanException( "unrecognized options: "+map ); - } - } - - public static String toHttpHeaderName(String luanName) { - luanName = luanName.toLowerCase(); - StringBuilder buf = new StringBuilder(); - boolean capitalize = true; - char[] a = luanName.toCharArray(); - for( int i=0; i<a.length; i++ ) { - char c = a[i]; - if( c == '_' || c == '-' ) { - a[i] = '-'; - capitalize = true; - } else if( capitalize ) { - a[i] = Character.toUpperCase(c); - capitalize = false; - } - } - return String.valueOf(a); - } - - private static void and(StringBuilder sb) { - if( sb.length() > 0 ) - sb.append('&'); - } - - private static String encode(String s) { - try { - return URLEncoder.encode(s,"UTF-8"); - } catch(UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - private static String getString(Map map,String key) throws LuanException { - Object val = map.remove(key); - if( val!=null && !(val instanceof String) ) - throw new LuanException( "parameter '"+key+"' must be a string" ); - return (String)val; - } - - private static LuanTable getTable(Map map,String key) throws LuanException { - Object val = map.remove(key); - if( val!=null && !(val instanceof LuanTable) ) - throw new LuanException( "parameter '"+key+"' must be a table" ); - return (LuanTable)val; - } - - private static Map getMap(LuanState luan,Map map,String key) throws LuanException { - LuanTable t = getTable(map,key); - return t==null ? null : t.asMap(luan); - } - - @Override InputStream inputStream() throws IOException, LuanException { - URLConnection con = url.openConnection(); - if( headers != null ) { - for( Object hack : headers.entrySet() ) { - Map.Entry entry = (Map.Entry)hack; - String key = (String)entry.getKey(); - Object val = entry.getValue(); - if( val instanceof String ) { - con.addRequestProperty(key,(String)val); - } else { - List list = (List)val; - for( Object obj : list ) { - con.addRequestProperty(key,(String)obj); - } - } - } - } - if( method==Method.GET ) { - return con.getInputStream(); - } - - HttpURLConnection httpCon = (HttpURLConnection)con; - - if( method==Method.DELETE ) { - httpCon.setRequestMethod("DELETE"); - return httpCon.getInputStream(); - } - - // POST - -// httpCon.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); - httpCon.setDoOutput(true); - httpCon.setRequestMethod("POST"); - - byte[] post = content.getBytes(); -// httpCon.setRequestProperty("Content-Length",Integer.toString(post.length)); - OutputStream out = httpCon.getOutputStream(); - out.write(post); - out.flush(); - try { - try { - return httpCon.getInputStream(); - } catch(IOException e) { - InputStream is = httpCon.getErrorStream(); - if( is == null ) - throw e; - Reader in = new InputStreamReader(is); - String msg = Utils.readAll(in); - in.close(); - throw new LuanException(msg,e); - } - } finally { - out.close(); - } - } - - @Override public String to_string() { - return url.toString(); - } - - @Override public String to_uri_string() { - return url.toString(); - } -/* - public String post(String postS) throws IOException { - return new UrlCall(url).post(postS); - } - - @Override public LuanTable table() { - LuanTable tbl = super.table(); - try { - tbl.rawPut( "post", new LuanJavaFunction( - LuanUrl.class.getMethod( "post", String.class ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } -*/ -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/url/LuanUrl.java Wed Jun 08 23:13:10 2016 -0600 @@ -0,0 +1,275 @@ +package luan.modules.url; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Base64; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanJavaFunction; +import luan.LuanException; +import luan.modules.IoLuan; +import luan.modules.Utils; + + +public final class LuanUrl extends IoLuan.LuanIn { + + private static enum Method { GET, POST, DELETE } + + private URL url; + private Method method = Method.GET; + private Map headers; + private String content = null; + private MultipartClient multipart = null; + + public LuanUrl(LuanState luan,URL url,LuanTable options) throws LuanException { + this.url = url; + if( options != null ) { + Map map = options.asMap(luan); + String methodStr = getString(map,"method"); + if( methodStr != null ) { + methodStr = methodStr.toUpperCase(); + try { + this.method = Method.valueOf(methodStr); + } catch(IllegalArgumentException e) { + throw new LuanException( "invalid method: "+methodStr ); + } + } + Map headerMap = getMap(luan,map,"headers"); + if( headerMap != null ) { + headers = new HashMap(); + for( Object hack : headerMap.entrySet() ) { + Map.Entry entry = (Map.Entry)hack; + String key = (String)entry.getKey(); + Object val = entry.getValue(); + String name = toHttpHeaderName(key); + if( val instanceof String ) { + headers.put(name,val); + } else { + if( !(val instanceof LuanTable) ) + throw new LuanException( "header '"+key+"' must be string or table" ); + LuanTable t = (LuanTable)val; + if( !t.isList() ) + throw new LuanException( "header '"+key+"' table must be list" ); + headers.put(name,t.asList()); + } + } + } + Map auth = getMap(luan,map,"authorization"); + if( auth != null ) { + if( headers!=null && headers.containsKey("Authorization") ) + throw new LuanException( "can't define authorization with header 'Authorization' defined" ); + String user = getString(auth,"user"); + String password = getString(auth,"password"); + if( !auth.isEmpty() ) + throw new LuanException( "unrecognized authorization options: "+auth ); + StringBuilder sb = new StringBuilder(); + if( user != null ) + sb.append(user); + sb.append(':'); + if( password != null ) + sb.append(password); + String val = "Basic " + Base64.getEncoder().encodeToString(sb.toString().getBytes()); + if( headers == null ) + headers = new HashMap(); + headers.put("Authorization",val); + } + Map params = getMap(luan,map,"parameters"); + if( params != null ) { + if( this.method==Method.POST && "multipart/form-data".equals(headers.get("Content-Type")) ) { + multipart = new MultipartClient(params); + } else { + StringBuilder sb = new StringBuilder(); + for( Object hack : params.entrySet() ) { + Map.Entry entry = (Map.Entry)hack; + String key = (String)entry.getKey(); + Object val = entry.getValue(); + String keyEnc = encode(key); + if( val instanceof String ) { + and(sb); + sb.append( keyEnc ).append( '=' ).append( encode((String)val) ); + } else { + if( !(val instanceof LuanTable) ) + throw new LuanException( "parameter '"+key+"' must be string or table" ); + LuanTable t = (LuanTable)val; + if( !t.isList() ) + throw new LuanException( "parameter '"+key+"' table must be list" ); + for( Object obj : t.asList() ) { + if( !(obj instanceof String) ) + throw new LuanException( "parameter '"+key+"' values must be strings" ); + and(sb); + sb.append( keyEnc ).append( '=' ).append( encode((String)obj) ); + } + } + } + if( this.method==Method.DELETE ) + throw new LuanException( "the DELETE method cannot take parameters" ); + if( this.method==Method.POST ) { + content = sb.toString(); + } else { // GET + String urlS = this.url.toString(); + if( urlS.indexOf('?') == -1 ) { + urlS += '?'; + } else { + urlS += '&'; + } + urlS += sb; + try { + this.url = new URL(urlS); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + } + } + if( !map.isEmpty() ) + throw new LuanException( "unrecognized options: "+map ); + } + } + + public static String toHttpHeaderName(String luanName) { + luanName = luanName.toLowerCase(); + StringBuilder buf = new StringBuilder(); + boolean capitalize = true; + char[] a = luanName.toCharArray(); + for( int i=0; i<a.length; i++ ) { + char c = a[i]; + if( c == '_' || c == '-' ) { + a[i] = '-'; + capitalize = true; + } else if( capitalize ) { + a[i] = Character.toUpperCase(c); + capitalize = false; + } + } + return String.valueOf(a); + } + + private static void and(StringBuilder sb) { + if( sb.length() > 0 ) + sb.append('&'); + } + + private static String encode(String s) { + try { + return URLEncoder.encode(s,"UTF-8"); + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private static String getString(Map map,String key) throws LuanException { + Object val = map.remove(key); + if( val!=null && !(val instanceof String) ) + throw new LuanException( "parameter '"+key+"' must be a string" ); + return (String)val; + } + + private static LuanTable getTable(Map map,String key) throws LuanException { + Object val = map.remove(key); + if( val!=null && !(val instanceof LuanTable) ) + throw new LuanException( "parameter '"+key+"' must be a table" ); + return (LuanTable)val; + } + + private static Map getMap(LuanState luan,Map map,String key) throws LuanException { + LuanTable t = getTable(map,key); + return t==null ? null : t.asMap(luan); + } + + @Override public InputStream inputStream() throws IOException, LuanException { + URLConnection con = url.openConnection(); + if( headers != null ) { + for( Object hack : headers.entrySet() ) { + Map.Entry entry = (Map.Entry)hack; + String key = (String)entry.getKey(); + Object val = entry.getValue(); + if( val instanceof String ) { + con.addRequestProperty(key,(String)val); + } else { + List list = (List)val; + for( Object obj : list ) { + con.addRequestProperty(key,(String)obj); + } + } + } + } + if( method==Method.GET ) { + return con.getInputStream(); + } + + HttpURLConnection httpCon = (HttpURLConnection)con; + + if( method==Method.DELETE ) { + httpCon.setRequestMethod("DELETE"); + return httpCon.getInputStream(); + } + + // POST + +// httpCon.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); + httpCon.setDoOutput(true); + httpCon.setRequestMethod("POST"); + + OutputStream out; + if( multipart != null ) { + out = multipart.write(httpCon); + } else { + byte[] post = content.getBytes(); +// httpCon.setRequestProperty("Content-Length",Integer.toString(post.length)); + out = httpCon.getOutputStream(); + out.write(post); + out.flush(); + } + try { + try { + return httpCon.getInputStream(); + } catch(IOException e) { + InputStream is = httpCon.getErrorStream(); + if( is == null ) + throw e; + Reader in = new InputStreamReader(is); + String msg = Utils.readAll(in); + in.close(); + throw new LuanException(msg,e); + } + } finally { + out.close(); + } + } + + @Override public String to_string() { + return url.toString(); + } + + @Override public String to_uri_string() { + return url.toString(); + } +/* + public String post(String postS) throws IOException { + return new UrlCall(url).post(postS); + } + + @Override public LuanTable table() { + LuanTable tbl = super.table(); + try { + tbl.rawPut( "post", new LuanJavaFunction( + LuanUrl.class.getMethod( "post", String.class ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } +*/ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/url/MultiPartOutputStream.java Wed Jun 08 23:13:10 2016 -0600 @@ -0,0 +1,146 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// +// This horrible broken code from jetty is just here for me to look at. It isn't used. -fschmidt + +package luan.modules.url; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + + +/* ================================================================ */ +/** Handle a multipart MIME response. + * + * + * +*/ +public class MultiPartOutputStream extends FilterOutputStream +{ + /* ------------------------------------------------------------ */ + private static final byte[] __CRLF={'\r','\n'}; + private static final byte[] __DASHDASH={'-','-'}; + + public static String MULTIPART_MIXED="multipart/mixed"; + public static String MULTIPART_X_MIXED_REPLACE="multipart/x-mixed-replace"; + public static final String __ISO_8859_1="ISO-8859-1"; + + public static String newBoundary(Object obj) { + return "jetty"+System.identityHashCode(obj)+ + Long.toString(System.currentTimeMillis(),36); + } + + /* ------------------------------------------------------------ */ + private final String boundary; + private final byte[] boundaryBytes; + + /* ------------------------------------------------------------ */ + private boolean inPart=false; + + /* ------------------------------------------------------------ */ + public MultiPartOutputStream(OutputStream out,String boundary) + throws IOException + { + super(out); + + this.boundary = boundary; + boundaryBytes=boundary.getBytes(__ISO_8859_1); + + inPart=false; + } + + + + /* ------------------------------------------------------------ */ + /** End the current part. + * @exception IOException IOException + */ + @Override + public void close() + throws IOException + { + if (inPart) + out.write(__CRLF); + out.write(__DASHDASH); + out.write(boundaryBytes); + out.write(__DASHDASH); + out.write(__CRLF); + inPart=false; + super.close(); + } + + /* ------------------------------------------------------------ */ + public String getBoundary() + { + return boundary; + } + + public OutputStream getOut() {return out;} + + /* ------------------------------------------------------------ */ + /** Start creation of the next Content. + */ + public void startPart(String contentType) + throws IOException + { + if (inPart) + out.write(__CRLF); + inPart=true; + out.write(__DASHDASH); + out.write(boundaryBytes); + out.write(__CRLF); + if (contentType != null) + out.write(("Content-Type: "+contentType).getBytes(__ISO_8859_1)); + out.write(__CRLF); + out.write(__CRLF); + } + + /* ------------------------------------------------------------ */ + /** Start creation of the next Content. + */ + public void startPart(String contentType, String[] headers) + throws IOException + { + if (inPart) + out.write(__CRLF); + inPart=true; + out.write(__DASHDASH); + out.write(boundaryBytes); + out.write(__CRLF); + if (contentType != null) + out.write(("Content-Type: "+contentType).getBytes(__ISO_8859_1)); + out.write(__CRLF); + for (int i=0;headers!=null && i<headers.length;i++) + { + out.write(headers[i].getBytes(__ISO_8859_1)); + out.write(__CRLF); + } + out.write(__CRLF); + } + + /* ------------------------------------------------------------ */ + @Override + public void write(byte[] b, int off, int len) throws IOException + { + out.write(b,off,len); + } +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/url/MultipartClient.java Wed Jun 08 23:13:10 2016 -0600 @@ -0,0 +1,76 @@ +package luan.modules.url; + +import java.io.OutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import luan.LuanTable; +import luan.LuanException; + + +public final class MultipartClient { + private static final byte[] __CRLF = {'\r','\n'}; + private static final byte[] __DASHDASH = {'-','-'}; + private static final String __ISO_8859_1 = "ISO-8859-1"; + + private final Map params = new HashMap(); + + MultipartClient(Map params) throws LuanException { + for( Object hack : params.entrySet() ) { + Map.Entry entry = (Map.Entry)hack; + String key = (String)entry.getKey(); + Object val = entry.getValue(); + List list = new ArrayList(); + if( val instanceof String ) { + list.add(val); + } else { + if( !(val instanceof LuanTable) ) + throw new LuanException( "parameter '"+key+"' must be string or table" ); + LuanTable t = (LuanTable)val; + if( !t.isList() ) + throw new LuanException( "parameter '"+key+"' table must be list" ); + for( Object obj : t.asList() ) { + if( !(obj instanceof String) ) + throw new LuanException( "parameter '"+key+"' values must be strings" ); + list.add(obj); + } + } + this.params.put(key,list); + } + } + + public OutputStream write(HttpURLConnection httpCon) throws IOException { + String boundary = "luan" + System.identityHashCode(this) + Long.toString(System.currentTimeMillis(),36); + byte[] boundaryBytes = boundary.getBytes(__ISO_8859_1); + + httpCon.setRequestProperty("Content-Type","multipart/form-data; boundary="+boundary); + OutputStream out = httpCon.getOutputStream(); + for( Object hack : params.entrySet() ) { + Map.Entry entry = (Map.Entry)hack; + String name = (String)entry.getKey(); + List list = (List)entry.getValue(); + for( Object obj : list ) { + String val = (String)obj; + out.write(__DASHDASH); + out.write(boundaryBytes); + out.write(__CRLF); +// if (contentType != null) +// out.write(("Content-Type: "+contentType).getBytes(__ISO_8859_1)); +// out.write(__CRLF); + out.write(("Content-Disposition: form-data; name=\""+name+"\"").getBytes(__ISO_8859_1)); + out.write(__CRLF); + out.write(__CRLF); + out.write(val.getBytes()); + out.write(__CRLF); + } + } + out.write(__DASHDASH); + out.write(boundaryBytes); + out.write(__DASHDASH); + out.write(__CRLF); + return out; + } +}
--- a/http/src/luan/modules/http/HttpServicer.java Tue Jun 07 16:00:41 2016 -0600 +++ b/http/src/luan/modules/http/HttpServicer.java Wed Jun 08 23:13:10 2016 -0600 @@ -33,9 +33,9 @@ import luan.DeepCloner; import luan.modules.PackageLuan; import luan.modules.IoLuan; -import luan.modules.LuanUrl; import luan.modules.TableLuan; import luan.modules.Utils; +import luan.modules.url.LuanUrl; public final class HttpServicer { @@ -108,6 +108,13 @@ for( Part p : mpis.getParts() ) { final MultiPartInputStream.MultiPart part = (MultiPartInputStream.MultiPart)p; String name = part.getName(); +/* +System.out.println("name = "+name); +System.out.println("getContentType = "+part.getContentType()); +System.out.println("getHeaderNames = "+part.getHeaderNames()); +System.out.println("content-disposition = "+part.getHeader("content-disposition")); +System.out.println(); +*/ Object value; String filename = part.getContentDispositionFilename(); if( filename == null ) {