Some progress on fileupload

This commit is contained in:
Ziver Koc 2016-07-13 17:22:11 +02:00
parent f2939f819f
commit 5606f57514
17 changed files with 193 additions and 116 deletions

View file

@ -26,6 +26,7 @@
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$MODULE_DIR$/lib" /> <root url="file://$MODULE_DIR$/lib" />
<root url="jar://$USER_HOME$/.ideaLibSources/commons-fileupload-1.2.1-sources.jar!/" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$MODULE_DIR$/lib" recursive="false" /> <jarDirectory url="file://$MODULE_DIR$/lib" recursive="false" />
<jarDirectory url="file://$MODULE_DIR$/lib" recursive="false" type="SOURCES" /> <jarDirectory url="file://$MODULE_DIR$/lib" recursive="false" type="SOURCES" />

Binary file not shown.

BIN
lib/commons-io-2.5.jar Executable file

Binary file not shown.

View file

@ -41,7 +41,7 @@ public class IOUtil {
* @param stream * @param stream
* @return the stream contents * @return the stream contents
*/ */
public static byte[] getContent(InputStream stream) throws IOException{ public static byte[] readContent(InputStream stream) throws IOException{
DynamicByteArrayStream dyn_buff = new DynamicByteArrayStream(); DynamicByteArrayStream dyn_buff = new DynamicByteArrayStream();
byte[] buff = new byte[8192]; byte[] buff = new byte[8192];
int len = 0; int len = 0;
@ -60,8 +60,8 @@ public class IOUtil {
* @param stream * @param stream
* @return a String with the content of the stream * @return a String with the content of the stream
*/ */
public static String getContentAsString(InputStream stream) throws IOException{ public static String readContentAsString(InputStream stream) throws IOException{
return getContentAsString(new InputStreamReader(stream)); return readContentAsString(new InputStreamReader(stream));
} }
/** /**
@ -71,7 +71,7 @@ public class IOUtil {
* @param reader * @param reader
* @return a String with the content of the stream * @return a String with the content of the stream
*/ */
public static String getContentAsString(Reader reader) throws IOException{ public static String readContentAsString(Reader reader) throws IOException{
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
BufferedReader in = null; BufferedReader in = null;
if(reader instanceof BufferedReader) if(reader instanceof BufferedReader)
@ -89,7 +89,8 @@ public class IOUtil {
} }
/** /**
* Reads on line terminated by a new line or carriage return from a stream. * Reads one line terminated by a new line or carriage return from a stream.
* Will only read ASCII based char streams.
* *
* @param in the stream to read from * @param in the stream to read from
* @return a String that contains one line excluding line terminating * @return a String that contains one line excluding line terminating
@ -106,6 +107,26 @@ public class IOUtil {
return null; // End of the stream return null; // End of the stream
return str.toString(); return str.toString();
} }
/**
* Reads one line terminated by a new line or carriage return from a Reader.
* Will only read ASCII based char streams.
*
* @param in the Reader to read from
* @return a String that contains one line excluding line terminating
* characters, null if it is the end of the stream
*/
public static String readLine(Reader in) throws IOException {
StringBuilder str = new StringBuilder(80);
int c = 0;
while ((c=in.read()) >= 0 && (c != '\n') && (c != '\r'))
str.append((char)c);
if (c == '\r')
in.read(); // if the last char is carriage return we assume the next char in the stream will be new line so skip it
if (c == -1 && str.length() == 0)
return null; // End of the stream
return str.toString();
}
/** /**
* Copies all data from one InputStream to another OutputStream. * Copies all data from one InputStream to another OutputStream.

View file

@ -163,7 +163,7 @@ public class FileUtil {
} }
public static byte[] getByteContent(File file) throws IOException { public static byte[] getByteContent(File file) throws IOException {
InputStream in = new FileInputStream(file); InputStream in = new FileInputStream(file);
byte[] data = IOUtil.getContent(in); byte[] data = IOUtil.readContent(in);
in.close(); in.close();
return data; return data;
} }
@ -176,7 +176,7 @@ public class FileUtil {
*/ */
public static String getContent(URL url) throws IOException{ public static String getContent(URL url) throws IOException{
InputStream in = url.openStream(); InputStream in = url.openStream();
String data = new String(IOUtil.getContent(in)); String data = new String(IOUtil.readContent(in));
in.close(); in.close();
return data; return data;
} }

4
src/zutil/net/FTPClient.java Normal file → Executable file
View file

@ -175,7 +175,7 @@ public class FTPClient extends Thread{
BufferedInputStream data_in = getDataInputStream(); BufferedInputStream data_in = getDataInputStream();
sendCommand("NLST "+path); sendCommand("NLST "+path);
String data = new String(IOUtil.getContent(data_in)); String data = new String(IOUtil.readContent(data_in));
data_in.close(); data_in.close();
readCommand(); readCommand();
@ -194,7 +194,7 @@ public class FTPClient extends Thread{
BufferedInputStream data_in = getDataInputStream(); BufferedInputStream data_in = getDataInputStream();
sendCommand("LIST "+path); sendCommand("LIST "+path);
String data = new String(IOUtil.getContent(data_in)); String data = new String(IOUtil.readContent(data_in));
data_in.close(); data_in.close();
readCommand(); readCommand();

View file

@ -26,6 +26,7 @@ package zutil.net.http;
import zutil.net.http.HttpPrintStream.HttpMessageType; import zutil.net.http.HttpPrintStream.HttpMessageType;
import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -52,8 +53,8 @@ public class HttpClient implements AutoCloseable{
private String data; private String data;
// Response variables // Response variables
private HttpHeaderParser rspHeader; private HttpHeaderParser rspHeader;
private BufferedReader rspReader; private BufferedInputStream rspReader;
@ -128,7 +129,7 @@ public class HttpClient implements AutoCloseable{
// Response // Response
if(rspHeader != null || rspReader != null) // Close previous request if(rspHeader != null || rspReader != null) // Close previous request
this.close(); this.close();
rspReader = new BufferedReader(new InputStreamReader(conn.getInputStream())); rspReader = new BufferedInputStream(conn.getInputStream());
rspHeader = new HttpHeaderParser( rspReader ); rspHeader = new HttpHeaderParser( rspReader );
return rspHeader; return rspHeader;
@ -137,7 +138,7 @@ public class HttpClient implements AutoCloseable{
public HttpHeaderParser getResponseHeader(){ public HttpHeaderParser getResponseHeader(){
return rspHeader; return rspHeader;
} }
public BufferedReader getResponseReader(){ public BufferedInputStream getResponseReader(){
return rspReader; return rspReader;
} }

View file

@ -26,6 +26,8 @@ package zutil.net.http;
import zutil.converter.Converter; import zutil.converter.Converter;
import java.io.BufferedReader;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -37,6 +39,7 @@ public class HttpHeader {
private HashMap<String, String> urlAttributes; private HashMap<String, String> urlAttributes;
private float version; private float version;
private int httpCode; private int httpCode;
private InputStream in;
// Parameters // Parameters
private HashMap<String, String> headers; private HashMap<String, String> headers;
@ -51,13 +54,13 @@ public class HttpHeader {
/** /**
* @return true if this header represents a server response * @return true if this header represents a server response
*/ */
public boolean isResponse(){ public boolean isResponse(){
return !request; return !request;
} }
/** /**
* @return true if this header represents a client request * @return true if this header represents a client request
*/ */
public boolean isRequest(){ public boolean isRequest(){
return request; return request;
@ -103,47 +106,47 @@ public class HttpHeader {
return null; return null;
} }
/** /**
* @return a Iterator with all defined url keys * @return a Iterator with all defined url keys
*/ */
public Iterator<String> getURLAttributeKeys(){ public Iterator<String> getURLAttributeKeys(){
return urlAttributes.keySet().iterator(); return urlAttributes.keySet().iterator();
} }
/** /**
* Returns the URL attribute value of the given name. * @return the URL attribute value of the given name. null if there is no such attribute
*
* returns null if there is no such attribute
*/ */
public String getURLAttribute(String name){ public String getURLAttribute(String name){
return urlAttributes.get( name ); return urlAttributes.get( name );
} }
/** /**
* @return a Iterator with all defined headers * @return a Iterator with all defined headers
*/ */
public Iterator<String> getHeaderKeys(){ public Iterator<String> getHeaderKeys(){
return headers.keySet().iterator(); return headers.keySet().iterator();
} }
/** /**
* Returns the HTTP attribute value of the given name. * @return the HTTP attribute value of the given name. null if there is no such attribute
*
* returns null if there is no such attribute
*/ */
public String getHeader(String name){ public String getHeader(String name){
return headers.get( name.toUpperCase() ); return headers.get( name.toUpperCase() );
} }
/** /**
* @return a Iterator with all defined cookies * @return a Iterator with all defined cookies
*/ */
public Iterator<String> getCookieKeys(){ public Iterator<String> getCookieKeys(){
return cookies.keySet().iterator(); return cookies.keySet().iterator();
} }
/** /**
* Returns the cookie value of the given name. * @return the cookie value of the given name. null if there is no such attribute.
*
* returns null if there is no such attribute
*/ */
public String getCookie(String name){ public String getCookie(String name){
return cookies.get( name ); return cookies.get( name );
} }
/**
* @return a Reader that contains the body of the http request.
*/
public InputStream getInputStream(){
return in;
}
protected void setIsRequest(boolean request) { this.request = request; } protected void setIsRequest(boolean request) { this.request = request; }
@ -159,6 +162,9 @@ public class HttpHeader {
protected void setRequestURL(String url){ protected void setRequestURL(String url){
this.url = url.trim().replaceAll("//", "/"); this.url = url.trim().replaceAll("//", "/");
} }
protected void setInputStream(InputStream in){
this.in = in;
}
protected HashMap<String,String> getHeaderMap(){ protected HashMap<String,String> getHeaderMap(){
return headers; return headers;

View file

@ -24,17 +24,18 @@
package zutil.net.http; package zutil.net.http;
import com.mysql.jdbc.Buffer;
import zutil.StringUtil; import zutil.StringUtil;
import zutil.io.IOUtil;
import zutil.io.StringInputStream;
import zutil.parser.URLDecoder; import zutil.parser.URLDecoder;
import java.io.BufferedReader; import java.io.*;
import java.io.IOException;
import java.io.StringReader;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class HttpHeaderParser { public class HttpHeaderParser {
public static final String HEADER_COOKIE = "COOKIE"; private static final String HEADER_COOKIE = "COOKIE";
private static final Pattern PATTERN_COLON = Pattern.compile(":"); private static final Pattern PATTERN_COLON = Pattern.compile(":");
private static final Pattern PATTERN_EQUAL = Pattern.compile("="); private static final Pattern PATTERN_EQUAL = Pattern.compile("=");
@ -42,7 +43,7 @@ public class HttpHeaderParser {
private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";"); private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
private BufferedReader in; private InputStream in;
private boolean readStatusLine; private boolean readStatusLine;
@ -51,8 +52,8 @@ public class HttpHeaderParser {
* *
* @param in is the stream * @param in is the stream
*/ */
public HttpHeaderParser(BufferedReader in){ public HttpHeaderParser(InputStream in){
this.in = in; this.in = in;
this.readStatusLine = true; this.readStatusLine = true;
} }
@ -62,28 +63,29 @@ public class HttpHeaderParser {
* @param in is the String * @param in is the String
*/ */
public HttpHeaderParser(String in){ public HttpHeaderParser(String in){
this(new BufferedReader(new StringReader(in))); this(new StringInputStream(in));
} }
public HttpHeader read() throws IOException { public HttpHeader read() throws IOException {
HttpHeader header = new HttpHeader(); HttpHeader header = new HttpHeader();
String line = null; String line;
// First line // First line
if (readStatusLine) { if (readStatusLine) {
if( (line=in.readLine()) != null && !line.isEmpty() ) if( (line= IOUtil.readLine(in)) != null && !line.isEmpty() )
parseStatusLine(header, line); parseStatusLine(header, line);
else else
return null; return null;
} }
// Read header body // Read header body
while( (line=in.readLine()) != null && !line.isEmpty() ){ while( (line=IOUtil.readLine(in)) != null && !line.isEmpty() ){
parseHeaderLine(header, line); parseHeaderLine(header.getHeaderMap(), line);
} }
// Post processing // Post processing
parseHeaderValue(header.getCookieMap(), header.getHeader(HEADER_COOKIE)); parseHeaderValue(header.getCookieMap(), header.getHeader(HEADER_COOKIE));
header.setInputStream(in);
return header; return header;
} }
@ -119,7 +121,7 @@ public class HttpHeaderParser {
if(index > -1){ if(index > -1){
header.setRequestURL( statusLine.substring(0, index)); header.setRequestURL( statusLine.substring(0, index));
statusLine = statusLine.substring( index+1, statusLine.length()); statusLine = statusLine.substring( index+1, statusLine.length());
parseURLParameters(header, statusLine); parseURLParameters(header.getUrlAttributeMap(), statusLine);
} }
else{ else{
header.setRequestURL(statusLine); header.setRequestURL(statusLine);
@ -128,14 +130,16 @@ public class HttpHeaderParser {
} }
/** /**
* Parses a http key value paired header line * Parses a http key value paired header line.
* Note that all header keys will be stored with
* uppercase notation to make them case insensitive.
* *
* @param header the header object where the cookies will be stored. * @param map a map where the header key(Uppercase) and value will be stored.
* @param line is the next line in the header * @param line is the next line in the header
*/ */
public static void parseHeaderLine(HttpHeader header, String line){ public static void parseHeaderLine(Map<String,String> map, String line){
String[] data = PATTERN_COLON.split( line, 2 ); String[] data = PATTERN_COLON.split( line, 2 );
header.getHeaderMap().put( map.put(
data[0].trim().toUpperCase(), // Key data[0].trim().toUpperCase(), // Key
(data.length>1 ? data[1] : "").trim()); //Value (data.length>1 ? data[1] : "").trim()); //Value
} }
@ -160,20 +164,30 @@ public class HttpHeaderParser {
} }
} }
/** /**
* Parses a string with variables from a get or post request that was sent from a client * Parses a string with variables from a get or post request that was sent from a client
* *
* @param header the header object where the cookies will be stored. * @param header the header object where the url attributes key and value will be stored.
* @param urlAttributes is the String containing all the attributes * @param urlAttributes is the String containing all the attributes
*/ */
public static void parseURLParameters(HttpHeader header, String urlAttributes){ public static void parseURLParameters(HttpHeader header, String urlAttributes){
parseURLParameters(header.getUrlAttributeMap(), urlAttributes);
}
/**
* Parses a string with variables from a get or post request that was sent from a client
*
* @param map a map where the url attributes key and value will be stored.
* @param urlAttributes is the String containing all the attributes
*/
public static void parseURLParameters(Map<String,String> map, String urlAttributes){
String[] tmp; String[] tmp;
urlAttributes = URLDecoder.decode(urlAttributes); urlAttributes = URLDecoder.decode(urlAttributes);
// get the variables // get the variables
String[] data = PATTERN_AND.split( urlAttributes ); String[] data = PATTERN_AND.split( urlAttributes );
for(String element : data){ for(String element : data){
tmp = PATTERN_EQUAL.split(element, 2); tmp = PATTERN_EQUAL.split(element, 2);
header.getUrlAttributeMap().put( map.put(
tmp[0].trim(), // Key tmp[0].trim(), // Key
(tmp.length>1 ? tmp[1] : "").trim()); //Value (tmp.length>1 ? tmp[1] : "").trim()); //Value
} }

View file

@ -29,10 +29,7 @@ import zutil.log.LogUtil;
import zutil.net.threaded.ThreadedTCPNetworkServer; import zutil.net.threaded.ThreadedTCPNetworkServer;
import zutil.net.threaded.ThreadedTCPNetworkServerThread; import zutil.net.threaded.ThreadedTCPNetworkServerThread;
import java.io.BufferedReader; import java.io.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket; import java.net.Socket;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -151,12 +148,12 @@ public class HttpServer extends ThreadedTCPNetworkServer{
*/ */
protected class HttpServerThread implements ThreadedTCPNetworkServerThread{ protected class HttpServerThread implements ThreadedTCPNetworkServerThread{
private HttpPrintStream out; private HttpPrintStream out;
private BufferedReader in; private BufferedInputStream in;
private Socket socket; private Socket socket;
public HttpServerThread(Socket socket) throws IOException{ public HttpServerThread(Socket socket) throws IOException{
out = new HttpPrintStream(socket.getOutputStream()); out = new HttpPrintStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream())); in = new BufferedInputStream(socket.getInputStream());
this.socket = socket; this.socket = socket;
} }
@ -175,30 +172,19 @@ public class HttpServer extends ThreadedTCPNetworkServer{
String tmp = null; String tmp = null;
//******* Read in the post data if available //******* Read in the post data if available
if (header.getHeader("Content-Length") != null) { if (header.getHeader("Content-Length") != null &&
header.getHeader("Content-Type") != null &&
header.getHeader("Content-Type").contains("application/x-www-form-urlencoded")) {
// Reads the post data size // Reads the post data size
tmp = header.getHeader("Content-Length"); int post_data_length = Integer.parseInt(header.getHeader("Content-Length"));
int post_data_length = Integer.parseInt(tmp);
// read the data // read the data
StringBuilder tmpBuff = new StringBuilder(); StringBuilder tmpBuff = new StringBuilder();
// read the data // read the data
for (int i = 0; i < post_data_length; i++) { for (int i = 0; i < post_data_length; i++) {
tmpBuff.append((char) in.read()); tmpBuff.append((char) in.read());
} }
// get the variables
tmp = header.getHeader("Content-Type"); HttpHeaderParser.parseURLParameters(header, tmpBuff.toString());
if (tmp.contains("application/x-www-form-urlencoded")) {
// get the variables
HttpHeaderParser.parseURLParameters(header, tmpBuff.toString());
} else if (tmp.contains("application/soap+xml") ||
tmp.contains("text/xml") ||
tmp.contains("text/plain")) {
// save the variables
header.getUrlAttributeMap().put("", tmpBuff.toString());
} else if (tmp.contains("multipart/form-data")) {
// TODO: File upload
throw new UnsupportedOperationException("HTTP Content-Type 'multipart-form-data' not supported.");
}
} }
//**************************** HANDLE REQUEST ********************************* //**************************** HANDLE REQUEST *********************************

View file

@ -25,10 +25,13 @@
package zutil.net.http.multipart; package zutil.net.http.multipart;
import zutil.io.IOUtil; import zutil.io.IOUtil;
import zutil.log.LogUtil;
import java.io.*; import java.io.*;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger;
import static zutil.net.http.multipart.MultipartParser.HEADER_CONTENT_TYPE;
/** /**
@ -37,16 +40,23 @@ import java.util.Map;
* @author Ziver * @author Ziver
*/ */
public class MultipartFileField implements MultipartField{ public class MultipartFileField implements MultipartField{
private static final Logger logger = LogUtil.getLogger();
private String fieldname; private String fieldname;
private String filename; private String filename;
private String contentType; private String contentType;
private byte[] content;
private InputStream in; private InputStream in;
protected MultipartFileField(String name, String filename, String contentType, BufferedReader in) throws IOException { protected MultipartFileField(Map<String,String> headers, InputStream in) throws IOException {
this.fieldname = name; this.fieldname = headers.get("name");
this.filename = filename; this.filename = headers.get("filename");
this.contentType = contentType; this.contentType = headers.get(HEADER_CONTENT_TYPE);
this.in = in;
if (contentType != null && !contentType.equalsIgnoreCase("application/octet-stream"))
logger.warning("Unsupported Content-Type: "+contentType);
} }
/** /**
@ -71,19 +81,42 @@ public class MultipartFileField implements MultipartField{
return contentType; return contentType;
} }
public InputStream getInputStream(){
return in;
/**
* First time this method is called the contents of the
* file will be read into a byte array and returned.
* Subsequent calls will just return the array without
* reading any more data from the stream.
*
* Note: Only one of the methods {@link #getContent()} or
* {@link #saveToFile(File)} can be used as they will consume the data in the stream.
*
* @return a byte array containing the file data. null if the Stream has already been consumed
*/
public byte[] getContent() throws IOException {
if (in != null) {
content = IOUtil.readContent(in);
in = null; // reset InputStream
}
return content;
} }
/** /**
* Reads in all data and save it into the specified file * Reads in all data and save it into the specified file.
*
* Note: Only one of the methods {@link #getContent()} or
* {@link #saveToFile(File)} can be used as they will consume the data in the stream.
* *
* @param file is the new file where the data will be stored * @param file is the new file where the data will be stored
*/ */
public void saveToFile(File file) throws IOException { public void saveToFile(File file) throws IOException {
if (in == null)
throw new IOException("Stream already consumed.");
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
IOUtil.copyStream(in, out); IOUtil.copyStream(in, out);
out.close(); out.close();
in = null; // reset InputStream
} }
} }

View file

@ -49,8 +49,8 @@ import java.util.logging.Logger;
*/ */
public class MultipartParser implements Iterable<MultipartField>{ public class MultipartParser implements Iterable<MultipartField>{
private static final Logger logger = LogUtil.getLogger(); private static final Logger logger = LogUtil.getLogger();
private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; protected static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition".toUpperCase();
private static final String HEADER_CONTENT_TYPE = "Content-Type"; protected static final String HEADER_CONTENT_TYPE = "Content-Type".toUpperCase();
/** This is the delimiter that will separate the fields */ /** This is the delimiter that will separate the fields */
private String delimiter; private String delimiter;
@ -67,17 +67,17 @@ public class MultipartParser implements Iterable<MultipartField>{
this.delimiter = delimiter; this.delimiter = delimiter;
this.contentLength = length; this.contentLength = length;
} }
public MultipartParser(InputStream in, HttpHeader header){ public MultipartParser(HttpHeader header){
this(in, this(header.getInputStream(),
parseDelimiter(header.getHeader("Content-type")), parseDelimiter(header.getHeader("Content-type")),
Long.parseLong( header.getHeader("Content-Length"))); Long.parseLong(header.getHeader("Content-Length")));
} }
public MultipartParser(HttpServletRequest req) throws IOException { /* public MultipartParser(HttpServletRequest req) throws IOException {
this(req.getInputStream(), this(req.getInputStream(),
parseDelimiter(req.getHeader("Content-type")), parseDelimiter(req.getHeader("Content-type")),
req.getContentLength()); req.getContentLength());
} }
*/
private static String parseDelimiter(String contentTypeHeader){ private static String parseDelimiter(String contentTypeHeader){
String delimiter = contentTypeHeader.split(" *; *")[1]; String delimiter = contentTypeHeader.split(" *; *")[1];
delimiter = delimiter.split(" *= *")[1]; delimiter = delimiter.split(" *= *")[1];
@ -102,22 +102,20 @@ public class MultipartParser implements Iterable<MultipartField>{
protected class MultiPartIterator implements Iterator<MultipartField>{ protected class MultiPartIterator implements Iterator<MultipartField>{
private BufferedBoundaryInputStream boundaryIn; private BufferedBoundaryInputStream boundaryIn;
private BufferedReader buffIn;
private HttpHeaderParser parser;
private boolean firstIteration; private boolean firstIteration;
protected MultiPartIterator(){ protected MultiPartIterator(){
this.boundaryIn = new BufferedBoundaryInputStream(in); this.boundaryIn = new BufferedBoundaryInputStream(in);
this.buffIn = new BufferedReader(new InputStreamReader(boundaryIn));
this.parser = new HttpHeaderParser(buffIn);
this.parser.setReadStatusLine(false);
this.boundaryIn.setBoundary("--"+delimiter); this.boundaryIn.setBoundary("--"+delimiter);
firstIteration = true; firstIteration = true;
} }
/**
* TODO: there is a bug where this returns true after the last MultiPart as it cannot read ahead. So use next() != null instead
*/
@Override @Override
public boolean hasNext() { public boolean hasNext() {
try { try {
@ -137,31 +135,26 @@ public class MultipartParser implements Iterable<MultipartField>{
this.boundaryIn.setBoundary("\n--"+delimiter); // Add new-line to boundary after the first iteration this.boundaryIn.setBoundary("\n--"+delimiter); // Add new-line to boundary after the first iteration
firstIteration = false; firstIteration = false;
} }
String tmp = buffIn.readLine(); // read the new line after the delimiter String tmp = IOUtil.readLine(boundaryIn); // read the new line after the delimiter
if (tmp == null || tmp.equals("--")) if (tmp == null || tmp.equals("--"))
return null; return null;
HttpHeader header = parser.read(); // Read Headers
String disposition = header.getHeader(HEADER_CONTENT_DISPOSITION); HashMap<String,String> headers = new HashMap<>();
String contentType = header.getHeader("Content-Type"); while ((tmp=IOUtil.readLine(boundaryIn)) != null && !tmp.isEmpty())
if (contentType != null && !contentType.equalsIgnoreCase("application/octet-stream")) HttpHeaderParser.parseHeaderLine(headers, tmp);
logger.warning("Unsupported ontent-Type: "+contentType);
// Parse
String disposition = headers.get(HEADER_CONTENT_DISPOSITION);
if (disposition != null){ if (disposition != null){
HashMap<String,String> map = new HashMap<>(); HttpHeaderParser.parseHeaderValue(headers, disposition);
HttpHeaderParser.parseHeaderValue(map, disposition); if (headers.containsKey("form-data")){
if (map.containsKey("form-data")){ if (headers.containsKey("filename")){
if (map.containsKey("filename")){ MultipartFileField field = new MultipartFileField(headers, boundaryIn);
MultipartFileField field = new MultipartFileField(
map.get("name"),
map.get("filename"),
contentType,
buffIn);
return field; return field;
} }
else{ else{
MultipartStringField field = new MultipartStringField( MultipartStringField field = new MultipartStringField(headers, boundaryIn);
map.get("name"),
buffIn);
return field; return field;
} }
} }

View file

@ -2,9 +2,11 @@ package zutil.net.http.multipart;
import zutil.io.IOUtil; import zutil.io.IOUtil;
import zutil.io.InputStreamCloser;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Map; import java.util.Map;
@ -15,9 +17,9 @@ public class MultipartStringField implements MultipartField {
private String name; private String name;
private String value; private String value;
protected MultipartStringField(String name, BufferedReader in) throws IOException { protected MultipartStringField(Map<String,String> headers, InputStream in) throws IOException {
this.name = name; this.name = headers.get("name");
value = in.readLine(); value = IOUtil.readLine(in);
} }
@Override @Override

View file

@ -78,7 +78,7 @@ public class SOAPClientInvocationHandler implements InvocationHandler {
request.setURL(url); request.setURL(url);
request.setData(reqXml); request.setData(reqXml);
HttpHeaderParser response = request.send(); HttpHeaderParser response = request.send();
String rspXml = IOUtil.getContentAsString( request.getResponseReader()); String rspXml = IOUtil.readContentAsString( request.getResponseReader());
// DEBUG // DEBUG
if( logger.isLoggable(Level.FINEST) ){ if( logger.isLoggable(Level.FINEST) ){

View file

@ -39,6 +39,8 @@ import zutil.net.http.HttpPrintStream;
import zutil.net.ws.*; import zutil.net.ws.*;
import zutil.net.ws.WSReturnObject.WSValueName; import zutil.net.ws.WSReturnObject.WSValueName;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Iterator; import java.util.Iterator;
@ -120,6 +122,22 @@ public class SOAPHttpPage implements HttpPage{
Map<String, String> request) { Map<String, String> request) {
try { try {
// Read http body
StringBuilder data = null;
String contentType = headers.getHeader("Content-Type");
if (contentType != null &&
(contentType.contains("application/soap+xml") ||
contentType.contains("text/xml") ||
contentType.contains("text/plain"))) {
int post_data_length = Integer.parseInt(headers.getHeader("Content-Length"));
BufferedReader in = new BufferedReader(new InputStreamReader(headers.getInputStream()));
data = new StringBuilder(post_data_length);
for (int i = 0; i < post_data_length; i++) {
data.append((char) in.read());
}
}
// Response
out.setHeader("Content-Type", "text/xml"); out.setHeader("Content-Type", "text/xml");
out.flush(); out.flush();
@ -138,7 +156,7 @@ public class SOAPHttpPage implements HttpPage{
obj = ws; obj = ws;
} }
Document document = genSOAPResponse( request.get(""), obj); Document document = genSOAPResponse( (data!=null ? data.toString() : ""), obj);
OutputFormat format = OutputFormat.createPrettyPrint(); OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter( out, format ); XMLWriter writer = new XMLWriter( out, format );

View file

@ -70,7 +70,7 @@ public class PluginManager<T> implements Iterable<PluginData>{
log.fine("Searching for plugins..."); log.fine("Searching for plugins...");
for(FileSearcher.FileSearchItem file : search){ for(FileSearcher.FileSearchItem file : search){
try { try {
DataNode node = JSONParser.read(IOUtil.getContentAsString(file.getInputStream())); DataNode node = JSONParser.read(IOUtil.readContentAsString(file.getInputStream()));
log.fine("Found plugin: "+file.getPath()); log.fine("Found plugin: "+file.getPath());
PluginData plugin = new PluginData(node); PluginData plugin = new PluginData(node);

View file

@ -38,6 +38,8 @@ public class MultipartParserTest {
assertEquals("foo", stringField.getName()); assertEquals("foo", stringField.getName());
assertEquals("bar", stringField.getValue()); assertEquals("bar", stringField.getValue());
//assertFalse(it.hasNext()); //TODO: does not work, how to solve this? //assertFalse(it.hasNext()); //TODO: does not work, how to solve this?
assertEquals(null, it.next());
assertEquals(null, it.next());
} }
@Test @Test