深入Jetty源码之HttpParser

概述

Jetty作为HTTP服务器,服务器和客户端以HTTP协议格式通信,Jetty使用Parser(HttpParser)来抽象HTTP请求消息和响应消息的解析类引擎。在HttpParser实现中,它采用有限状态机算法:定义了21中状态,每解析一个字符,就根据当前的状态做相应的处理,并决定是否要迁移到下一个状态,直到HTTP请求消息或响应消息解析完成。HttpParser采用事件驱动机制,它定义了EventHandler类,用户可以通过注册的EventHandler实例获取相应的消息:请求行解析完成(startRequest)、响应行解析完成(startResponse)、每个消息头解析完成(parsedHeader)、所有消息头解析完成(headerComplete)、消息内容解析完成(content)、整个消息(请求消息或响应消息)解析完成(messageComplete)。

Parser接口定义

public interface Parser {
    // 重置Parser的内部状态,以重用Parser实例,如果returnBuffers为true,则将内部Buffer回收。
    void reset(boolean returnBuffers);
    // 当前Parser是否已经解析完成。
    boolean isComplete();
    // 当前Parser是否处于Idle状态,它还处于初始状态,解析还没有开始。
    boolean isIdle();
    // 内部Buffer是否还有内容没有解析。
    boolean isMoreInBuffer() throws IOException;
    // 开始解析已接收到的消息,返回-1表示解析到流的末位,0表示没有该次调用没有解析任何消息,>0表示这次调用总共解析过的字节数。
    int parseAvailable() throws IOException;
}

EventHandler定义

public static abstract class EventHandler {
    // 消息内容解析完成
    public abstract void content(Buffer ref) throws IOException;

    // 所有消息头解析完成
    public void headerComplete() throws IOException {
    }

    // 整个消息(请求消息或响应消息)解析完成
    public void messageComplete(long contentLength) throws IOException {
    }

    // 每个消息头解析完成
    public void parsedHeader(Buffer name, Buffer value) throws IOException {
    }

    // 请求行解析完成
    public abstract void startRequest(Buffer method, Buffer url, Buffer version)
            throws IOException;

    // 响应行解析完成
    public abstract void startResponse(Buffer version, int status, Buffer reason)
            throws IOException;
}

EventHandler的实现类

在HttpConnection的内部类RequestHandler类实现了HttpParser.EventHandler类,以作为HttpParser使用时的回调。
startRequest:重置当前HttpConnection状态,HttpRequest的时间戳,设置新解析出来的RequestMethod、URI、version信息。
parsedHeader:将每个HTTP头(name, value)对添加到_requestFields字段中,并检查某些头的存在性以及其值的合法性。
1. 如果“host”头存在,则设置_host为true。
2. 对“Expect”头,如果其值是“100-continue”,设置_expect100Continue为true,若值是“102-processing”,设置_expect102Processing值为true,当信息不足时,设置_expect为true。
3. 对“Accept-Encoding”和“User-Agent”头,只能是预定义的值。
4. 对“Content-Type”头只能是预定义的值,并且根据该值设置_charset字段。
5. 对“Connectin”头,如果是“close”值,则设置HttpGenerator的persistent属性为false,并且设置_responseFields的“Connection”值为“close”,否则为“keep-alive”。
headerComplete:在HTTP消息头解析结束后,对AsyncEndpoint,调用其scheduleIdle()方法,设置HttpGenerator中的HTTP version字段,以及当前请求是否为HEAD请求,如果当前Server配置了sendDateHeader,则设置HttpGenerator的Date字段为HttpRequest的时间戳(在startRequest方法调用是设置)。对HTTP/1.1,如果没有设置Host头,直接返回400响应(调用_generator的completeHeader和complete方法);如果expect为true,表示Expect头设置有问题,直接返回417响应(调用_generator的completeHeader和complete方法)。设置_charset字段,对CHUNK请求立即开始处理请求(handleRequest),否则延迟到消息读取完成。
content:对AsyncEndPoint,调用其scheduleIdle()方法,如果请求还未开始处理,则立即开始处理请求。
messageComplete:如果请求还未开始处理,则立即开始处理请求。

注:这里并没有在content方法中保存消息体的内容,在Jetty中使用HttpInput类从HttpParser中直接读取消息体的内容(通过HttpInput的read方法调用HttpParser.blockForContent()方法)。

HttpPaser有限状态机实现

在HttpParser中定义了21中状态,其中STATE_END以前的状态用于解析HTTP头消息,而STATE_END以后的状态用于解析HTTP消息体。它们各自的状态迁移图如下。

HttpParser在解析HTTP消息头时的状态迁移图

HttpParser在解析HTTP消息体时的状态迁移图

HttpParser在HttpConnection类中的使用

HttpParser在HttpConnection中的handle方法被调用时用于解析客户端过来的HTTP请求消息。

if (!_parser.isComplete()) {
     int parsed=_parser.parseAvailable();
     if (parsed>0)
         progress=true;
}

时间: 2024-11-02 08:35:17

深入Jetty源码之HttpParser的相关文章

深入Jetty源码之Handler总述

Handler概述 Handler是Jetty中的核心接口,它用于处理所有连接以外的逻辑,比如对Servlet框架的实现,以及用户自定义的Handler等,它继承自LifeCycle和Destroyable接口,只有一个主要方法:handle,包含Request和Response实例.在深入Jetty源码之Connection中有写道在HttpConnection的handleRequest()方法中会最终调用Server的handle()或handleAsync()方法,并且传入HttpCon

深入Jetty源码之ContextHandler

概述 ContextHandler继承自ScopedHandler,它是Jetty中实现对一个Web Application的各种资源进行管理,并串联实现整个Servlet框架的类,比如它部分实现了ServletContext接口,并且在其doScope方法中为当前Request的执行提供了相应的环境,如设置servletPath.pathInfo.设置ServletContext到ThreadLocal中.在Jetty中,Servlet的执行流程和框架由ServletHandler实现,Sec

深入Jetty源码之Connector

Connector概述 Connector是Jetty中可以直接接受客户端连接的抽象,一个Connector监听Jetty服务器的一个端口,所有客户端的连接请求首先通过该端口,而后由操作系统分配一个新的端口(Socket)与客户端进行数据通信(先握手,然后建立连接,但是使用不同的端口).不同的Connector实现可以使用不同的底层结构,如Socket Connector.NIO Connector等,也可以使用不同的协议,如Ssl Connector.AJP Connector,从而在不同的C

深入Jetty源码之Servlet框架及实现(ServletRequest、ServletResponse)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性).在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互的

深入Jetty源码之Connection

概述 当Jetty中的Connector收到一个客户端的连接时(ServerSocket或ServerSocketChannel的accept()方法返回),Connector会首先创建一个ConnectedEndPoint用于和连接的底层(Socket.Channel)打交道(读写数据),在创建的ConnectedEndPoint时会同时使用该EndPoint创建相应类型的Connection,然后会创建一个Task仍给线程池,最终线程池会启动一个线程启动这个Task,而在这个Task中调用C

深入Jetty源码之HttpGenerator

基于抽象和聚合原则,Jetty中需要一个单独的类来专门处理HTTP响应消息和请求消息的生成和发送,Jetty的作者将该抽象(接口)命名为Generator,它有两个实现类:HttpGenerator和NestedGenerator.其类图如下: Generator接口 HTTP请求消息分为请求行.消息报头.请求正文三部分,HTTP响应消息分为状态行.消息报头.消息正文.在HTTP请求消息和响应消息格式的唯一区别是请求行和状态行,因而只需要将这一行的内容区分开来,其他的可以共享逻辑. 请求行和响应

深入Jetty源码之EndPoint

概述 在Jetty中,使用Connector来抽象Jetty服务器对某个端口的监听.在Connector启动时,它会启动acceptors个Acceptor线程用于监听在Connector中配置的端口.对于客户端的每次连接,Connector都会创建相应的EndPoint来表示该连接,一般在创建EndPoint的同时会同时创建Connection,这里EndPoint用于和Socket打交道,而Connection用于在从Socket中读取到数据后的处理逻辑以及生成响应数据的处理逻辑. 不同的C

深入Jetty源码之Servlet框架及实现(AsyncContext、RequestDispatcher、HttpSession)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性).在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互的

深入Jetty源码之Servlet框架及实现(ServletContext)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性). 在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互