diff --git a/Zutil.iml b/Zutil.iml
index 0848f64..66692df 100755
--- a/Zutil.iml
+++ b/Zutil.iml
@@ -26,6 +26,7 @@
+
diff --git a/lib/commons-io-1.4.jar b/lib/commons-io-1.4.jar
deleted file mode 100644
index 133dc6c..0000000
Binary files a/lib/commons-io-1.4.jar and /dev/null differ
diff --git a/lib/commons-io-2.5.jar b/lib/commons-io-2.5.jar
new file mode 100755
index 0000000..1234918
Binary files /dev/null and b/lib/commons-io-2.5.jar differ
diff --git a/src/zutil/io/IOUtil.java b/src/zutil/io/IOUtil.java
index 05c87de..86f3c2b 100755
--- a/src/zutil/io/IOUtil.java
+++ b/src/zutil/io/IOUtil.java
@@ -41,7 +41,7 @@ public class IOUtil {
* @param stream
* @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();
byte[] buff = new byte[8192];
int len = 0;
@@ -60,8 +60,8 @@ public class IOUtil {
* @param stream
* @return a String with the content of the stream
*/
- public static String getContentAsString(InputStream stream) throws IOException{
- return getContentAsString(new InputStreamReader(stream));
+ public static String readContentAsString(InputStream stream) throws IOException{
+ return readContentAsString(new InputStreamReader(stream));
}
/**
@@ -71,7 +71,7 @@ public class IOUtil {
* @param reader
* @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();
BufferedReader in = null;
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
* @return a String that contains one line excluding line terminating
@@ -106,6 +107,26 @@ public class IOUtil {
return null; // End of the stream
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.
diff --git a/src/zutil/io/file/FileUtil.java b/src/zutil/io/file/FileUtil.java
index 658d83d..1debbe5 100755
--- a/src/zutil/io/file/FileUtil.java
+++ b/src/zutil/io/file/FileUtil.java
@@ -163,7 +163,7 @@ public class FileUtil {
}
public static byte[] getByteContent(File file) throws IOException {
InputStream in = new FileInputStream(file);
- byte[] data = IOUtil.getContent(in);
+ byte[] data = IOUtil.readContent(in);
in.close();
return data;
}
@@ -176,7 +176,7 @@ public class FileUtil {
*/
public static String getContent(URL url) throws IOException{
InputStream in = url.openStream();
- String data = new String(IOUtil.getContent(in));
+ String data = new String(IOUtil.readContent(in));
in.close();
return data;
}
diff --git a/src/zutil/net/FTPClient.java b/src/zutil/net/FTPClient.java
old mode 100644
new mode 100755
index c7e330a..9bc3d17
--- a/src/zutil/net/FTPClient.java
+++ b/src/zutil/net/FTPClient.java
@@ -175,7 +175,7 @@ public class FTPClient extends Thread{
BufferedInputStream data_in = getDataInputStream();
sendCommand("NLST "+path);
- String data = new String(IOUtil.getContent(data_in));
+ String data = new String(IOUtil.readContent(data_in));
data_in.close();
readCommand();
@@ -194,7 +194,7 @@ public class FTPClient extends Thread{
BufferedInputStream data_in = getDataInputStream();
sendCommand("LIST "+path);
- String data = new String(IOUtil.getContent(data_in));
+ String data = new String(IOUtil.readContent(data_in));
data_in.close();
readCommand();
diff --git a/src/zutil/net/http/HttpClient.java b/src/zutil/net/http/HttpClient.java
index 1cb39a7..e8316cd 100755
--- a/src/zutil/net/http/HttpClient.java
+++ b/src/zutil/net/http/HttpClient.java
@@ -26,6 +26,7 @@ package zutil.net.http;
import zutil.net.http.HttpPrintStream.HttpMessageType;
+import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -52,8 +53,8 @@ public class HttpClient implements AutoCloseable{
private String data;
// Response variables
- private HttpHeaderParser rspHeader;
- private BufferedReader rspReader;
+ private HttpHeaderParser rspHeader;
+ private BufferedInputStream rspReader;
@@ -128,7 +129,7 @@ public class HttpClient implements AutoCloseable{
// Response
if(rspHeader != null || rspReader != null) // Close previous request
this.close();
- rspReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ rspReader = new BufferedInputStream(conn.getInputStream());
rspHeader = new HttpHeaderParser( rspReader );
return rspHeader;
@@ -137,7 +138,7 @@ public class HttpClient implements AutoCloseable{
public HttpHeaderParser getResponseHeader(){
return rspHeader;
}
- public BufferedReader getResponseReader(){
+ public BufferedInputStream getResponseReader(){
return rspReader;
}
diff --git a/src/zutil/net/http/HttpHeader.java b/src/zutil/net/http/HttpHeader.java
index 460e836..a0af5ae 100755
--- a/src/zutil/net/http/HttpHeader.java
+++ b/src/zutil/net/http/HttpHeader.java
@@ -26,6 +26,8 @@ package zutil.net.http;
import zutil.converter.Converter;
+import java.io.BufferedReader;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
@@ -37,6 +39,7 @@ public class HttpHeader {
private HashMap urlAttributes;
private float version;
private int httpCode;
+ private InputStream in;
// Parameters
private HashMap 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(){
return !request;
}
/**
- * @return true if this header represents a client request
+ * @return true if this header represents a client request
*/
public boolean isRequest(){
return request;
@@ -103,47 +106,47 @@ public class HttpHeader {
return null;
}
/**
- * @return a Iterator with all defined url keys
+ * @return a Iterator with all defined url keys
*/
public Iterator getURLAttributeKeys(){
return urlAttributes.keySet().iterator();
}
/**
- * Returns the URL attribute value of the given name.
- *
- * returns null if there is no such attribute
+ * @return the URL attribute value of the given name. null if there is no such attribute
*/
public String getURLAttribute(String name){
return urlAttributes.get( name );
}
/**
- * @return a Iterator with all defined headers
+ * @return a Iterator with all defined headers
*/
public Iterator getHeaderKeys(){
return headers.keySet().iterator();
}
/**
- * Returns the HTTP attribute value of the given name.
- *
- * returns null if there is no such attribute
+ * @return the HTTP attribute value of the given name. null if there is no such attribute
*/
public String getHeader(String name){
return headers.get( name.toUpperCase() );
}
/**
- * @return a Iterator with all defined cookies
+ * @return a Iterator with all defined cookies
*/
public Iterator getCookieKeys(){
return cookies.keySet().iterator();
}
/**
- * Returns the cookie value of the given name.
- *
- * returns null if there is no such attribute
+ * @return the cookie value of the given name. null if there is no such attribute.
*/
public String getCookie(String 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; }
@@ -159,6 +162,9 @@ public class HttpHeader {
protected void setRequestURL(String url){
this.url = url.trim().replaceAll("//", "/");
}
+ protected void setInputStream(InputStream in){
+ this.in = in;
+ }
protected HashMap getHeaderMap(){
return headers;
diff --git a/src/zutil/net/http/HttpHeaderParser.java b/src/zutil/net/http/HttpHeaderParser.java
index 3c5e4ce..44d2989 100755
--- a/src/zutil/net/http/HttpHeaderParser.java
+++ b/src/zutil/net/http/HttpHeaderParser.java
@@ -24,17 +24,18 @@
package zutil.net.http;
+import com.mysql.jdbc.Buffer;
import zutil.StringUtil;
+import zutil.io.IOUtil;
+import zutil.io.StringInputStream;
import zutil.parser.URLDecoder;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
+import java.io.*;
import java.util.Map;
import java.util.regex.Pattern;
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_EQUAL = Pattern.compile("=");
@@ -42,7 +43,7 @@ public class HttpHeaderParser {
private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
- private BufferedReader in;
+ private InputStream in;
private boolean readStatusLine;
@@ -51,8 +52,8 @@ public class HttpHeaderParser {
*
* @param in is the stream
*/
- public HttpHeaderParser(BufferedReader in){
- this.in = in;
+ public HttpHeaderParser(InputStream in){
+ this.in = in;
this.readStatusLine = true;
}
@@ -62,28 +63,29 @@ public class HttpHeaderParser {
* @param in is the String
*/
public HttpHeaderParser(String in){
- this(new BufferedReader(new StringReader(in)));
+ this(new StringInputStream(in));
}
public HttpHeader read() throws IOException {
HttpHeader header = new HttpHeader();
- String line = null;
+ String line;
// First line
if (readStatusLine) {
- if( (line=in.readLine()) != null && !line.isEmpty() )
+ if( (line= IOUtil.readLine(in)) != null && !line.isEmpty() )
parseStatusLine(header, line);
else
return null;
}
// Read header body
- while( (line=in.readLine()) != null && !line.isEmpty() ){
- parseHeaderLine(header, line);
+ while( (line=IOUtil.readLine(in)) != null && !line.isEmpty() ){
+ parseHeaderLine(header.getHeaderMap(), line);
}
+
// Post processing
parseHeaderValue(header.getCookieMap(), header.getHeader(HEADER_COOKIE));
-
+ header.setInputStream(in);
return header;
}
@@ -119,7 +121,7 @@ public class HttpHeaderParser {
if(index > -1){
header.setRequestURL( statusLine.substring(0, index));
statusLine = statusLine.substring( index+1, statusLine.length());
- parseURLParameters(header, statusLine);
+ parseURLParameters(header.getUrlAttributeMap(), statusLine);
}
else{
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
*/
- public static void parseHeaderLine(HttpHeader header, String line){
+ public static void parseHeaderLine(Map map, String line){
String[] data = PATTERN_COLON.split( line, 2 );
- header.getHeaderMap().put(
+ map.put(
data[0].trim().toUpperCase(), // Key
(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
*
- * @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
*/
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 map, String urlAttributes){
String[] tmp;
urlAttributes = URLDecoder.decode(urlAttributes);
// get the variables
String[] data = PATTERN_AND.split( urlAttributes );
for(String element : data){
tmp = PATTERN_EQUAL.split(element, 2);
- header.getUrlAttributeMap().put(
+ map.put(
tmp[0].trim(), // Key
(tmp.length>1 ? tmp[1] : "").trim()); //Value
}
diff --git a/src/zutil/net/http/HttpServer.java b/src/zutil/net/http/HttpServer.java
index 60f60a2..77066bf 100755
--- a/src/zutil/net/http/HttpServer.java
+++ b/src/zutil/net/http/HttpServer.java
@@ -29,10 +29,7 @@ import zutil.log.LogUtil;
import zutil.net.threaded.ThreadedTCPNetworkServer;
import zutil.net.threaded.ThreadedTCPNetworkServerThread;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.*;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -151,12 +148,12 @@ public class HttpServer extends ThreadedTCPNetworkServer{
*/
protected class HttpServerThread implements ThreadedTCPNetworkServerThread{
private HttpPrintStream out;
- private BufferedReader in;
+ private BufferedInputStream in;
private Socket socket;
public HttpServerThread(Socket socket) throws IOException{
out = new HttpPrintStream(socket.getOutputStream());
- in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ in = new BufferedInputStream(socket.getInputStream());
this.socket = socket;
}
@@ -175,30 +172,19 @@ public class HttpServer extends ThreadedTCPNetworkServer{
String tmp = null;
//******* 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
- tmp = header.getHeader("Content-Length");
- int post_data_length = Integer.parseInt(tmp);
+ int post_data_length = Integer.parseInt(header.getHeader("Content-Length"));
// read the data
StringBuilder tmpBuff = new StringBuilder();
// read the data
for (int i = 0; i < post_data_length; i++) {
tmpBuff.append((char) in.read());
}
-
- tmp = header.getHeader("Content-Type");
- 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.");
- }
+ // get the variables
+ HttpHeaderParser.parseURLParameters(header, tmpBuff.toString());
}
//**************************** HANDLE REQUEST *********************************
diff --git a/src/zutil/net/http/multipart/MultipartFileField.java b/src/zutil/net/http/multipart/MultipartFileField.java
index 142da73..9bec786 100755
--- a/src/zutil/net/http/multipart/MultipartFileField.java
+++ b/src/zutil/net/http/multipart/MultipartFileField.java
@@ -25,10 +25,13 @@
package zutil.net.http.multipart;
import zutil.io.IOUtil;
+import zutil.log.LogUtil;
import java.io.*;
-import java.util.HashMap;
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
*/
public class MultipartFileField implements MultipartField{
+ private static final Logger logger = LogUtil.getLogger();
+
private String fieldname;
private String filename;
private String contentType;
+ private byte[] content;
private InputStream in;
- protected MultipartFileField(String name, String filename, String contentType, BufferedReader in) throws IOException {
- this.fieldname = name;
- this.filename = filename;
- this.contentType = contentType;
+ protected MultipartFileField(Map headers, InputStream in) throws IOException {
+ this.fieldname = headers.get("name");
+ this.filename = headers.get("filename");
+ 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;
}
- 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
*/
public void saveToFile(File file) throws IOException {
+ if (in == null)
+ throw new IOException("Stream already consumed.");
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
IOUtil.copyStream(in, out);
out.close();
+ in = null; // reset InputStream
}
}
diff --git a/src/zutil/net/http/multipart/MultipartParser.java b/src/zutil/net/http/multipart/MultipartParser.java
index 61f62bc..9ae048e 100755
--- a/src/zutil/net/http/multipart/MultipartParser.java
+++ b/src/zutil/net/http/multipart/MultipartParser.java
@@ -49,8 +49,8 @@ import java.util.logging.Logger;
*/
public class MultipartParser implements Iterable{
private static final Logger logger = LogUtil.getLogger();
- private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
- private static final String HEADER_CONTENT_TYPE = "Content-Type";
+ protected static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition".toUpperCase();
+ protected static final String HEADER_CONTENT_TYPE = "Content-Type".toUpperCase();
/** This is the delimiter that will separate the fields */
private String delimiter;
@@ -67,17 +67,17 @@ public class MultipartParser implements Iterable{
this.delimiter = delimiter;
this.contentLength = length;
}
- public MultipartParser(InputStream in, HttpHeader header){
- this(in,
+ public MultipartParser(HttpHeader header){
+ this(header.getInputStream(),
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(),
parseDelimiter(req.getHeader("Content-type")),
req.getContentLength());
}
-
+*/
private static String parseDelimiter(String contentTypeHeader){
String delimiter = contentTypeHeader.split(" *; *")[1];
delimiter = delimiter.split(" *= *")[1];
@@ -102,22 +102,20 @@ public class MultipartParser implements Iterable{
protected class MultiPartIterator implements Iterator{
private BufferedBoundaryInputStream boundaryIn;
- private BufferedReader buffIn;
- private HttpHeaderParser parser;
private boolean firstIteration;
protected MultiPartIterator(){
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);
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
public boolean hasNext() {
try {
@@ -137,31 +135,26 @@ public class MultipartParser implements Iterable{
this.boundaryIn.setBoundary("\n--"+delimiter); // Add new-line to boundary after the first iteration
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("--"))
return null;
- HttpHeader header = parser.read();
- String disposition = header.getHeader(HEADER_CONTENT_DISPOSITION);
- String contentType = header.getHeader("Content-Type");
- if (contentType != null && !contentType.equalsIgnoreCase("application/octet-stream"))
- logger.warning("Unsupported ontent-Type: "+contentType);
+ // Read Headers
+ HashMap headers = new HashMap<>();
+ while ((tmp=IOUtil.readLine(boundaryIn)) != null && !tmp.isEmpty())
+ HttpHeaderParser.parseHeaderLine(headers, tmp);
+
+ // Parse
+ String disposition = headers.get(HEADER_CONTENT_DISPOSITION);
if (disposition != null){
- HashMap map = new HashMap<>();
- HttpHeaderParser.parseHeaderValue(map, disposition);
- if (map.containsKey("form-data")){
- if (map.containsKey("filename")){
- MultipartFileField field = new MultipartFileField(
- map.get("name"),
- map.get("filename"),
- contentType,
- buffIn);
+ HttpHeaderParser.parseHeaderValue(headers, disposition);
+ if (headers.containsKey("form-data")){
+ if (headers.containsKey("filename")){
+ MultipartFileField field = new MultipartFileField(headers, boundaryIn);
return field;
}
else{
- MultipartStringField field = new MultipartStringField(
- map.get("name"),
- buffIn);
+ MultipartStringField field = new MultipartStringField(headers, boundaryIn);
return field;
}
}
diff --git a/src/zutil/net/http/multipart/MultipartStringField.java b/src/zutil/net/http/multipart/MultipartStringField.java
index 229bf06..bb36940 100755
--- a/src/zutil/net/http/multipart/MultipartStringField.java
+++ b/src/zutil/net/http/multipart/MultipartStringField.java
@@ -2,9 +2,11 @@ package zutil.net.http.multipart;
import zutil.io.IOUtil;
+import zutil.io.InputStreamCloser;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Map;
@@ -15,9 +17,9 @@ public class MultipartStringField implements MultipartField {
private String name;
private String value;
- protected MultipartStringField(String name, BufferedReader in) throws IOException {
- this.name = name;
- value = in.readLine();
+ protected MultipartStringField(Map headers, InputStream in) throws IOException {
+ this.name = headers.get("name");
+ value = IOUtil.readLine(in);
}
@Override
diff --git a/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java b/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java
index b427232..ab69f25 100755
--- a/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java
+++ b/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java
@@ -78,7 +78,7 @@ public class SOAPClientInvocationHandler implements InvocationHandler {
request.setURL(url);
request.setData(reqXml);
HttpHeaderParser response = request.send();
- String rspXml = IOUtil.getContentAsString( request.getResponseReader());
+ String rspXml = IOUtil.readContentAsString( request.getResponseReader());
// DEBUG
if( logger.isLoggable(Level.FINEST) ){
diff --git a/src/zutil/net/ws/soap/SOAPHttpPage.java b/src/zutil/net/ws/soap/SOAPHttpPage.java
index 54fcb5d..0090336 100755
--- a/src/zutil/net/ws/soap/SOAPHttpPage.java
+++ b/src/zutil/net/ws/soap/SOAPHttpPage.java
@@ -39,6 +39,8 @@ import zutil.net.http.HttpPrintStream;
import zutil.net.ws.*;
import zutil.net.ws.WSReturnObject.WSValueName;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Iterator;
@@ -120,6 +122,22 @@ public class SOAPHttpPage implements HttpPage{
Map request) {
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.flush();
@@ -138,7 +156,7 @@ public class SOAPHttpPage implements HttpPage{
obj = ws;
}
- Document document = genSOAPResponse( request.get(""), obj);
+ Document document = genSOAPResponse( (data!=null ? data.toString() : ""), obj);
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter( out, format );
diff --git a/src/zutil/plugin/PluginManager.java b/src/zutil/plugin/PluginManager.java
index fb7513e..763a705 100755
--- a/src/zutil/plugin/PluginManager.java
+++ b/src/zutil/plugin/PluginManager.java
@@ -70,7 +70,7 @@ public class PluginManager implements Iterable{
log.fine("Searching for plugins...");
for(FileSearcher.FileSearchItem file : search){
try {
- DataNode node = JSONParser.read(IOUtil.getContentAsString(file.getInputStream()));
+ DataNode node = JSONParser.read(IOUtil.readContentAsString(file.getInputStream()));
log.fine("Found plugin: "+file.getPath());
PluginData plugin = new PluginData(node);
diff --git a/test/zutil/net/http/multipart/MultipartParserTest.java b/test/zutil/net/http/multipart/MultipartParserTest.java
index c8bf27f..a33ffa6 100755
--- a/test/zutil/net/http/multipart/MultipartParserTest.java
+++ b/test/zutil/net/http/multipart/MultipartParserTest.java
@@ -38,6 +38,8 @@ public class MultipartParserTest {
assertEquals("foo", stringField.getName());
assertEquals("bar", stringField.getValue());
//assertFalse(it.hasNext()); //TODO: does not work, how to solve this?
+ assertEquals(null, it.next());
+ assertEquals(null, it.next());
}
@Test