blob: 460d3f34e91937624c497d920bac5e651392077d [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.base.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
/**
* HttpRequestFileUpload - Receive a file upload through an HttpServletRequest
*
*/
public class HttpRequestFileUpload {
private int BUFFER_SIZE = 4096;
private int WAIT_INTERVAL = 200; // in milliseconds
private int MAX_WAITS = 20;
private int waitCount = 0;
private String savePath;
private String filepath;
private String filename;
private String contentType;
private String overrideFilename = null;
private Map<String, String> fields;
public String getOverrideFilename() {
return overrideFilename;
}
public void setOverrideFilename(String ofName) {
overrideFilename = ofName;
}
public String getFilename() {
return filename;
}
public String getFilepath() {
return filepath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String getContentType() {
return contentType;
}
public String getFieldValue(String fieldName) {
if (fields == null || fieldName == null)
return null;
return fields.get(fieldName);
}
private void setFilename(String s) {
if (s == null)
return;
int pos = s.indexOf("filename=\"");
if (pos != -1) {
filepath = s.substring(pos + 10, s.length() - 1);
// Windows browsers include the full path on the client
// But Linux/Unix and Mac browsers only send the filename
// test if this is from a Windows browser
pos = filepath.lastIndexOf("\\");
if (pos != -1)
filename = filepath.substring(pos + 1);
else
filename = filepath;
}
}
private void setContentType(String s) {
if (s == null)
return;
int pos = s.indexOf(": ");
if (pos != -1)
contentType = s.substring(pos + 2, s.length());
}
public void doUpload(HttpServletRequest request) throws IOException {
ServletInputStream in = request.getInputStream();
String reqLengthString = request.getHeader("content-length");
System.out.println("expect " + reqLengthString + " bytes.");
int requestLength = 0;
try {
requestLength = Integer.valueOf(reqLengthString).intValue();
} catch (Exception e2) {
e2.printStackTrace();
return;
}
byte[] line = new byte[BUFFER_SIZE];
int i = -1;
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
if (i < 3)
return;
int boundaryLength = i - 2;
String boundary = new String(line, 0, boundaryLength); // -2 discards the newline character
System.out.println("boundary=[" + boundary + "] length is " + boundaryLength);
fields = new HashMap<String, String>();
while (requestLength > 0/* i != -1*/) {
String newLine = "";
if (i > -1) {
newLine = new String(line, 0, i);
}
if (newLine.startsWith("Content-Disposition: form-data; name=\"")) {
if (newLine.indexOf("filename=\"") != -1) {
setFilename(new String(line, 0, i - 2));
if (filename == null)
return;
// this is the file content
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
setContentType(new String(line, 0, i - 2));
// blank line
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
newLine = new String(line, 0, i);
String filenameToUse = filename;
if (overrideFilename != null) {
filenameToUse = overrideFilename;
}
// first line of actual file
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
newLine = new String(line, 0, i);
byte[] lastTwoBytes = new byte[2];
if (i > 1) {
lastTwoBytes[0] = line[i - 2];
lastTwoBytes[1] = line[i - 1];
}
System.out.println("about to create a file:" + (savePath == null ? "" : savePath) + filenameToUse);
// before creating the file make sure directory exists
File savePathFile = new File(savePath);
if (!savePathFile.exists()) {
savePathFile.mkdirs();
}
FileOutputStream fos = new FileOutputStream((savePath == null ? "" : savePath) + filenameToUse);
boolean bail = (new String(line, 0, i).startsWith(boundary));
boolean oneByteLine = (i == 1); // handle one-byte lines
while ((requestLength > 0/* i != -1*/) && !bail) {
// write the current buffer, except the last 2 bytes;
if (i > 1) {
fos.write(line, 0, i - 2);
}
oneByteLine = (i == 1); // we need to track on-byte lines differently
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
// the problem is the last line of the file content
// contains the new line character.
// if the line just read was the last line, we're done.
// if not, we must write the last 2 bytes of the previous buffer
// just assume that a one-byte line isn't the last line
if (requestLength < 1) {
bail = true;
} else if (oneByteLine) {
fos.write(lastTwoBytes, 0, 1); // we only saved one byte
} else {
fos.write(lastTwoBytes, 0, 2);
}
if (i > 1) {
// save the last 2 bytes of the buffer
lastTwoBytes[0] = line[i - 2];
lastTwoBytes[1] = line[i - 1];
} else {
lastTwoBytes[0] = line[0]; // only save one byte
}
}
fos.flush();
fos.close();
} else {
// this is a field
// get the field name
int pos = newLine.indexOf("name=\"");
String fieldName = newLine.substring(pos + 6, newLine.length() - 3);
// blank line
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
newLine = new String(line, 0, i);
StringBuilder fieldValue = new StringBuilder(BUFFER_SIZE);
while (requestLength > 0/* i != -1*/ && !newLine.startsWith(boundary)) {
// The last line of the field
// contains the new line character.
// So, we need to check if the current line is
// the last line.
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
requestLength -= i;
if ((i == boundaryLength + 2 || i == boundaryLength + 4) // + 4 is eof
&& (new String(line, 0, i).startsWith(boundary)))
fieldValue.append(newLine.substring(0, newLine.length() - 2));
else
fieldValue.append(newLine);
newLine = new String(line, 0, i);
}
fields.put(fieldName, fieldValue.toString());
}
}
i = waitingReadLine(in, line, 0, BUFFER_SIZE, requestLength);
if (i > -1) {
requestLength -= i;
}
} // end while
}
// reads a line, waiting if there is nothing available and reqLen > 0
private int waitingReadLine(ServletInputStream in, byte[] buf, int off, int len, int reqLen) throws IOException {
int i = -1;
while (((i = in.readLine(buf, off, len)) == -1) && (reqLen > 0)) {
System.out.print("waiting");
if (waitCount > MAX_WAITS) {
System.out.println("waited " + waitCount + " times, bailing out while still expecting " +
reqLen + " bytes.");
throw new IOException("waited " + waitCount + " times, bailing out while still expecting " +
reqLen + " bytes.");
}
waitCount++;
long endMS = new Date().getTime() + WAIT_INTERVAL;
while (endMS > (new Date().getTime())) {
try {
wait(WAIT_INTERVAL);
} catch (Exception e3) {
System.out.print(".");
}
}
System.out.println((new Date().getTime() - endMS) + " ms");
}
return i;
}
}