diff --git a/src/zutil/io/BoundaryBufferedInputStream.java b/src/zutil/io/BoundaryBufferedInputStream.java index c62d1f5..a4dd6b3 100644 --- a/src/zutil/io/BoundaryBufferedInputStream.java +++ b/src/zutil/io/BoundaryBufferedInputStream.java @@ -5,7 +5,8 @@ import java.io.IOException; import java.io.InputStream; /** - * TODO + * TODO: boundry + * * @author Ziver * */ diff --git a/src/zutil/network/http/multipart/MultipartField.java b/src/zutil/network/http/multipart/MultipartField.java new file mode 100644 index 0000000..6231d0a --- /dev/null +++ b/src/zutil/network/http/multipart/MultipartField.java @@ -0,0 +1,51 @@ +package zutil.network.http.multipart; + +import java.io.BufferedReader; +import java.io.File; + +import zutil.ProgressListener; + + +/** + * A class for handling multipart field + * + * @author Ziver + */ +public class MultipartField{ + protected long received; + protected long length; + protected String contentType; + + protected String fieldname; + protected String value; + + + protected MultipartField(){ + + } + + /** + * @return the amount of data received for this field + */ + public long getReceivedBytes(){ + return received; + } + + /** + * @return the fieldname + */ + public String getFieldname(){ + return fieldname; + } + + /** + * @return the value of the field + */ + public String getValue(){ + return value; + } + + protected void parse(){ + + } +} \ No newline at end of file diff --git a/src/zutil/network/http/multipart/MultipartFile.java b/src/zutil/network/http/multipart/MultipartFile.java new file mode 100644 index 0000000..9045706 --- /dev/null +++ b/src/zutil/network/http/multipart/MultipartFile.java @@ -0,0 +1,63 @@ +package zutil.network.http.multipart; + +import java.io.BufferedReader; +import java.io.File; + +import zutil.ProgressListener; + + +/** + * A class for handling multipart files + * + * @author Ziver + */ +public class MultipartFile extends MultipartField{ + protected String filename; + protected File file; + + + protected MultipartFile(File tempFile){ + this.file = tempFile; + } + + /** + * @return the amount of data received for this field + */ + public long getReceivedBytes(){ + return received; + } + + /** + * @return the value of the field + */ + public String getValue(){ + return null; + } + + /** + * @return the filename + */ + public String getFilename(){ + return filename; + } + + /** + * @return the File class that points to the received file + */ + public File getFile(){ + return file; + } + + /** + * Moves this file + * + * @param new_file is the new location to move the file to + * @return if the move was successful + */ + public boolean moveFile(File new_file){ + boolean success = file.renameTo(new_file); + if(success) + file = new_file; + return success; + } +} \ No newline at end of file diff --git a/src/zutil/network/http/multipart/MultipartParser.java b/src/zutil/network/http/multipart/MultipartParser.java new file mode 100644 index 0000000..a82ff0f --- /dev/null +++ b/src/zutil/network/http/multipart/MultipartParser.java @@ -0,0 +1,194 @@ +package zutil.network.http.multipart; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import zutil.ProgressListener; +import zutil.network.http.HTTPHeaderParser; + +/** + * Parses a multipart/form-data http request, + * saves files to temporary location. + * + * http://www.ietf.org/rfc/rfc1867.txt + * + * @author Ziver + * + */ +public class MultipartParser { + /** This is the temporary directory for the received files */ + private File tempDir; + /** This is the delimiter that will separate the fields */ + private String delimiter; + /** The length of the HTTP Body */ + private long contentLength; + /** This is the input stream */ + private BufferedReader in; + + /** This is the listener that will listen on the progress */ + private ProgressListener listener; + + + + public MultipartParser(BufferedReader in, HTTPHeaderParser header){ + this.in = in; + + String cotype = header.getHeader("Content-type"); + cotype = cotype.split(" *; *")[1]; + delimiter = cotype.split(" *= *")[1]; + + contentLength = Long.parseLong( header.getHeader("Content-Length") ); + } + + public MultipartParser(BufferedReader in, HttpServletRequest req){ + this.in = in; + + String cotype = req.getHeader("Content-type"); + cotype = cotype.split(" *; *")[1]; + delimiter = cotype.split(" *= *")[1]; + + contentLength = req.getContentLength(); + } + + public MultipartParser(BufferedReader in, String delimiter, long length){ + this.in = in; + this.delimiter = delimiter; + this.contentLength = length; + } + + + /** + * @param listener is the listener that will be called for progress + */ + public void setListener(ProgressListener listener){ + this.listener = listener; + } + + /** + * Parses the HTTP Body and returns a list of fields + * + * @return A list of FormField + */ + public List parse() throws IOException{ + ArrayList list = new ArrayList(); + // TODO: parse(list, delimiter); + return list; + } + +// TODO: +/* + private void parse(List list, String delimiter) throws IOException{ + String line = ""; + MultipartField field = null; + delimiter = "--"+delimiter; + String endDelimiter = delimiter+"--"; + BufferedWriter out = null; + // Parsing the stream + while(line != null){ + line = in.readLine(); + // Skip empty lines + if(line == null || line.trim().isEmpty()) + continue; + // End of field + else if(line.equals( endDelimiter )){ + list.add(field); + if(out != null) out.close(); + field.length = field.file.length(); + out = null; + field = null; + continue; + } + // New field + else if(line.equals( delimiter )){ + if(field != null){ + list.add(field); + if(out != null) out.close(); + field.length = field.file.length(); + out = null; + field = null; + } + // Read the content-disposition + line = in.readLine(); + if(line.toLowerCase().startsWith("content-disposition")){ + line = line.split(":", 2)[1]; + String[] fieldData = line.split(" *; *"); + //String type = fieldData[0].toLowerCase(); + field = new MultipartField(); + field.type = MultipartField.FieldType.Field; + + // Parse content-disposition parameters + for(String param : fieldData){ + String[] temp = param.split(" *= *"); + if(temp[0].equalsIgnoreCase("name")) + field.fieldname = temp[1]; + else if(temp[0].equalsIgnoreCase("filename")){ + field.filename = temp[1]; + field.file = createTempFile(); + out = new BufferedWriter(new FileWriter(field.file)); + field.type = MultipartField.FieldType.File; + } + } + } + else + throw new IOException("MultipartForm parse error unrecognized line: "+line); + } + // Read field data + else if(field != null){ + if(field.type == MultipartField.FieldType.File){ + out.append(line); + } + else{ + field.value += line; + } + field.received += line.length(); + } + } + + if(field != null) + throw new IOException("MultipartForm parse error stream ended prematurely"); + } +*/ + + /** + * Creates a temporary file in either the system + * temporary folder or by the setTempDir() function + * + * @return the temporary file + */ + protected File createTempFile() throws IOException{ + if(tempDir != null) + return File.createTempFile("upload", ".part", tempDir.getAbsoluteFile()); + else + return File.createTempFile("upload", ".part"); + } + + /** + * Sets the initial delimiter + * + * @param delimiter is the new delimiter + */ + public void setDelimiter(String delimiter){ + this.delimiter = delimiter; + } + + public void setTempDir(File dir){ + if(!dir.isDirectory()) + throw new RuntimeException("\""+dir.getAbsolutePath()+"\" is not a directory!"); + if(!dir.canWrite()) + throw new RuntimeException("\""+dir.getAbsolutePath()+"\" is not writable!"); + tempDir = dir; + } + + public long getContentLength(){ + return contentLength; + } +}