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