天天看点

深入Jetty源码之HttpParser

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

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;

}

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)

在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()方法)。

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

深入Jetty源码之HttpParser

httpparser在解析http消息头时的状态迁移图

深入Jetty源码之HttpParser

httpparser在解析http消息体时的状态迁移图

httpparser在httpconnection中的handle方法被调用时用于解析客户端过来的http请求消息。

if (!_parser.iscomplete()) {

     int parsed=_parser.parseavailable();

     if (parsed>0)

         progress=true;

继续阅读