📄 ajp13parser.java
字号:
//========================================================================//Copyright 2006 Mort Bay Consulting Pty. Ltd.//------------------------------------------------------------------------//Licensed under the Apache License, Version 2.0 (the "License");//you may not use this file except in compliance with the License.//You may obtain a copy of the License at//http://www.apache.org/licenses/LICENSE-2.0//Unless required by applicable law or agreed to in writing, software//distributed under the License is distributed on an "AS IS" BASIS,//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.//See the License for the specific language governing permissions and//limitations under the License.//========================================================================package org.mortbay.jetty.ajp;import java.io.IOException;import java.io.InterruptedIOException;import javax.servlet.ServletInputStream;import org.mortbay.io.Buffer;import org.mortbay.io.BufferUtil;import org.mortbay.io.Buffers;import org.mortbay.io.EndPoint;import org.mortbay.io.View;import org.mortbay.jetty.EofException;import org.mortbay.jetty.HttpTokens;import org.mortbay.jetty.Parser;import org.mortbay.log.Log;/** * @author Markus Kobler */public class Ajp13Parser implements Parser{ private final static int STATE_START = -1; private final static int STATE_END = 0; private final static int STATE_AJP13CHUNK_START = 1; private final static int STATE_AJP13CHUNK = 2; private int _state = STATE_START; private long _contentLength; private long _contentPosition; private int _chunkLength; private int _chunkPosition; private int _headers; private Buffers _buffers; private EndPoint _endp; private Buffer _buffer; private Buffer _header; // Buffer for header data (and small _content) private Buffer _body; // Buffer for large content private View _contentView = new View(); private EventHandler _handler; private Ajp13Generator _generator; private View _tok0; // Saved token: header name, request method or response version private View _tok1; // Saved token: header value, request URI orresponse code protected int _length; protected int _packetLength; /* ------------------------------------------------------------------------------- */ public Ajp13Parser(Buffers buffers, EndPoint endPoint) { _buffers = buffers; _endp = endPoint; } /* ------------------------------------------------------------------------------- */ public void setEventHandler(EventHandler handler) { _handler=handler; } /* ------------------------------------------------------------------------------- */ public void setGenerator(Ajp13Generator generator) { _generator=generator; } /* ------------------------------------------------------------------------------- */ public long getContentLength() { return _contentLength; } /* ------------------------------------------------------------------------------- */ public int getState() { return _state; } /* ------------------------------------------------------------------------------- */ public boolean inContentState() { return _state > 0; } /* ------------------------------------------------------------------------------- */ public boolean inHeaderState() { return _state < 0; } /* ------------------------------------------------------------------------------- */ public boolean isIdle() { return _state == STATE_START; } /* ------------------------------------------------------------------------------- */ public boolean isComplete() { return _state == STATE_END; } /* ------------------------------------------------------------------------------- */ public boolean isMoreInBuffer() { if (_header != null && _header.hasContent() || _body != null && _body.hasContent()) return true; return false; } /* ------------------------------------------------------------------------------- */ public boolean isState(int state) { return _state == state; } /* ------------------------------------------------------------------------------- */ public void parse() throws IOException { if (_state == STATE_END) reset(false); if (_state != STATE_START) throw new IllegalStateException("!START"); // continue parsing while (!isComplete()) { parseNext(); } } /* ------------------------------------------------------------------------------- */ public long parseAvailable() throws IOException { long len = parseNext(); long total = len > 0 ? len : 0; // continue parsing while (!isComplete() && _buffer != null && _buffer.length() > 0) { len = parseNext(); if (len > 0) total += len; else break; } return total; } /* ------------------------------------------------------------------------------- */ private int fill() throws IOException { int filled = -1; if (_body != null && _buffer != _body) { // mod_jk implementations may have some partial data from header // check if there are partial contents in the header // copy it to the body if there are any if(_header.length() > 0) { // copy the patial data from the header to the body _body.put(_header); } _buffer = _body; if (_buffer.length()>0) { filled = _buffer.length(); return filled; } } if (_buffer.markIndex() == 0 && _buffer.putIndex() == _buffer.capacity()) throw new IOException("FULL"); if (_endp != null && filled <= 0) { // Compress buffer if handling _content buffer // TODO check this is not moving data too much if (_buffer == _body) _buffer.compact(); if (_buffer.space() == 0) throw new IOException("FULL"); try { filled = _endp.fill(_buffer); } catch (IOException e) { // This is normal in AJP since the socket closes on timeout only Log.debug(e); reset(true); throw (e instanceof EofException) ? e : new EofException(e); } } if (filled < 0) { if (_state > STATE_END) { _state = STATE_END; _handler.messageComplete(_contentPosition); return filled; } reset(true); throw new EofException(); } return filled; } /* ------------------------------------------------------------------------------- */ public long parseNext() throws IOException { long total_filled = -1; if (_buffer == null) { if (_header == null) { _header = _buffers.getBuffer(Ajp13Packet.MAX_PACKET_SIZE); _header.clear(); } _buffer = _header; _tok0 = new View(_header); _tok1 = new View(_header); _tok0.setPutIndex(_tok0.getIndex()); _tok1.setPutIndex(_tok1.getIndex()); } if (_state == STATE_END) throw new IllegalStateException("STATE_END"); if (_state > STATE_END && _contentPosition == _contentLength) { _state = STATE_END; _handler.messageComplete(_contentPosition); return total_filled; } if (_state < 0) { // have we seen a packet? if (_packetLength<=0) { if (_buffer.length()<4) { if (total_filled<0) total_filled=0; total_filled+=fill(); if (_buffer.length()<4) return total_filled; } _contentLength = HttpTokens.UNKNOWN_CONTENT; int _magic = Ajp13RequestPacket.getInt(_buffer); if (_magic != Ajp13RequestHeaders.MAGIC) throw new IOException("Bad AJP13 rcv packet: " + "0x" + Integer.toHexString(_magic) + " expected " + "0x" + Integer.toHexString(Ajp13RequestHeaders.MAGIC) + " " + this); _packetLength = Ajp13RequestPacket.getInt(_buffer); if (_packetLength > Ajp13Packet.MAX_PACKET_SIZE) throw new IOException("AJP13 packet (" + _packetLength + "bytes) too large for buffer"); } if (_buffer.length() < _packetLength) { if (total_filled<0) total_filled=0; total_filled+=fill(); if (_buffer.length() < _packetLength) return total_filled; } // Parse Header Buffer bufHeaderName = null; Buffer bufHeaderValue = null; int attr_type = 0; byte packetType = Ajp13RequestPacket.getByte(_buffer); switch (packetType) { case Ajp13Packet.FORWARD_REQUEST_ORDINAL: _handler.startForwardRequest(); break; case Ajp13Packet.CPING_REQUEST_ORDINAL: ((Ajp13Generator) _generator).sendCPong(); if(_header != null) { _buffers.returnBuffer(_header); _header = null; } if(_body != null) { _buffers.returnBuffer(_body); _body = null; } _buffer= null; reset(true); return -1; case Ajp13Packet.SHUTDOWN_ORDINAL: shutdownRequest(); return -1; default: // XXX Throw an Exception here?? Close // connection! Log.warn("AJP13 message type ({PING}: "+packetType+" ) not supported/recognized as an AJP request"); throw new IllegalStateException("PING is not implemented"); } _handler.parsedMethod(Ajp13RequestPacket.getMethod(_buffer)); _handler.parsedProtocol(Ajp13RequestPacket.getString(_buffer, _tok0)); _handler.parsedUri(Ajp13RequestPacket.getString(_buffer, _tok1)); _handler.parsedRemoteAddr(Ajp13RequestPacket.getString(_buffer, _tok1)); _handler.parsedRemoteHost(Ajp13RequestPacket.getString(_buffer, _tok1)); _handler.parsedServerName(Ajp13RequestPacket.getString(_buffer, _tok1)); _handler.parsedServerPort(Ajp13RequestPacket.getInt(_buffer)); _handler.parsedSslSecure(Ajp13RequestPacket.getBool(_buffer)); _headers = Ajp13RequestPacket.getInt(_buffer); for (int h=0;h<_headers;h++) { bufHeaderName = Ajp13RequestPacket.getHeaderName(_buffer, _tok0); bufHeaderValue = Ajp13RequestPacket.getString(_buffer, _tok1); if (bufHeaderName != null && bufHeaderName.toString().equals(Ajp13RequestHeaders.CONTENT_LENGTH)) { _contentLength = BufferUtil.toLong(bufHeaderValue); if (_contentLength == 0) _contentLength = HttpTokens.NO_CONTENT; } _handler.parsedHeader(bufHeaderName, bufHeaderValue); } attr_type = Ajp13RequestPacket.getByte(_buffer) & 0xff; while (attr_type != 0xFF) { switch (attr_type) { // XXX How does this plug into the web // containers // authentication? case Ajp13RequestHeaders.REMOTE_USER_ATTR: _handler.parsedRemoteUser(Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.AUTH_TYPE_ATTR: _handler.parsedAuthorizationType(Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.QUERY_STRING_ATTR: _handler.parsedQueryString(Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.JVM_ROUTE_ATTR: // XXX Using old Jetty 5 key, // should change! // Note used in // org.mortbay.jetty.servlet.HashSessionIdManager _handler.parsedRequestAttribute("org.mortbay.http.ajp.JVMRoute", Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.SSL_CERT_ATTR: _handler.parsedSslCert(Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.SSL_CIPHER_ATTR: _handler.parsedSslCipher(Ajp13RequestPacket.getString(_buffer, _tok1)); // SslSocketConnector.customize() break; case Ajp13RequestHeaders.SSL_SESSION_ATTR: _handler.parsedSslSession(Ajp13RequestPacket.getString(_buffer, _tok1)); break; case Ajp13RequestHeaders.REQUEST_ATTR: _handler.parsedRequestAttribute(Ajp13RequestPacket.getString(_buffer, _tok0).toString(), Ajp13RequestPacket.getString(_buffer, _tok1)); break; // New Jk API? // Check if experimental or can they // assumed to be // supported case Ajp13RequestHeaders.SSL_KEYSIZE_ATTR: // This has been implemented in AJP13 as either a string or a integer. // Servlet specs say javax.servlet.request.key_size must be an Integer // Does it look like a string containing digits? int length = Ajp13RequestPacket.getInt(_buffer); if (length>0 && length<16) { // this must be a string length rather than a key length _buffer.skip(-2); _handler.parsedSslKeySize(Integer.parseInt(Ajp13RequestPacket.getString(_buffer, _tok1).toString())); } else _handler.parsedSslKeySize(length); break; // Used to lock down jk requests with a // secreate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -