KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > web > connector > grizzly > algorithms > ContentLengthAlgorithm


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Copyright 1999-2004 The Apache Software Foundation
26  *
27  * Licensed under the Apache License, Version 2.0 (the "License");
28  * you may not use this file except in compliance with the License.
29  * You may obtain a copy of the License at
30  *
31  * http://www.apache.org/licenses/LICENSE-2.0
32  *
33  * Unless required by applicable law or agreed to in writing, software
34  * distributed under the License is distributed on an "AS IS" BASIS,
35  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36  * See the License for the specific language governing permissions and
37  * limitations under the License.
38  */

39 package com.sun.enterprise.web.connector.grizzly.algorithms;
40
41 import com.sun.enterprise.web.connector.grizzly.Constants;
42 import com.sun.enterprise.web.connector.grizzly.Handler;
43 import com.sun.enterprise.web.connector.grizzly.SelectorThread;
44 import com.sun.enterprise.web.connector.grizzly.handlers.ContentLengthHandler;
45
46 import java.nio.ByteBuffer JavaDoc;
47 import java.nio.BufferUnderflowException JavaDoc;
48 import java.util.logging.Level JavaDoc;
49
50 import org.apache.tomcat.util.buf.Ascii;
51
52 /**
53  * Predict if the NIO channel has been fully read or not. This lagorithm will
54  * first search for the content-length header, and use that value to determine if
55  * the bytes has been fully read or not. If the content-length isn't included,
56  * it will search for the end of the HTTP stream, which is a '\r\n'
57  *
58  * Note: the parsing algorithm is an adaptation of:
59  * org.apache.coyote.http11.InternalInputBuffer
60  * written by Remy Maucherat
61  *
62  * @author Jean-Francois Arcand
63  */

64 public final class ContentLengthAlgorithm extends StreamAlgorithmBase{
65          
66     private final static byte[] POST_METHOD = "post".getBytes();
67     private final static byte[] PUT_METHOD = "put".getBytes();
68     
69     private final static byte[] CL_HEADER = "content-length".getBytes();
70     
71     
72     /**
73      * Pointer to the US-ASCII header buffer.
74      */

75     public byte[] ascbuf = new byte[Constants.CHANNEL_BYTE_SIZE];
76
77     
78     /**
79      * Last valid byte.
80      */

81     protected int lastValid;
82
83
84     /**
85      * Position in the buffer.
86      */

87     protected int pos;
88
89     
90     /**
91      * Is the content-length fully read.
92      */

93     private boolean isFound = false;
94     
95     
96     /**
97      * Is the request line parsed?
98      */

99     private boolean requestLineParsed = false;
100     
101     
102     /**
103      * The request bytes position.
104      */

105     public int startReq = -1;
106           
107     
108     /**
109      * The request bytes length
110      */

111     public int lengthReq = -1;
112
113     
114     // ---------------------------------------------- Constructor ----------/
115

116     
117     public ContentLengthAlgorithm() {
118         handler = new ContentLengthHandler(this);
119     }
120     
121  
122     /**
123      * Parse the <code>ByteBuffer</code> and try to determine if the bytes
124      * stream has been fully read from the <code>SocketChannel</code>.
125      *
126      * Drain the <code>SocketChannel</code> and determine if the request bytes
127      * has been fully read. For POST method, parse the bytes and seek for the
128      * content-type header to determine the length of the request bytes.
129      * @return true if we need to call back the <code>SelectorThread</code>
130      * This occurs when the stream doesn't contains all the
131      * request bytes.
132      * false if the stream contains all request bytes.
133      *
134      * @paran byteBuffer the bytes read.
135      * @return true if the algorithm determines the end of the stream.
136      */

137     public boolean parse(ByteBuffer JavaDoc byteBuffer){
138         isFound = false;
139
140         curLimit = byteBuffer.limit();
141         curPosition = byteBuffer.position();
142
143         // Rule a - if we know the content length, verify all bytes are read
144
// Return true only if all bytes has been read.
145
if ( contentLength != -1 ){
146             isFound =
147                  ((contentLength + headerLength) <= byteBuffer.position());
148
149             if (isFound)
150                byteBuffer.flip();
151
152             return isFound;
153         }
154        
155         try{
156             // Rule b - If nothing, return to the Selector.
157
if (byteBuffer.position() == 0)
158                 return false;
159                     
160             byteBuffer.flip();
161             lastValid = byteBuffer.limit();
162
163             // Rule c - Parse the request line
164
if ( !requestLineParsed ) {
165                 requestLineParsed = parseRequestLine(byteBuffer);
166                 if ( !requestLineParsed ) {
167                     return false;
168                 }
169             }
170
171             // Rule d -- Parse the headers, looking for content-length
172
while (parseHeader(byteBuffer));
173             
174             // Rule e - for POST/PUT, make sure all the body is loaded from
175
// the socket channel.
176
if ( headerLength != -1 && isFound ){
177                 isFound = ((contentLength + headerLength)
178                                 <= byteBuffer.limit());
179             } else {
180                 // The content-length was found, but the headers
181
// aren't yet bufferred entirely.
182
isFound = false;
183             }
184            
185             return isFound;
186         } catch (BufferUnderflowException JavaDoc bue) {
187             SelectorThread.logger().log(Level.SEVERE,
188                     "readTask.bufferunderflow", bue);
189             return false;
190         } finally {
191             byteBuffer.limit(curLimit);
192             byteBuffer.position(curPosition);
193             
194             if (isFound){
195                 byteBuffer.flip();
196             }
197         }
198     }
199     
200     
201     /**
202      * Parse the request line, looking for a POST method.
203      */

204     private boolean parseRequestLine(ByteBuffer JavaDoc byteBuffer){
205         int start = 0;
206         byte chr = 0;
207         
208         if ( state == 0 ){
209             do {
210                 if (pos >= lastValid)
211                     return false;
212
213                 chr = byteBuffer.get(pos++);
214
215             } while ((chr == Constants.CR) || (chr == Constants.LF));
216             
217             state = 1;
218
219             pos--;
220             byteBuffer.position(pos);
221         }
222             
223         // Mark the current buffer position
224
start = pos;
225         boolean space = false;
226         if ( state == 1 ) {
227             while (!space) {
228                 if (pos >= lastValid)
229                     return false;
230
231                 byte c = byteBuffer.get(pos);
232                 ascbuf[pos] = c;
233
234                 if (c == Constants.SP) {
235                     space = true;
236                     if ( !isFound &&
237                             (findBytes(ascbuf,start, pos, POST_METHOD) == -1
238                              || findBytes(ascbuf,start, pos, PUT_METHOD) == -1)){
239                         isFound = true;
240                     }
241                 }
242
243                 pos++;
244             }
245             state = 2;
246         }
247
248         // Mark the current buffer position
249
start = pos;
250         int end = 0;
251         space = false;
252         boolean eol = false;
253         int questionPos = -1;
254         if ( state == 2 ){
255             while (!space) {
256                 // Read new bytes if needed
257
if (pos >= lastValid)
258                     return false;
259
260                 byte b = byteBuffer.get(pos);
261                 ascbuf[pos] = b;
262                 if ( b == Constants.SP) {
263                     space = true;
264                     end = pos;
265                 } else if ((b == Constants.CR)
266                            || (b == Constants.LF)) {
267                     // HTTP/0.9 style request
268
eol = true;
269                     space = true;
270                     end = pos;
271                 } else if ((b == Constants.QUESTION) && (questionPos == -1)){
272                     questionPos = pos;
273                 }
274                 pos++;
275
276             }
277             state = 3;
278             
279             startReq = start;
280             if (questionPos >= 0) {
281                 lengthReq = questionPos - start;
282             } else {
283                 lengthReq = end - start;
284             }
285         }
286
287         if ( state == 3 ) {
288             // Mark the current buffer position
289
start = pos;
290             end = 0;
291             while (!eol) {
292                 // Read new bytes if needed
293
if (pos >= lastValid)
294                     return false;
295
296                 byte b = byteBuffer.get(pos);
297
298                 if (b == Constants.CR) {
299                     end = pos;
300                 } else if (b == Constants.LF) {
301                     if (end == 0)
302                         end = pos;
303                     eol = true;
304                 }
305                 pos++;
306             }
307             state = 4;
308         }
309         return eol;
310     }
311     
312     
313    /**
314      * Parse the headers, looking for content-length header and value.
315      */

316     public boolean parseHeader(ByteBuffer JavaDoc byteBuffer){
317
318         boolean headerFound = false;
319         byte chr = 0;
320         
321         if ( state == 4 ){
322             while (true) {
323                 // Read new bytes if needed
324
if (pos >= lastValid)
325                     return false;
326
327                 chr = byteBuffer.get(pos);
328
329                 if ((chr == Constants.CR) || (chr == Constants.LF)) {
330                     if (chr == Constants.LF) {
331                         pos++;
332                         headerLength = pos;
333                         isFound = true;
334                         state = 4;
335                         return false;
336                     }
337                 } else {
338                     break;
339                 }
340
341                 pos++;
342             }
343             state = 5;
344         }
345         
346         // Mark the current buffer position
347
int start = pos;
348
349         if ( state == 5 ){
350             boolean colon = false;
351             while (!colon) {
352                 // Read new bytes if needed
353
if (pos >= lastValid)
354                     return false;
355
356                 chr = byteBuffer.get(pos);
357                 if (chr == Constants.COLON) {
358                     colon = true;
359
360                     if ( contentLength == -1
361                          && findBytes(ascbuf, start, start + (pos - start),
362                             CL_HEADER ) != -1){
363                         headerFound = true;
364                     }
365                 }
366
367                 if ((chr >= Constants.A) && (chr <= Constants.Z)) {
368                     chr = (byte) (chr - Constants.LC_OFFSET);
369                 }
370
371                 ascbuf[pos] = chr;
372
373                 pos++;
374             }
375             state = 6;
376         }
377         
378         // Mark the current buffer position
379
start = pos;
380         int realPos = pos;
381
382         boolean eol = false;
383         boolean validLine = true;
384
385         while (validLine) {
386
387             boolean space = true;
388
389             if ( state == 6 ){
390                 // Skipping spaces
391
while (space) {
392                     // Read new bytes if needed
393
if (pos >= lastValid)
394                         return false;
395
396                     chr = byteBuffer.get(pos);
397                     if (( chr == Constants.SP) || (chr == Constants.HT)) {
398                         pos++;
399                     } else {
400                         space = false;
401                     }
402                 }
403                 state = 7;
404             }
405             
406             int lastSignificantChar = realPos;
407             // Reading bytes until the end of the line
408
if ( state == 7){
409                 while (!eol) {
410                     // Read new bytes if needed
411
if (pos >= lastValid)
412                         return false;
413
414                     chr = byteBuffer.get(pos);
415                     if (chr == Constants.CR) {
416                     } else if (chr == Constants.LF) {
417                         eol = true;
418                     } else if (chr == Constants.SP) {
419                         realPos++;
420                     } else {
421                         realPos++;
422                         lastSignificantChar = realPos;
423                     }
424                     pos++;
425                 }
426                 state = 8;
427                 realPos = lastSignificantChar;
428             }
429
430             if ( state == 8){
431                 // Read new bytes if needed
432
if (pos >= lastValid)
433                     return false;
434
435                 chr = byteBuffer.get(pos);
436                 if ((chr != Constants.SP) && (chr != Constants.HT)) {
437                     validLine = false;
438                 } else {
439                     eol = false;
440                     realPos++;
441                 }
442                  state = 4;
443             }
444         }
445  
446         if ( headerFound ){
447             byteBuffer.position(start+1);
448             StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
449             for(int i=0; i < realPos - start; i++) {
450                 sb.append((char) byteBuffer.get());
451             }
452             contentLength = Integer.parseInt(sb.toString());
453         }
454
455         return true;
456
457     }
458  
459     
460     /**
461      * Compare two bytes array and return > 0 if true.
462      */

463     private int findBytes(byte[] buff, int start, int end, byte[] b) {
464
465         byte first = b[0];
466
467         // Look for first char
468
int srcEnd = b.length;
469
470         for (int i = start; i <= (end - srcEnd); i++) {
471             if (Ascii.toLower(buff[i]) != first) continue;
472             
473             // found first char, now look for a match
474
int myPos = i+1;
475             for (int srcPos = 1; srcPos < srcEnd; ) {
476                 if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
477                     break;
478                 if (srcPos == srcEnd) return i - start; // found it
479
}
480         }
481         return -1;
482
483     }
484       
485     
486     /***
487      * Recylce this object.
488      */

489     public void recycle(){
490         contentLength = -1;
491         headerLength = -1;
492         curLimit = -1;
493         curPosition = -1;
494         pos = 0;
495         lastValid = 0;
496         requestLineParsed = false;
497         isFound = false;
498         state = 0;
499         lengthReq = -1;
500         startReq = -1;
501         
502         socketChannel = null;
503         if ( handler != null){
504             ((ContentLengthHandler)handler).attachChannel(null);
505         }
506     }
507
508     
509     /**
510      * Return the <code>Handler</code> used by this algorithm.
511      */

512     public Handler getHandler(){
513        ((ContentLengthHandler)handler).attachChannel(socketChannel);
514        return handler;
515     }
516 }
517
Popular Tags