View Javadoc

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