package com.alimama.web.adhoc;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.log4j.Logger;
import org.mortbay.log.Log;
import com.alimama.web.ByteBuffer;
public class Upload {
private static Logger LOG = Logger.getLogger(Upload.class);
private static int BUFFER_LEN=10240;
private static int HEADER_SIZE=102400;
char[] buffer = new char[BUFFER_LEN];
//----boundary----
private char[] m_boundary = new char[HEADER_SIZE];
private int m_boundary_length=0;
private boolean foundBoundary = false;
//----for file split---
int boundarySkipLen=0;
//----for header read----
private boolean foundHeader=false;
//----header info-----
private String dataHeader = new String();
private String fieldName = new String();
private String fileName = new String();
private String fileExt = new String();
private String filePathName = new String();
private String contentType = new String();
private String contentDisp = new String();
private String typeMIME = new String();
private String subTypeMIME = new String();
private boolean isFile = false;
private void resetHeader()
{
this.foundHeader=false;
this.boundarySkipLen=0;
}
private int setBoundary(int readBytes,int i)
{
for(; !foundBoundary && i<readBytes; i++)
{
if(buffer[i] == 13)
{
foundBoundary = true;
char[] newboundary=new char[m_boundary_length];
for(int j=0;j<m_boundary_length;j++)
{
newboundary[j]=m_boundary[j];
}
m_boundary=newboundary;
break;
}
else
{
int currindex=m_boundary_length;
m_boundary_length++;
m_boundary[currindex]=buffer[i];
}
}
return i;
}
private static char[] headerSplit={13,42,13};
private char[] splitbuffer=new char[0];
private boolean setHearder(int readBytes,int i,String charset) throws UnsupportedEncodingException
{
int leftdata=readBytes-i;
int lastlen=splitbuffer.length;
char[] tmpbyte=new char[lastlen+leftdata];
for(int j=0;j<lastlen;j++)
{
tmpbyte[j]=splitbuffer[j];
}
for(int j=0;j<leftdata;j++)
{
tmpbyte[j+lastlen]=buffer[j+i];
}
ByteSplit split=this.readUntil(tmpbyte, headerSplit,true);
splitbuffer=split.left;
foundHeader=split.isfullcut;
if(foundHeader)
{
dataHeader = new String(split.read, 0, split.read.length);
LOG.info("@@@@@@@dataHeader:" + dataHeader + "@@@@"
+ new String(m_boundary, 0, m_boundary_length));
isFile = dataHeader.indexOf("filename") > 0;
fieldName = getDataFieldValue(dataHeader, "name");
if (isFile) {
filePathName = getDataFieldValue(dataHeader, "filename");
fileName = getFileName(filePathName);
fileExt = getFileExt(fileName);
contentType = getContentType(dataHeader);
contentDisp = getContentDisp(dataHeader);
typeMIME = getTypeMIME(contentType);
subTypeMIME = getSubTypeMIME(contentType);
LOG.info("@@@@@@@file:" + fieldName + "," + filePathName
+ "," + fileName);
}
}
return foundHeader;
}
private boolean setHeadVal(int readBytes,int i,String charset,OutputStreamWriter out,HashMap<String,String> params) throws IOException
{
int leftdata=readBytes-i;
int lastlen=splitbuffer.length;
char[] tmpbyte=new char[lastlen+leftdata];
for(int j=0;j<lastlen;j++)
{
tmpbyte[j]=splitbuffer[j];
}
for(int j=0;j<leftdata;j++)
{
tmpbyte[j+lastlen]=buffer[j+i];
}
ByteSplit split=this.readUntil(tmpbyte, m_boundary,false);
splitbuffer=split.left;
foundHeader=split.isfullcut;
for(int j=0;j<split.read.length;j++)
{
writebuff.append(split.read[j]);
}
if(writebuff.size()>10240&&isFile)
{
out.write(writebuff.toArray(),0,writebuff.size());
writebuff=new ByteBuffer(10752);
}
if(split.isfullcut)
{
this.skip(out, writebuff, charset, params);
writebuff=new ByteBuffer(10752);
}
return split.isfullcut;
}
ByteBuffer writebuff=new ByteBuffer(10752);
public void mergerTo(HttpServletRequest request, HttpServletResponse response,String charset,OutputStreamWriter out,HashMap<String,String> params) throws IOException
{
// int totalBytes = request.getContentLength();
// ServletInputStream in=request.getInputStream();
InputStreamReader in=new InputStreamReader(request.getInputStream(), "gbk") ;
// OutputStreamWriter osw = new OutputStreamWriter(System.out, "UTF-8");
// osw.
int readBytes = 0;
this.resetHeader();
boolean isReadHeader=true;
int index=0;
int totalRead=0;
while(true)
{
// int size=totalBytes - totalRead;
readBytes = in.read(buffer, 0, BUFFER_LEN);
if(index++%10000==0)
{
Log.info("total read="+totalRead);
}
if(readBytes<0)
{
break;
}
totalRead += readBytes;
int i=0;
i=this.setBoundary(readBytes, i);
if(i>=readBytes)
{
continue;
}
boolean isloop=true;
while(isloop)
{
isloop=false;
if(isReadHeader)
{
if(this.setHearder(readBytes, i,charset))
{
isReadHeader=false;
isloop=true;
}
}else{
if(this.setHeadVal( readBytes, i, charset, out, params))
{
isReadHeader=true;
isloop=true;
}
}
i=readBytes;
}
}
if(this.splitbuffer.length>0)
{
for(int j=0;j<this.splitbuffer.length;j++)
{
writebuff.append(splitbuffer[j]);
}
}
if(writebuff.size()>0&&!keys.contains(fieldName))
{
if(isFile)
{
out.write(writebuff.toArray(),0,writebuff.size());
}else{
String val=new String(writebuff.toArray(),0,writebuff.size()).replaceAll("^[\r|\n]*", "").replaceAll("[\r|\n]*$", "");
params.put(fieldName, val);
LOG.info("@@@@@@@keyval_final:"+fieldName+"="+val);
}
writebuff=new ByteBuffer(10752);
}
}
HashSet<String> keys=new HashSet<String>();
private void skip(OutputStreamWriter out, ByteBuffer writebuff,String charset,HashMap<String,String> params) throws IOException
{
keys.add(fieldName);
if(this.isFile)
{
out.write(writebuff.toArray(),0,writebuff.size());
}else{
String val=new String(writebuff.toArray(),0,writebuff.size()).replaceAll("^[\r|\n]*", "").replaceAll("[\r|\n]*$", "");
params.put(fieldName, val);
LOG.info("@@@@@@@keyval:"+fieldName+"="+val);
}
this.resetHeader();
}
private String getFileExt(String fileName)
{
String value = new String();
int start = 0;
int end = 0;
if(fileName == null)
return null;
start = fileName.lastIndexOf(46) + 1;
end = fileName.length();
value = fileName.substring(start, end);
if(fileName.lastIndexOf(46) > 0)
return value;
else
return "";
}
private String getContentType(String dataHeader)
{
String token = new String();
String value = new String();
int start = 0;
int end = 0;
token = "Content-Type:";
start = dataHeader.indexOf(token) + token.length();
if(start != -1)
{
end = dataHeader.length();
value = dataHeader.substring(start, end);
}
return value;
}
private String getTypeMIME(String ContentType)
{
int pos = 0;
pos = ContentType.indexOf("/");
if(pos != -1)
return ContentType.substring(1, pos);
else
return ContentType;
}
private String getSubTypeMIME(String ContentType)
{
int start = 0;
int end = 0;
start = ContentType.indexOf("/") + 1;
if(start != -1)
{
end = ContentType.length();
return ContentType.substring(start, end);
} else
{
return ContentType;
}
}
private String getContentDisp(String dataHeader)
{
String value = new String();
int start = 0;
int end = 0;
start = dataHeader.indexOf(":") + 1;
end = dataHeader.indexOf(";");
value = dataHeader.substring(start, end);
return value;
}
private String getDataFieldValue(String dataHeader, String fieldName)
{
String token = new String();
String value = new String();
int pos = 0;
int i = 0;
int start = 0;
int end = 0;
token = String.valueOf((new StringBuffer(String.valueOf(fieldName))).append("=").append('"'));
pos = dataHeader.indexOf(token);
if(pos > 0)
{
i = pos + token.length();
start = i;
token = "\"";
end = dataHeader.indexOf(token, i);
if(start > 0 && end > 0)
value = dataHeader.substring(start, end);
}
return value;
}
private String getFileName(String filePathName)
{
int pos = 0;
pos = filePathName.lastIndexOf(47);
if(pos != -1)
return filePathName.substring(pos + 1, filePathName.length());
pos = filePathName.lastIndexOf(92);
if(pos != -1)
return filePathName.substring(pos + 1, filePathName.length());
else
return filePathName;
}
private static class ByteSplit{
public boolean isfullcut;
public char[] read;
public char[] left;
public ByteSplit(boolean isfullcut, char[] read, char[] left) {
super();
this.isfullcut = isfullcut;
this.read = read;
this.left = left;
}
}
private ByteSplit readUntil(char[] buffer,char[] search,boolean fuzzle) {
final int len = buffer.length;
int matpos=len;
boolean isfound=false;
for (int i = 0; i < len; ++i) {
int leftlen=len-i;
if(this.ismatch(buffer, search,i,0,Math.min(search.length, leftlen),fuzzle))
{
isfound=true;
matpos=i;
break;
}
}
boolean isfullcut=isfound&&(len-matpos>=search.length);
char[] read=new char[matpos];
for(int i=0;i<matpos;i++)
{
read[i]=buffer[i];
}
int offset=matpos;
if(isfullcut)
{
offset+=search.length;
}
int leftlen=len-offset;
leftlen=leftlen>0?leftlen:0;
char[] left=new char[leftlen];
for(int i=0;i<leftlen;i++)
{
left[i]=buffer[i+offset];
}
return new ByteSplit(isfullcut, read, left);
}
private boolean ismatch(char[] buffer,char[] search,int offset,int start,int end,boolean fuzzle)
{
boolean isallMatch=true;
for(int j=start;j<end;j++)
{
if(!this.ismatch(buffer[j+offset], search[j],fuzzle))
{
isallMatch=false;
break;
}
}
return isallMatch;
}
private boolean ismatch(char a,char mat,boolean fuzzle){
if(fuzzle)
{
return mat==42||a==mat;
}
return a==mat;
}
}