KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > teamkonzept > web > TKHttpMultipartBuffer


1 /*
2  * $Header: /cvsroot/webman-cms/source/webman/com/teamkonzept/web/TKHttpMultipartBuffer.java,v 1.8 2001/06/11 09:14:11 alex Exp $
3  *
4  */

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 JavaDoc CRLF = "\015\012";
14     //public static final String END_OF_HEADER = CRLF+CRLF;
15

16     public int maxBufferSize = 5000;
17     public byte[] buffer; // hier werden bis zu maxBufferSize Bytes gespeichert
18
public int bufferEntries; // soviel Bytes sind gerade in buffer noch drin
19
public InputStream dataStream; // Hierher werden die Daten gelesen
20
public int contentLength; // soviele Daten m¸ssen noch gelesen werden
21
public byte[] boundary; // das ist der Trenncode zwischen den Parametern
22
public int boundaryLength; // das ist die L‰nge des Trenncodes
23
public int boundaryStart; // an dieser Stelle in buffer beginnt der naechste Trenncode
24
// -1 := neuer Parameter; -2 := Folge-Parameter
25

26     
27     public TKHttpMultipartBuffer( InputStream is, int length, String JavaDoc 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             // Netscape-Bug mit fehlenden Boundaries umgehen
53
StringBuffer JavaDoc boundBuf = new StringBuffer JavaDoc();
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         // boundary + CRLF ueberspringen
68
contentLength -= boundaryLength+2;
69         
70         if( maxBufferSize < boundary.length ) {
71             maxBufferSize = boundary.length*2;
72         }
73         
74         buffer = new byte[ maxBufferSize ];
75     }
76     
77 /* public int getRequestData( StringBuffer dest, byte[] delimiter )
78         throws IOException
79     {
80         boolean done = false;
81         int delimiterPos = 0;
82         int delimiterLength = delimiter.length;
83         int read = 0;
84         dest.setLength(0);
85         while( true ) {
86             int nextChar = dataStream.read();
87             if( nextChar < 0 ) throw new Error("error in multipart form");
88             read++;
89             dest.append( (char) nextChar );
90             if( nextChar == delimiter[ delimiterPos ] ) {
91                 delimiterPos++;
92                 if( delimiterPos >= delimiterLength ) {
93                     read -= delimiterLength;
94                     dest.setLength( read );
95                     return read-1;
96                 }
97             }
98             else {
99                 delimiterPos = 0;
100             }
101         }
102         return -1;
103     }
104     
105     public TKHashtable getMultipartParams( String boundary, int length )
106     {
107         if( boundary == null ) {
108             final byte[] crlf = { 13, 10 };
109             StringBuffer boundaryBuf = new StringBuffer();
110             length -= appendRequestData( boundaryBuf, crlf );
111             boundary = boundaryBuf.toString();
112         }
113         else {
114             boundary = "--"+boundary;
115             length -= append;
116         }
117     }
118 */

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 JavaDoc( buf, 0, startIdx, length-startIdx ))
142             .indexOf( new String JavaDoc( 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     /**
161         liest den naechsten Parameter-Header aus dem Puffer
162     */

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             //bufferStr = new String( buffer, 0, 0, bufferEntries );
175
//ok = ( (endIdx = bufferStr.indexOf( END_OF_HEADER )) >= 0 )
176
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 JavaDoc( "Format-error in multipart-encoded data" );
188         
189         String JavaDoc bufferStr = new String JavaDoc( 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 JavaDoc nextBody()
208         throws IOException
209     {
210         String JavaDoc body = "";
211         int bodySize = 0;
212         while( (bodySize = nextBodyChunk()) != -1 ) {
213             body += new String JavaDoc( buffer, 0, 0, bodySize );
214         }
215         return body;
216     }
217     
218     public int nextBodyChunk()
219         throws IOException
220     {
221         if( boundaryStart != -1 ) {
222             // zuletzt ausgelesenen Puffer loeschen
223
if( boundaryStart >= 0 ) {
224                 // beim letzten Aufruf wurde das Ende des Bodies erreicht?
225
if( (buffer[boundaryStart+boundaryLength] == (byte) '-') &&
226                   (buffer[boundaryStart+boundaryLength+1] == (byte) '-') ) {
227                     // Ende-Markierung erreicht!
228
bufferEntries = 0;
229                     contentLength = 0;
230                     boundaryStart = -1;
231                     return -1;
232                 }
233                 // letzten body, boundary + CRLF rausnehmen
234
stripBuffer( boundaryStart + boundaryLength + 2 );
235                 boundaryStart = -1;
236                 return -1;
237             }
238             else {
239                 // aktueller Body passte nicht vollstaendig in Buffer
240
stripBuffer( bufferEntries - boundaryLength - 1 );
241             }
242         }
243         
244         // Puffer auffuellen
245
fillBuffer( maxBufferSize );
246         
247         // Boundary suchen
248
boundaryStart = arrayIndexOf( buffer, boundary );
249         
250         // Input komplett ausgelesen und keine Boundary gefunden?
251
if( (boundaryStart < 0) && (contentLength <= 0) ) {
252             throw new Error JavaDoc("malformed multipart POST");
253         }
254         
255         if( boundaryStart > 0 )
256             // alles bis zum CRLF vor Boundary auslesen lassen
257
return boundaryStart-2;
258         
259         // markieren, daš Body ueber mehrere Puffereintraege laueft
260
boundaryStart = -2;
261         
262         // darauf achten, dass eventuell nur das letzte
263
// Zeichen in der Boundary gefehlt hat, und deshalb
264
// muessen CRLF und Boundary-Length-1 Zeichen
265
// unausgelesen bleiben
266

267         return bufferEntries - boundaryLength - 1;
268     }
269     
270     /**
271         liest den naechsten Block aus dem Eingabestrom,
272         wobei gew‰hrleistet wird, dass die maximale
273         Puffer maxSize nicht ueberschritten wird.
274     */

275     
276     public void fillBuffer( int maxSize )
277         throws IOException
278     {
279         if( contentLength <= 0 ) return;
280         
281         int bytesToRead = maxSize - bufferEntries;// + boundaryLength + 2;
282

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 JavaDoc disposition = (String JavaDoc) header.get("content-disposition");
300             
301             int nameStart = disposition.indexOf(" name=\"")+7;
302             int nameEnd = disposition.indexOf('"',nameStart);
303             String JavaDoc name = disposition.substring( nameStart, nameEnd );
304             
305             String JavaDoc 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                 // normaler Parameter
313
params.extend( name, nextBody() );
314             }
315             else {
316                 // hochgeladenes File
317
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