View Javadoc

1   // ========================================================================
2   // Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.ajp;
15  
16  import java.io.IOException;
17  import java.io.InterruptedIOException;
18  
19  import javax.servlet.ServletInputStream;
20  
21  import org.eclipse.jetty.http.HttpTokens;
22  import org.eclipse.jetty.http.Parser;
23  import org.eclipse.jetty.io.Buffer;
24  import org.eclipse.jetty.io.BufferUtil;
25  import org.eclipse.jetty.io.Buffers;
26  import org.eclipse.jetty.io.EndPoint;
27  import org.eclipse.jetty.io.EofException;
28  import org.eclipse.jetty.io.View;
29  import org.eclipse.jetty.util.log.Log;
30  
31  /**
32   * 
33   */
34  public class Ajp13Parser implements Parser
35  {
36      private final static int STATE_START = -1;
37      private final static int STATE_END = 0;
38      private final static int STATE_AJP13CHUNK_START = 1;
39      private final static int STATE_AJP13CHUNK = 2;
40  
41      private int _state = STATE_START;
42      private long _contentLength;
43      private long _contentPosition;
44      private int _chunkLength;
45      private int _chunkPosition;
46      private int _headers;
47      private Buffers _buffers;
48      private EndPoint _endp;
49      private Buffer _buffer;
50      private Buffer _header; // Buffer for header data (and small _content)
51      private Buffer _body; // Buffer for large content
52      private View _contentView = new View();
53      private EventHandler _handler;
54      private Ajp13Generator _generator;
55      private View _tok0; // Saved token: header name, request method or response version
56      private View _tok1; // Saved token: header value, request URI orresponse code
57      protected int _length;
58      protected int _packetLength;
59      
60  
61      /* ------------------------------------------------------------------------------- */
62      public Ajp13Parser(Buffers buffers, EndPoint endPoint)
63      {
64          _buffers = buffers;
65          _endp = endPoint;
66      }
67      
68      /* ------------------------------------------------------------------------------- */
69      public void setEventHandler(EventHandler handler)
70      {
71          _handler=handler;
72      }
73      
74      /* ------------------------------------------------------------------------------- */
75      public void setGenerator(Ajp13Generator generator)
76      {
77          _generator=generator;
78      }
79  
80      /* ------------------------------------------------------------------------------- */
81      public long getContentLength()
82      {
83          return _contentLength;
84      }
85  
86      /* ------------------------------------------------------------------------------- */
87      public int getState()
88      {
89          return _state;
90      }
91  
92      /* ------------------------------------------------------------------------------- */
93      public boolean inContentState()
94      {
95          return _state > 0;
96      }
97  
98      /* ------------------------------------------------------------------------------- */
99      public boolean inHeaderState()
100     {
101         return _state < 0;
102     }
103 
104     /* ------------------------------------------------------------------------------- */
105     public boolean isIdle()
106     {
107         return _state == STATE_START;
108     }
109 
110     /* ------------------------------------------------------------------------------- */
111     public boolean isComplete()
112     {
113         return _state == STATE_END;
114     }
115 
116     /* ------------------------------------------------------------------------------- */
117     public boolean isMoreInBuffer()
118     {
119 
120         if (_header != null && _header.hasContent() || _body != null && _body.hasContent())
121             return true;
122 
123         return false;
124     }
125 
126     /* ------------------------------------------------------------------------------- */
127     public boolean isState(int state)
128     {
129         return _state == state;
130     }
131 
132     /* ------------------------------------------------------------------------------- */
133     public void parse() throws IOException
134     {
135         if (_state == STATE_END)
136             reset();
137         if (_state != STATE_START)
138             throw new IllegalStateException("!START");
139 
140         // continue parsing
141         while (!isComplete())
142         {
143             parseNext();
144         }
145     }
146 
147     /* ------------------------------------------------------------------------------- */
148     public int parseAvailable() throws IOException
149     {
150         int len = parseNext();
151         int total = len > 0 ? len : 0;
152 
153         // continue parsing
154         while (!isComplete() && _buffer != null && _buffer.length() > 0)
155         {
156             len = parseNext();
157             if (len > 0)
158                 total += len;
159             else
160                 break;
161         }
162         return total;
163     }
164 
165     /* ------------------------------------------------------------------------------- */
166     private int fill() throws IOException
167     {
168         int filled = -1;
169         if (_body != null && _buffer != _body)
170         {
171             // mod_jk implementations may have some partial data from header
172             // check if there are partial contents in the header
173             // copy it to the body if there are any
174             if(_header.length() > 0)
175             {
176                 // copy the patial data from the header to the body
177                 _body.put(_header);
178             }
179 
180             _buffer = _body;
181             
182             if (_buffer.length()>0)
183             {            
184                 filled = _buffer.length();
185                 return filled;
186             }
187         }
188 
189         if (_buffer.markIndex() == 0 && _buffer.putIndex() == _buffer.capacity())
190             throw new IOException("FULL");
191         if (_endp != null && filled <= 0)
192         {
193             // Compress buffer if handling _content buffer
194             // TODO check this is not moving data too much
195             if (_buffer == _body)
196                 _buffer.compact();
197 
198             if (_buffer.space() == 0)
199                 throw new IOException("FULL");
200 
201             try
202             {
203                 filled = _endp.fill(_buffer);
204             }
205             catch (IOException e)
206             {
207                 // This is normal in AJP since the socket closes on timeout only
208                 Log.debug(e);
209                 reset();
210                 throw (e instanceof EofException) ? e : new EofException(e);
211             }
212         }
213         
214         if (filled < 0)
215         {
216             if (_state > STATE_END)
217             {
218                 _state = STATE_END;
219                 _handler.messageComplete(_contentPosition);
220                 return filled;
221             }
222             reset();
223             throw new EofException();
224         }
225     
226         return filled;
227     }
228     
229     volatile int _seq=0;
230     /* ------------------------------------------------------------------------------- */
231     public int parseNext() throws IOException
232     {
233         int total_filled = 0;
234 
235         if (_buffer == null)
236         {
237             if (_header == null)
238                 _header = _buffers.getHeader();
239            
240             _buffer = _header;
241             _tok0 = new View(_header);
242             _tok1 = new View(_header);
243             _tok0.setPutIndex(_tok0.getIndex());
244             _tok1.setPutIndex(_tok1.getIndex());
245         }
246 
247         if (_state == STATE_END)
248             throw new IllegalStateException("STATE_END");
249         if (_state > STATE_END && _contentPosition == _contentLength)
250         {
251             _state = STATE_END;
252             _handler.messageComplete(_contentPosition);
253             return 1;
254         }
255         
256         if (_state < 0)
257         {
258             // have we seen a packet?
259             if (_packetLength<=0)
260             {
261                 if (_buffer.length()<4)
262                 {
263                     if (total_filled<0) 
264                         total_filled=0;
265                     total_filled+=fill();
266                     if (_buffer.length()<4)
267                         return total_filled;
268                 }
269                 
270                 _contentLength = HttpTokens.UNKNOWN_CONTENT;
271                 int _magic = Ajp13RequestPacket.getInt(_buffer);
272                 if (_magic != Ajp13RequestHeaders.MAGIC)
273                     throw new IOException("Bad AJP13 rcv packet: " + "0x" + Integer.toHexString(_magic) + " expected " + "0x" + Integer.toHexString(Ajp13RequestHeaders.MAGIC) + " " + this);
274 
275 
276                 _packetLength = Ajp13RequestPacket.getInt(_buffer);
277                 if (_packetLength > Ajp13Packet.MAX_PACKET_SIZE)
278                     throw new IOException("AJP13 packet (" + _packetLength + "bytes) too large for buffer");
279                 
280             }
281             
282             if (_buffer.length() < _packetLength)
283             {
284                 if (total_filled<0) 
285                     total_filled=0;
286                 total_filled+=fill();
287                 if (_buffer.length() < _packetLength)
288                     return total_filled;
289             }
290 
291             // Parse Header
292             Buffer bufHeaderName = null;
293             Buffer bufHeaderValue = null;
294             int attr_type = 0;
295 
296             byte packetType = Ajp13RequestPacket.getByte(_buffer);
297             
298             switch (packetType)
299             {
300                 case Ajp13Packet.FORWARD_REQUEST_ORDINAL:
301                     _handler.startForwardRequest();
302                     break;
303                 case Ajp13Packet.CPING_REQUEST_ORDINAL:
304                     (_generator).sendCPong();
305                     
306                     if(_header != null)
307                     {
308                         _buffers.returnBuffer(_header);
309                         _header = null;
310                     }
311 
312                     if(_body != null)
313                     {
314                         _buffers.returnBuffer(_body);
315                         _body = null;
316                     }
317 
318                     _buffer= null;
319 
320                     reset();
321 
322                     return -1;
323                 case Ajp13Packet.SHUTDOWN_ORDINAL:
324                     shutdownRequest();
325 
326                     return -1;
327 
328                 default:
329                     // XXX Throw an Exception here?? Close
330                     // connection!
331                     Log.warn("AJP13 message type ({PING}: "+packetType+" ) not supported/recognized as an AJP request");
332                 throw new IllegalStateException("PING is not implemented");
333             }
334 
335 
336             _handler.parsedMethod(Ajp13RequestPacket.getMethod(_buffer));
337             _handler.parsedProtocol(Ajp13RequestPacket.getString(_buffer, _tok0));
338             _handler.parsedUri(Ajp13RequestPacket.getString(_buffer, _tok1));
339             _handler.parsedRemoteAddr(Ajp13RequestPacket.getString(_buffer, _tok1));
340             _handler.parsedRemoteHost(Ajp13RequestPacket.getString(_buffer, _tok1));
341             _handler.parsedServerName(Ajp13RequestPacket.getString(_buffer, _tok1));
342             _handler.parsedServerPort(Ajp13RequestPacket.getInt(_buffer));
343             _handler.parsedSslSecure(Ajp13RequestPacket.getBool(_buffer));
344 
345 
346             _headers = Ajp13RequestPacket.getInt(_buffer);
347 
348             for (int h=0;h<_headers;h++)
349             {
350                 bufHeaderName = Ajp13RequestPacket.getHeaderName(_buffer, _tok0);
351                 bufHeaderValue = Ajp13RequestPacket.getString(_buffer, _tok1);
352 
353                 if (bufHeaderName != null && bufHeaderName.toString().equals(Ajp13RequestHeaders.CONTENT_LENGTH))
354                 {
355                     _contentLength = BufferUtil.toLong(bufHeaderValue);
356                     if (_contentLength == 0)
357                         _contentLength = HttpTokens.NO_CONTENT;
358                 }
359 
360                 _handler.parsedHeader(bufHeaderName, bufHeaderValue);
361             }
362 
363 
364 
365             attr_type = Ajp13RequestPacket.getByte(_buffer) & 0xff;
366             while (attr_type != 0xFF)
367             {
368                 switch (attr_type)
369                 {
370                     // XXX How does this plug into the web
371                     // containers
372                     // authentication?
373 
374                     case Ajp13RequestHeaders.REMOTE_USER_ATTR:
375                         _handler.parsedRemoteUser(Ajp13RequestPacket.getString(_buffer, _tok1));
376                         break;
377                     case Ajp13RequestHeaders.AUTH_TYPE_ATTR:
378                         //XXX JASPI how does this make sense?
379                         _handler.parsedAuthorizationType(Ajp13RequestPacket.getString(_buffer, _tok1));
380                         break;
381 
382                     case Ajp13RequestHeaders.QUERY_STRING_ATTR:
383                         _handler.parsedQueryString(Ajp13RequestPacket.getString(_buffer, _tok1));
384                         break;
385 
386                     case Ajp13RequestHeaders.JVM_ROUTE_ATTR:
387                         // moved to Eclipse naming usage
388                         // used in org.eclipse.jetty.servlet.HashSessionIdManager
389                         _handler.parsedRequestAttribute("org.eclipse.jetty.ajp.JVMRoute", Ajp13RequestPacket.getString(_buffer, _tok1));
390                         break;
391 
392                     case Ajp13RequestHeaders.SSL_CERT_ATTR:
393                         _handler.parsedSslCert(Ajp13RequestPacket.getString(_buffer, _tok1));
394                         break;
395 
396                     case Ajp13RequestHeaders.SSL_CIPHER_ATTR:
397                         _handler.parsedSslCipher(Ajp13RequestPacket.getString(_buffer, _tok1));
398                         // SslSocketConnector.customize()
399                         break;
400 
401                     case Ajp13RequestHeaders.SSL_SESSION_ATTR:
402                         _handler.parsedSslSession(Ajp13RequestPacket.getString(_buffer, _tok1));
403                         break;
404 
405                     case Ajp13RequestHeaders.REQUEST_ATTR:
406                         _handler.parsedRequestAttribute(Ajp13RequestPacket.getString(_buffer, _tok0).toString(), Ajp13RequestPacket.getString(_buffer, _tok1));
407                         break;
408 
409                         // New Jk API?
410                         // Check if experimental or can they
411                         // assumed to be
412                         // supported
413                         
414                     case Ajp13RequestHeaders.SSL_KEYSIZE_ATTR:
415                         
416                         // This has been implemented in AJP13 as either a string or a integer.
417                         // Servlet specs say javax.servlet.request.key_size must be an Integer
418                         
419                         // Does it look like a string containing digits?
420                         int length = Ajp13RequestPacket.getInt(_buffer);
421                         
422                         if (length>0 && length<16)
423                         {
424                             // this must be a string length rather than a key length
425                             _buffer.skip(-2);
426                             _handler.parsedSslKeySize(Integer.parseInt(Ajp13RequestPacket.getString(_buffer, _tok1).toString()));
427                         }
428                         else
429                             _handler.parsedSslKeySize(length);
430                         
431                         break;
432 
433                         
434                         // Used to lock down jk requests with a
435                         // secreate
436                         // key.
437                         
438                     case Ajp13RequestHeaders.SECRET_ATTR:
439                         // XXX Investigate safest way to
440                         // deal with
441                         // this...
442                         // should this tie into shutdown
443                         // packet?
444                         break;
445 
446                     case Ajp13RequestHeaders.STORED_METHOD_ATTR:
447                         // XXX Confirm this should
448                         // really overide
449                         // previously parsed method?
450                         // _handler.parsedMethod(Ajp13PacketMethods.CACHE.get(Ajp13RequestPacket.getString()));
451                         break;
452 
453 
454                     case Ajp13RequestHeaders.CONTEXT_ATTR:
455                         _handler.parsedContextPath(Ajp13RequestPacket.getString(_buffer, _tok1));
456                         break;
457                     case Ajp13RequestHeaders.SERVLET_PATH_ATTR:
458                         _handler.parsedServletPath(Ajp13RequestPacket.getString(_buffer, _tok1));
459 
460                         break;
461                     default:
462                         Log.warn("Unsupported Ajp13 Request Attribute {}", new Integer(attr_type));
463                     break;
464                 }
465 
466                 attr_type = Ajp13RequestPacket.getByte(_buffer) & 0xff;
467             }
468 
469             _contentPosition = 0;
470             switch ((int) _contentLength)
471             {
472 
473                 case HttpTokens.NO_CONTENT:
474                     _state = STATE_END;
475                     _handler.headerComplete();
476                     _handler.messageComplete(_contentPosition);
477 
478                     break;
479 
480                 case HttpTokens.UNKNOWN_CONTENT:
481 
482                     _generator.getBodyChunk();
483                     if (_buffers != null && _body == null && _buffer == _header && _header.length() <= 0)
484                     {
485                         _body = _buffers.getBuffer();
486                         _body.clear();
487                     }
488                     _state = STATE_AJP13CHUNK_START;
489                     _handler.headerComplete(); // May recurse here!
490 
491                     return total_filled;
492 
493                 default:
494 
495                     if (_buffers != null && _body == null && _buffer == _header && _contentLength > (_header.capacity() - _header.getIndex()))
496                     {
497                         _body = _buffers.getBuffer();
498                         _body.clear();
499 
500                     }
501                 _state = STATE_AJP13CHUNK_START;
502                 _handler.headerComplete(); // May recurse here!
503                 return total_filled;
504             }
505         }
506 
507         Buffer chunk;
508 
509         while (_state>STATE_END)
510         {
511             switch (_state)
512             {
513                 case STATE_AJP13CHUNK_START:
514                     if (_buffer.length()<6)
515                     {
516                         if (total_filled<0) 
517                             total_filled=0;
518                         total_filled+=fill();
519                         if (_buffer.length()<6)
520                             return total_filled;
521                     }
522                     int _magic=Ajp13RequestPacket.getInt(_buffer);
523                     if (_magic!=Ajp13RequestHeaders.MAGIC)
524                     {
525                         throw new IOException("Bad AJP13 rcv packet: "+"0x"+Integer.toHexString(_magic)+" expected "+"0x"
526                                 +Integer.toHexString(Ajp13RequestHeaders.MAGIC)+" "+this);
527                     }
528                     _chunkPosition=0;
529                     _chunkLength=Ajp13RequestPacket.getInt(_buffer)-2;
530                     Ajp13RequestPacket.getInt(_buffer);
531                     if (_chunkLength==0)
532                     {
533                         _state=STATE_END;
534                          _generator.gotBody();
535                         _handler.messageComplete(_contentPosition);
536                         return total_filled;
537                     }
538                     _state=STATE_AJP13CHUNK;
539                     break;
540 
541                 case STATE_AJP13CHUNK:
542                     if (_buffer.length()<_chunkLength)
543                     {
544                         if (total_filled<0) 
545                             total_filled=0;
546                         total_filled+=fill();
547                         if (_buffer.length()<_chunkLength)
548                             return total_filled;
549                     }
550 
551                     int remaining=_chunkLength-_chunkPosition;
552                     
553                     if (remaining==0)
554                     {
555                         _state=STATE_AJP13CHUNK_START;
556                         if (_contentPosition<_contentLength)
557                         {
558                             _generator.getBodyChunk();
559                         }
560                         else
561                         {
562                             _generator.gotBody();
563                         }
564 
565                         return total_filled;
566                     }
567 
568                     if (_buffer.length()<remaining)
569                     {
570                         remaining=_buffer.length();
571                     }
572 
573                     chunk=Ajp13RequestPacket.get(_buffer,remaining);
574                     
575                     _contentPosition+=chunk.length();
576                     _chunkPosition+=chunk.length();
577                     _contentView.update(chunk);
578 
579                     remaining=_chunkLength-_chunkPosition;
580 
581                     if (remaining==0)
582                     {
583                         _state=STATE_AJP13CHUNK_START;
584                         if (_contentPosition<_contentLength || _contentLength == HttpTokens.UNKNOWN_CONTENT)
585                         {
586                             _generator.getBodyChunk();
587                         }
588                         else
589                         {
590                             _generator.gotBody();
591                         }
592                     }
593 
594                     _handler.content(chunk);
595 
596                 return total_filled;
597 
598             default:
599                 throw new IllegalStateException("Invalid Content State");
600 
601             }
602 
603         }
604         
605         return total_filled;
606     }
607 
608     /* ------------------------------------------------------------------------------- */
609     public void reset()
610     {
611         _state = STATE_START;
612         _contentLength = HttpTokens.UNKNOWN_CONTENT;
613         _contentPosition = 0;
614         _length = 0;
615         _packetLength = 0;
616 
617         if (_body!=null && _body.hasContent())
618         {
619             // There is content in the body after the end of the request.
620             // This is probably a pipelined header of the next request, so we need to
621             // copy it to the header buffer.
622             if (_header==null)
623             {
624                 _header=_buffers.getHeader();
625                 _tok0.update(_header);
626                 _tok0.update(0,0);
627                 _tok1.update(_header);
628                 _tok1.update(0,0);
629             }
630             else
631             {
632                 _header.setMarkIndex(-1);
633                 _header.compact();
634             }
635             int take=_header.space();
636             if (take>_body.length())
637                 take=_body.length();
638             _body.peek(_body.getIndex(),take);
639             _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
640         }
641 
642         if (_header!=null)
643             _header.setMarkIndex(-1);
644         if (_body!=null)
645             _body.setMarkIndex(-1);
646 
647         _buffer=_header;
648     }
649 
650 
651     /* ------------------------------------------------------------------------------- */
652     public void returnBuffers()
653     {
654         if (_body!=null && !_body.hasContent() && _body.markIndex()==-1)
655         {   
656             if (_buffer==_body)
657                 _buffer=_header;
658             if (_buffers!=null)
659                 _buffers.returnBuffer(_body);
660             _body=null; 
661         }
662 
663         if (_header!=null && !_header.hasContent() && _header.markIndex()==-1)
664         {
665             if (_buffer==_header)
666                 _buffer=null;
667             _buffers.returnBuffer(_header);
668             _header=null;
669         }
670     }
671 
672     /* ------------------------------------------------------------------------------- */
673     Buffer getHeaderBuffer()
674     {
675         return _buffer;
676     }
677 
678     private void shutdownRequest()
679     {
680         _state = STATE_END;
681 
682         if(!Ajp13SocketConnector.__allowShutdown)
683         {
684             Log.warn("AJP13: Shutdown Request is Denied, allowShutdown is set to false!!!");
685             return;
686         }
687 
688         if(Ajp13SocketConnector.__secretWord != null)
689         {
690             Log.warn("AJP13: Validating Secret Word");
691             try
692             {
693                 String secretWord = Ajp13RequestPacket.getString(_buffer, _tok1).toString();
694 
695                 if(!Ajp13SocketConnector.__secretWord.equals(secretWord))
696                 {
697                     Log.warn("AJP13: Shutdown Request Denied, Invalid Sercret word!!!");
698                     throw new IllegalStateException("AJP13: Secret Word is Invalid: Peer has requested shutdown but, Secret Word did not match");
699                 }
700             }
701             catch (Exception e)
702             {
703                 Log.warn("AJP13: Secret Word is Required!!!");
704                 Log.debug(e);
705                 throw new IllegalStateException("AJP13: Secret Word is Required: Peer has requested shutdown but, has not provided a Secret Word");
706             }
707 
708 
709             Log.warn("AJP13: Shutdown Request is Denied, allowShutdown is set to false!!!");
710             return;
711         }
712 
713         Log.warn("AJP13: Peer Has Requested for Shutdown!!!");
714         Log.warn("AJP13: Jetty 6 is shutting down !!!");
715         System.exit(0);
716     }
717 
718     /* ------------------------------------------------------------------------------- */
719     public interface EventHandler
720     {
721 
722         // public void shutdownRequest() throws IOException;
723         // public void cpingRequest() throws IOException;
724 
725         public void content(Buffer ref) throws IOException;
726 
727         public void headerComplete() throws IOException;
728 
729         public void messageComplete(long contextLength) throws IOException;
730 
731         public void parsedHeader(Buffer name, Buffer value) throws IOException;
732 
733         public void parsedMethod(Buffer method) throws IOException;
734 
735         public void parsedProtocol(Buffer protocol) throws IOException;
736 
737         public void parsedQueryString(Buffer value) throws IOException;
738 
739         public void parsedRemoteAddr(Buffer addr) throws IOException;
740 
741         public void parsedRemoteHost(Buffer host) throws IOException;
742 
743         public void parsedRequestAttribute(String key, Buffer value) throws IOException;
744         
745         public void parsedRequestAttribute(String key, int value) throws IOException;
746 
747         public void parsedServerName(Buffer name) throws IOException;
748 
749         public void parsedServerPort(int port) throws IOException;
750 
751         public void parsedSslSecure(boolean secure) throws IOException;
752 
753         public void parsedUri(Buffer uri) throws IOException;
754 
755         public void startForwardRequest() throws IOException;
756 
757         public void parsedAuthorizationType(Buffer authType) throws IOException;
758         
759         public void parsedRemoteUser(Buffer remoteUser) throws IOException;
760 
761         public void parsedServletPath(Buffer servletPath) throws IOException;
762         
763         public void parsedContextPath(Buffer context) throws IOException;
764 
765         public void parsedSslCert(Buffer sslCert) throws IOException;
766 
767         public void parsedSslCipher(Buffer sslCipher) throws IOException;
768 
769         public void parsedSslSession(Buffer sslSession) throws IOException;
770 
771         public void parsedSslKeySize(int keySize) throws IOException;
772 
773 
774 
775 
776 
777     }
778 
779     /* ------------------------------------------------------------ */
780     /**
781      * TODO Make this common with HttpParser
782      * 
783      */
784     public static class Input extends ServletInputStream
785     {
786         private Ajp13Parser _parser;
787         private EndPoint _endp;
788         private long _maxIdleTime;
789         private View _content;
790 
791         /* ------------------------------------------------------------ */
792         public Input(Ajp13Parser parser, long maxIdleTime)
793         {
794             _parser = parser;
795             _endp = parser._endp;
796             _maxIdleTime = maxIdleTime;
797             _content = _parser._contentView;
798         }
799 
800         /* ------------------------------------------------------------ */
801         @Override
802         public int read() throws IOException
803         {
804             int c = -1;
805             if (blockForContent())
806                 c = 0xff & _content.get();
807             return c;
808         }
809 
810         /* ------------------------------------------------------------ */
811         /*
812          * @see java.io.InputStream#read(byte[], int, int)
813          */
814         @Override
815         public int read(byte[] b, int off, int len) throws IOException
816         {
817             int l = -1;
818             if (blockForContent())
819                 l = _content.get(b, off, len);
820             return l;
821         }
822 
823         /* ------------------------------------------------------------ */
824         private boolean blockForContent() throws IOException
825         {
826             if (_content.length() > 0)
827                 return true;
828             if (_parser.isState(Ajp13Parser.STATE_END) || _parser.isState(Ajp13Parser.STATE_START))
829                 return false;
830 
831             // Handle simple end points.
832             if (_endp == null)
833                 _parser.parseNext();
834 
835             // Handle blocking end points
836             else if (_endp.isBlocking())
837             {
838                 _parser.parseNext();
839                 
840                 // parse until some progress is made (or IOException thrown for timeout)
841                 while (_content.length() == 0 && !_parser.isState(Ajp13Parser.STATE_END))
842                 {
843                     // Try to get more _parser._content
844                     _parser.parseNext();
845                 }
846             }
847             else // Handle non-blocking end point
848             {
849                 long filled = _parser.parseNext();
850                 boolean blocked = false;
851 
852                 // parse until some progress is made (or
853                 // IOException thrown for timeout)
854                 while (_content.length() == 0 && !_parser.isState(Ajp13Parser.STATE_END))
855                 {
856                     // if fill called, but no bytes read,
857                     // then block
858                     if (filled > 0)
859                         blocked = false;
860                     else if (filled == 0)
861                     {
862                         if (blocked)
863                             throw new InterruptedIOException("timeout");
864 
865                         blocked = true;
866                         _endp.blockReadable(_maxIdleTime);
867                     }
868 
869                     // Try to get more _parser._content
870                     filled = _parser.parseNext();
871                 }
872             }
873 
874             return _content.length() > 0;
875         }
876 
877     }
878 }