1 5 package com.teamkonzept.web; 6 7 import java.io.*; 8 9 import com.teamkonzept.lib.*; 10 11 public class TKHttpMultipartBuffer { 12 public static final byte[] END_OF_HEADER = { 13, 10, 13, 10 }; 13 public static final String CRLF = "\015\012"; 14 16 public int maxBufferSize = 5000; 17 public byte[] buffer; public int bufferEntries; public InputStream dataStream; public int contentLength; public byte[] boundary; public int boundaryLength; public int boundaryStart; 26 27 public TKHttpMultipartBuffer( InputStream is, int length, String boundary ) 28 throws IOException 29 { 30 this.dataStream = is; 31 this.contentLength = length; 32 if( boundary != null ) { 33 this.boundaryLength = boundary.length()+2; 34 this.boundary = new byte[ this.boundaryLength ]; 35 this.boundary[0] = (byte) '-'; 36 this.boundary[1] = (byte) '-'; 37 boundary.getBytes( 0, this.boundaryLength-2, this.boundary, 2 ); 38 } 39 this.bufferEntries = 0; 40 this.boundaryStart = -1; 41 42 init(); 43 } 44 45 public void init() 46 throws IOException 47 { 48 if( boundary != null ) { 49 dataStream.skip( boundary.length+2 ); 50 } 51 else { 52 StringBuffer boundBuf = new StringBuffer (); 54 int lastRead = dataStream.read(); 55 int currChar; 56 while( ! 57 ( ((currChar = dataStream.read()) == 10 58 &&( lastRead == 13 )) ) 59 ) { 60 boundBuf.append( (char) lastRead ); 61 lastRead = currChar; 62 } 63 boundaryLength = boundBuf.length(); 64 boundBuf.toString().getBytes( 0, boundaryLength, boundary, 0 ); 65 } 66 67 contentLength -= boundaryLength+2; 69 70 if( maxBufferSize < boundary.length ) { 71 maxBufferSize = boundary.length*2; 72 } 73 74 buffer = new byte[ maxBufferSize ]; 75 } 76 77 119 public boolean hasMoreHeaders() 120 { 121 return (bufferEntries > 0) || (contentLength > 0); 122 } 123 124 public int arrayIndexOf( byte[] buf, byte[] pat ) 125 { 126 return arrayIndexOf( buf, buf.length, pat, 0 ); 127 } 128 129 public int arrayIndexOf( byte[] buf, int length, byte[] pat ) 130 { 131 return arrayIndexOf( buf, length, pat, 0 ); 132 } 133 134 public int arrayIndexOf( byte[] buf, byte[] pat, int startIdx ) 135 { 136 return arrayIndexOf( buf, buf.length, pat, startIdx ); 137 } 138 139 public int arrayIndexOf( byte[] buf, int length, byte[] pat, int startIdx ) 140 { 141 return (new String ( buf, 0, startIdx, length-startIdx )) 142 .indexOf( new String ( pat, 0 ), 0 ) + startIdx; 143 } 144 145 public void expandBuffer( int newSize ) 146 { 147 byte[] newBuffer = new byte[ newSize ]; 148 System.arraycopy( buffer, 0, newBuffer, 0, bufferEntries ); 149 buffer = newBuffer; 150 maxBufferSize = newSize; 151 } 152 153 public void stripBuffer( int firstEntries ) 154 { 155 if( (bufferEntries -= firstEntries) > 0 ) { 156 System.arraycopy( buffer, firstEntries, buffer, 0, bufferEntries ); 157 } 158 } 159 160 163 164 public TKHashtable nextHeader() 165 throws IOException 166 { 167 boolean ok = false; 168 boolean bad = false; 169 int endIdx = -1; 170 171 int nextStart = 0; 172 do { 173 fillBuffer( maxBufferSize ); 174 ok = ( (endIdx = arrayIndexOf( buffer, END_OF_HEADER, nextStart )) >= 0 ) 177 || (bufferEntries == 0); 178 if( !ok ) { 179 bad = (contentLength <= 0); 180 if( bufferEntries == maxBufferSize ) { 181 expandBuffer( maxBufferSize * 2 ); 182 nextStart = bufferEntries-END_OF_HEADER.length+1; 183 } 184 } 185 } while( !( ok || bad ) ); 186 187 if( bad ) throw new Error ( "Format-error in multipart-encoded data" ); 188 189 String bufferStr = new String ( buffer, 0, 0, endIdx+2 ); 190 TKHashtable result = new TKHashtable(); 191 if( endIdx > 0 ) { 192 int startPos = 0; 193 while( startPos < endIdx + 2 ) { 194 int colonPos = bufferStr.indexOf( ':', startPos ); 195 int endOfLinePos = bufferStr.indexOf( CRLF, colonPos+1 ); 196 result.put( 197 bufferStr.substring( startPos, colonPos ).toLowerCase(), 198 bufferStr.substring( colonPos+2, endOfLinePos ) 199 ); 200 startPos = endOfLinePos + 2; 201 } 202 } 203 stripBuffer( endIdx+4 ); 204 return result; 205 } 206 207 public String nextBody() 208 throws IOException 209 { 210 String body = ""; 211 int bodySize = 0; 212 while( (bodySize = nextBodyChunk()) != -1 ) { 213 body += new String ( buffer, 0, 0, bodySize ); 214 } 215 return body; 216 } 217 218 public int nextBodyChunk() 219 throws IOException 220 { 221 if( boundaryStart != -1 ) { 222 if( boundaryStart >= 0 ) { 224 if( (buffer[boundaryStart+boundaryLength] == (byte) '-') && 226 (buffer[boundaryStart+boundaryLength+1] == (byte) '-') ) { 227 bufferEntries = 0; 229 contentLength = 0; 230 boundaryStart = -1; 231 return -1; 232 } 233 stripBuffer( boundaryStart + boundaryLength + 2 ); 235 boundaryStart = -1; 236 return -1; 237 } 238 else { 239 stripBuffer( bufferEntries - boundaryLength - 1 ); 241 } 242 } 243 244 fillBuffer( maxBufferSize ); 246 247 boundaryStart = arrayIndexOf( buffer, boundary ); 249 250 if( (boundaryStart < 0) && (contentLength <= 0) ) { 252 throw new Error ("malformed multipart POST"); 253 } 254 255 if( boundaryStart > 0 ) 256 return boundaryStart-2; 258 259 boundaryStart = -2; 261 262 267 return bufferEntries - boundaryLength - 1; 268 } 269 270 275 276 public void fillBuffer( int maxSize ) 277 throws IOException 278 { 279 if( contentLength <= 0 ) return; 280 281 int bytesToRead = maxSize - bufferEntries; 283 if( bytesToRead > contentLength ) 284 bytesToRead = contentLength; 285 286 int bytesRead = dataStream.read( buffer, bufferEntries, bytesToRead ); 287 288 contentLength -= bytesRead; 289 bufferEntries += bytesRead; 290 } 291 292 public TKHashtable getParams() 293 throws IOException 294 { 295 TKHashtable params = new TKHashtable(); 296 297 while( hasMoreHeaders() ) { 298 TKHashtable header = nextHeader(); 299 String disposition = (String ) header.get("content-disposition"); 300 301 int nameStart = disposition.indexOf(" name=\"")+7; 302 int nameEnd = disposition.indexOf('"',nameStart); 303 String name = disposition.substring( nameStart, nameEnd ); 304 305 String filename = null; 306 int fileStart = disposition.indexOf(" filename=\"")+11; 307 if( fileStart >= 11 ) { 308 filename = disposition.substring( fileStart, disposition.length()-1 ); 309 } 310 311 if( filename == null ) { 312 params.extend( name, nextBody() ); 314 } 315 else { 316 File tempFile = TKTemporaryFile.newTempFile(); 318 OutputStream temp = new FileOutputStream( tempFile ); 319 int chunkSize; 320 while( (chunkSize = nextBodyChunk()) != -1 ) { 321 temp.write( buffer, 0, chunkSize ); 322 } 323 temp.close(); 324 params.extend( name, new TKUploadFileInputStream( tempFile, filename, header ) ); 325 } 326 } 327 return params; 328 } 329 } 330 331 | Popular Tags |