📄 multipartrequest.java
字号:
package lightningboard.util;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.File;
import java.io.IOException;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
public class MultiPartRequest{
private File dir;
private File file;
private int maxSize;
private Hashtable params = new Hashtable();
private ServletRequest request;
public Hashtable getParameters() {
return params;
}
public String getParameter( String name ) {
try {
String param = (String)params.get( name );
return param;
}
catch( Exception e ) {
return null;
}
}
public Enumeration getParameterNames() {
return params.keys();
}
public String[] getParameterValues( String name ) {
String param = (String)params.get( name );
if( param != null ) {
return new String[] {
param
};
}
return null;
}
public MultiPartRequest(HttpServletRequest request, String dir ,int maxSize)
throws IOException {
if( request == null ) {
throw new IllegalArgumentException( "request can not be null" );
}
if( dir == null ) {
throw new IllegalArgumentException( "dir can not be null" );
}
this.request = request;
this.dir = new File(dir);
this.maxSize = maxSize;
// Check saveDirectory is truly a directory
if( !this.dir.isDirectory() ) {
throw new IllegalArgumentException( "Not a directory: " + dir );
}
// Check saveDirectory is writable
if( !this.dir.canWrite() ) {
throw new IllegalArgumentException( "Not writable: " + dir );
}
// Parse the request to get the parameters and files
// Check the content type to make sure it's "multipart/form-data"
String type = request.getContentType();
if( type == null || !type.toLowerCase().startsWith( "multipart/form-data" ) ) {
throw new IOException( "Content type isn't multipart/form-data" );
}
// Check the content length to prevent denial of service attacks
int length = request.getContentLength();
if( length > maxSize ) {
throw new IOException( "Content length of " + length + " exceeds limit of " + maxSize );
}
// Get the boundary string
int index = type.indexOf( "boundary=" );
if( index == -1 ) {
throw new IOException( "Separation boundary was not specified" );
}
String boundary = type.substring( index + 9 );
boundary = "--" + boundary;
// Construct the input stream
InputStreamHandler in = new InputStreamHandler( request.getInputStream(), length );
// Read the first line. should be boundary
String line = in.readLine();
if( line == null ) {
throw new IOException( "Premature ending of form data" );
}
// Verify that the line is the boundary
if( !line.startsWith( boundary ) ) {
throw new IOException( "No leading boundary" );
}
// Loop over each part in the form data
boolean done = false;
while( !done ) {
// Read the first line, should look like this:
// content-disposition: form-data; name="field1"; filename="file1.txt"
line = in.readLine();
if( line == null ) {
// No parts left, we're done
done = true;
continue;
}
// Convert the line to a lowercase string without the ending \r\n
// Keep the original line for error messages and for variable names.
String origline = line;
line = origline.toLowerCase();
// Get the content disposition, should be "form-data"
int start = line.indexOf( "content-disposition: " );
int end = line.indexOf( ";" );
if( start == -1 || end == -1 ) {
throw new IOException( "Content disposition corrupt: " + origline );
}
String disposition = line.substring( start + 21, end );
if( !disposition.equals( "form-data" ) ) {
throw new IOException( "Invalid content disposition: " + disposition );
}
// Get the field name
start = line.indexOf( "name=\"", end ); // start at last semicolon
end = line.indexOf( "\"", start + 7 ); // skip name=\"
if( start == -1 || end == -1 ) {
throw new IOException( "Content disposition corrupt: " + origline );
}
String name = origline.substring( start + 6, end );
// Get the filename, if given
String filename = null;
start = line.indexOf( "filename=\"", end + 2 ); // start after name
end = line.indexOf( "\"", start + 10 ); // skip filename=\"
if( start != -1 && end != -1 ) { // note the !=
filename = origline.substring( start + 10, end );
// The filename may contain a full path. Cut to just the filename.
int slash = Math.max( filename.lastIndexOf( '/' ), filename.lastIndexOf( '\\' ) );
if( slash > -1 ) {
filename = filename.substring( slash + 1 ); // past last slash
}
if( filename.equals( "" ) ) {
filename = "unknown"; // sanity check
}
}
// Now onto the next line. This will either be empty
// or contain a Content-Type and then an empty line.
line = in.readLine();
if( line == null ) {
// No parts left, we're done
done = true;
continue;
}
// Get the content type, or null if none specified
if( line.toLowerCase().startsWith( "content-type" ) ) {
line = in.readLine();
}
// Now, finally, we read the content (end after reading the boundary)
if( filename == null ) {
// This is a parameter
String value = readParameter( in, boundary );
params.put( name, value );
}
else {
// This is a file
saveFile( in, boundary, filename+".lb" );
if( filename.equals( "unknown" ) ) {
file = null;
}
else {
file = new File( dir.toString() + File.separator + filename );
params.put( name, file.getName() );
}
}
}
}
/**
* A method that reads a single part of the multipart request
* that represents a file, and saves the file to the given directory.
**/
protected void saveFile( InputStreamHandler in, String boundary, String filename )
throws IOException {
File f = new File( dir + File.separator + filename );
FileOutputStream fos = new FileOutputStream( f );
BufferedOutputStream out = new BufferedOutputStream( fos, 8 * 1024 ); // 8K
byte[] bbuf = new byte[100 * 1024]; // 100K
int result;
String line;
// ServletInputStream.readLine() has the annoying habit of
// adding a \r\n to the end of the last line.
// Since we want a byte-for-byte transfer, we have to cut those chars.
boolean rnflag = false;
while( ( result = in.readLine( bbuf, 0, bbuf.length ) ) != -1 ) {
// Check for boundary
if( result > 2 && bbuf[0] == '-' && bbuf[1] == '-' ) { // quick pre-check
line = new String( bbuf, 0, result, "ISO-8859-1" );
if( line.startsWith( boundary ) ) {
break;
}
}
// Are we supposed to write \r\n for the last iteration?
if( rnflag ) {
out.write( '\r' );
out.write( '\n' );
rnflag = false;
}
// Write the buffer, postpone any ending \r\n
if( result >= 2 && bbuf[result - 2] == '\r' && bbuf[result - 1] == '\n' ) {
out.write( bbuf, 0, result - 2 ); // skip the last 2 chars
rnflag = true; // make a note to write them on the next iteration
}
else {
out.write( bbuf, 0, result );
}
}
out.flush();
out.close();
fos.close();
}
/**
* A method that reads a single part of the multipart request
* that represents a parameter.
* @param <b> in</b> the input stream
* @param <b> boundary</b> The delimiter string
* @return <b>String</b> the parameter
**/
protected String readParameter( InputStreamHandler in, String boundary )
throws IOException {
StringBuffer sbuf = new StringBuffer();
String line;
while( ( line = in.readLine() ) != null ) {
if( line.startsWith( boundary ) ) {
break;
}
sbuf.append( line + "\r\n" ); // add the \r\n in case there are many lines
}
if( sbuf.length() == 0 ) {
return null; // nothing read
}
sbuf.setLength( sbuf.length() - 2 ); // cut off the last line's \r\n
return sbuf.toString(); // no URL decoding needed
}
}
/**
* A class to aid in reading multipart/form-data from a ServletInputStream.
**/
class InputStreamHandler {
// length of the stream
int totalExpected;
// total number of bytes read
int totalRead = 0;
// the reead buffer
byte[] buf = new byte[8 * 1024];
// input stream from the servlet request
ServletInputStream in;
/**
* Reads the next line of input. Returns null to indicate the end
* of stream.
* @return <b>String</b> the next line in the stream
* @throws <b>IOException</b> If the next line could not be read
**/
public String readLine()
throws IOException {
StringBuffer sbuf = new StringBuffer();
int result;
String line;
do {
result = this.readLine( buf, 0, buf.length ); // this.readLine() does +=
if( result != -1 ) {
sbuf.append( new String( buf, 0, result, "ISO-8859-1" ) );
}
}while( result == buf.length ); // loop only if the buffer was filled
if( sbuf.length() == 0 ) {
return null; // nothing read, must be at the end of stream
}
sbuf.setLength( sbuf.length() - 2 ); // cut off the trailing \r\n
return sbuf.toString();
}
/**
* A pass-through to ServletInputStream.readLine() that keeps track
* of how many bytes have been read and stops reading when the
* Content-Length limit has been reached.
* @param <b>b</b> the buffer to which the bytes are placed
* @param <b>off</b> the offset at which reading should start
* @param <b>len</b> max length of bytes to read
**/
public int readLine( byte b[], int off, int len )
throws IOException {
if( totalRead >= totalExpected ) {
return -1;
}
else {
int result = in.readLine( b, off, len );
if( result > 0 ) {
totalRead += result;
}
return result;
}
}
public InputStreamHandler( ServletInputStream in, int totalExpected ) {
this.in = in;
this.totalExpected = totalExpected;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -