View Javadoc

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