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