大概的协议格式为:
头呢有酱婶的信息:[注:${bound}这个是边界占位符会在body用到]
Content-Type: multipart/form-data; boundary=${bound}
multipart/form-data body呢大概是酱婶的:
--${bound}
Content-Disposition: form-data; name="Filename"
HTTP.pdf
--${bound}
Content-Disposition: form-data; name="file000"; filename="HTTP协议详解.pdf"
Content-Type: application/octet-stream
%PDF-1.5
file content
%%EOF
--${bound}
Content-Disposition: form-data; name="Upload"
Submit Query
--${bound}--
no picture say ge j8? 上栗子
Content-Type:
multipart/form-data; boundary=----WebKitFormBoundaryqao1oDQOjWcGVMoa
更有说服力的源码上场了:
commons-fileupload源码是酱婶说的:
public List parseRequest(RequestContext ctx) throws FileUploadException {
List items = new ArrayList();
boolean successful = false;
boolean var21 = false;
FileItem fileItem;
ArrayList var29;
try {
var21 = true;
FileItemIterator iter = this.getItemIterator(ctx);
FileItemFactory fac = this.getFileItemFactory();
if(fac == null) {
throw new NullPointerException("No FileItemFactory has been set.");
}
while(true) {
if(!iter.hasNext()) {
successful = true;
var29 = items;
var21 = false;
break;
}
FileItemStream item = iter.next();
String fileName = ((FileUploadBase.FileItemIteratorImpl.FileItemStreamImpl)item).name;
fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
items.add(fileItem);
try {
Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
} catch (FileUploadBase.FileUploadIOException var24) {
throw (FileUploadException)var24.getCause();
} catch (IOException var25) {
throw new FileUploadBase.IOFileUploadException("Processing of multipart/form-data request failed. " + var25.getMessage(), var25);
}
if(fileItem instanceof FileItemHeadersSupport) {
FileItemHeaders fih = item.getHeaders();
((FileItemHeadersSupport)fileItem).setHeaders(fih);
}
}
} catch (FileUploadBase.FileUploadIOException var26) {
throw (FileUploadException)var26.getCause();
} catch (IOException var27) {
throw new FileUploadException(var27.getMessage(), var27);
} finally {
if(var21) {
if(!successful) {
Iterator iterator = items.iterator();
while(iterator.hasNext()) {
FileItem fileItem = (FileItem)iterator.next();
try {
fileItem.delete();
} catch (Throwable var22) {
;
}
}
}
}
}
if(!successful) {
Iterator iterator = items.iterator();
while(iterator.hasNext()) {
fileItem = (FileItem)iterator.next();
try {
fileItem.delete();
} catch (Throwable var23) {
;
}
}
}
return var29;
}
根据parseRequest方法中的Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
得知FileItemIterator 生出的 FileItemStream 和 怎么生的是我们关注的地方:
FileItemIterator:
FileItemIteratorImpl(RequestContext ctx) throws FileUploadException, IOException { if(ctx == null) { throw new NullPointerException("ctx parameter"); } else { String contentType = ctx.getContentType(); if(null != contentType && contentType.toLowerCase().startsWith("multipart/")) { InputStream input = ctx.getInputStream(); if(FileUploadBase.this.sizeMax >= 0L) { int requestSize = ctx.getContentLength(); if(requestSize == -1) { input = new LimitedInputStream((InputStream)input, FileUploadBase.this.sizeMax) { protected void raiseError(long pSizeMax, long pCount) throws IOException { FileUploadException ex = new FileUploadBase.SizeLimitExceededException("the request was rejected because its size (" + pCount + ") exceeds the configured maximum" + " (" + pSizeMax + ")", pCount, pSizeMax); throw new FileUploadBase.FileUploadIOException(ex); } }; } else if(FileUploadBase.this.sizeMax >= 0L && (long)requestSize > FileUploadBase.this.sizeMax) { throw new FileUploadBase.SizeLimitExceededException("the request was rejected because its size (" + requestSize + ") exceeds the configured maximum (" + FileUploadBase.this.sizeMax + ")", (long)requestSize, FileUploadBase.this.sizeMax); } } String charEncoding = FileUploadBase.this.headerEncoding; if(charEncoding == null) { charEncoding = ctx.getCharacterEncoding(); } this.boundary = FileUploadBase.this.getBoundary(contentType); if(this.boundary == null) { throw new FileUploadException("the request was rejected because no multipart boundary was found"); } else { this.notifier = new ProgressNotifier(FileUploadBase.this.listener, (long)ctx.getContentLength()); this.multi = new MultipartStream((InputStream)input, this.boundary, this.notifier); this.multi.setHeaderEncoding(charEncoding); this.skipPreamble = true; this.findNextItem(); } } else { throw new FileUploadBase.InvalidContentTypeException("the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is " + contentType); } } }
呜呜喳喳一大堆,发现了这个:MultipartStream构造如下:很显然boundary被保留起来了;this.input = input; this.bufSize = bufSize; this.buffer = new byte[bufSize]; this.notifier = pNotifier; this.boundary = new byte[boundary.length + BOUNDARY_PREFIX.length]; this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length; this.keepRegion = this.boundary.length; System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length); System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); this.head = 0; this.tail = 0;
在FileItemStream中发现:
FileItemStreamImpl(String pName, String pFieldName, String pContentType, boolean pFormField, long pContentLength) throws IOException {
this.name = pName;
this.fieldName = pFieldName;
this.contentType = pContentType;
this.formField = pFormField;
final ItemInputStream itemStream = FileItemIteratorImpl.this.multi.newInputStream();
InputStream istream = itemStream;
if(FileUploadBase.this.fileSizeMax != -1L) {
if(pContentLength != -1L && pContentLength > FileUploadBase.this.fileSizeMax) {
FileUploadBase.FileSizeLimitExceededException e = new FileUploadBase.FileSizeLimitExceededException("The field " + this.fieldName + " exceeds its maximum permitted " + " size of " + FileUploadBase.this.fileSizeMax + " bytes.", pContentLength, FileUploadBase.this.fileSizeMax);
e.setFileName(pName);
e.setFieldName(pFieldName);
throw new FileUploadBase.FileUploadIOException(e);
}
istream = new LimitedInputStream(itemStream, FileUploadBase.this.fileSizeMax) {
protected void raiseError(long pSizeMax, long pCount) throws IOException {
itemStream.close(true);
FileUploadBase.FileSizeLimitExceededException e = new FileUploadBase.FileSizeLimitExceededException("The field " + FileItemStreamImpl.this.fieldName + " exceeds its maximum permitted " + " size of " + pSizeMax + " bytes.", pCount, pSizeMax);
e.setFieldName(FileItemStreamImpl.this.fieldName);
e.setFileName(FileItemStreamImpl.this.name);
throw new FileUploadBase.FileUploadIOException(e);
}
};
}
this.stream = (InputStream)istream;
}
MultipartStream.ItemInputStream newInputStream() {
return new MultipartStream.ItemInputStream();
}
multi也就是MultipartStream被用来开流了,MultipartStream又用到了ItemInputStream
以下部分开始处理那body里的数据了,反正看起来很厉害的样子。
ItemInputStream() {
this.findSeparator();
}
private void findSeparator() {
this.pos = MultipartStream.this.findSeparator();
if(this.pos == -1) {
if(MultipartStream.this.tail - MultipartStream.this.head > MultipartStream.this.keepRegion) {
this.pad = MultipartStream.this.keepRegion;
} else {
this.pad = MultipartStream.this.tail - MultipartStream.this.head;
}
}
}
public int available() throws IOException {
return this.pos == -1?MultipartStream.this.tail - MultipartStream.this.head - this.pad:this.pos - MultipartStream.this.head;
}
public int read() throws IOException {
if(this.closed) {
throw new ItemSkippedException();
} else if(this.available() == 0 && this.makeAvailable() == 0) {
return -1;
} else {
++this.total;
int b = MultipartStream.this.buffer[MultipartStream.this.head++];
return b >= 0?b:b + 256;
}
}
public int read(byte[] b, int off, int len) throws IOException {
if(this.closed) {
throw new ItemSkippedException();
} else if(len == 0) {
return 0;
} else {
int res = this.available();
if(res == 0) {
res = this.makeAvailable();
if(res == 0) {
return -1;
}
}
res = Math.min(res, len);
System.arraycopy(MultipartStream.this.buffer, MultipartStream.this.head, b, off, res);
MultipartStream.this.head = res;
this.total += (long)res;
return res;
}
}
private int makeAvailable() throws IOException {
if(this.pos != -1) {
return 0;
} else {
this.total += (long)(MultipartStream.this.tail - MultipartStream.this.head - this.pad);
System.arraycopy(MultipartStream.this.buffer, MultipartStream.this.tail - this.pad, MultipartStream.this.buffer, 0, this.pad);
MultipartStream.this.head = 0;
MultipartStream.this.tail = this.pad;
int av;
do {
int bytesRead = MultipartStream.this.input.read(MultipartStream.this.buffer, MultipartStream.this.tail, MultipartStream.this.bufSize - MultipartStream.this.tail);
if(bytesRead == -1) {
String msg = "Stream ended unexpectedly";
throw new MultipartStream.MalformedStreamException("Stream ended unexpectedly");
}
if(MultipartStream.this.notifier != null) {
MultipartStream.this.notifier.noteBytesRead(bytesRead);
}
MultipartStream.this.tail = bytesRead;
this.findSeparator();
av = this.available();
} while(av <= 0 && this.pos == -1);
return av;
}
}
基本完成只能说666...
spring:
servlet:
未完待续...
参考:(请以协议为准,其他资料仅供参考)
http1.1协议 点击打开链接 点击打开链接 点击打开链接 点击打开链接
百度http协议点击打开链接
spring-multipart API 点击打开链接
servlet3.0 点击打开链接
fileupload 点击打开链接 点击打开链接 点击打开链接
单文件servlet API 点击打开链接 点击打开链接 点击打开链接
http multipart 点击打开链接