上善若水
In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
posts - 146,comments - 147,trackbacks - 0

概述

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;
}
posted on 2014-04-19 18:31 DLevin 阅读(2477) 评论(3)  编辑  收藏 所属分类: Jetty

FeedBack:
# re: 深入Jetty源码之HttpParser
2014-04-21 10:53 | 无添加
想问下TF-IDF算法实现的具体事例有吗?  回复  更多评论
  
# re: 深入Jetty源码之HttpParser
2014-05-15 05:00 | jptan
请问博主是如何把uml图做出来的呢?  回复  更多评论
  
# re: 深入Jetty源码之HttpParser
2014-05-15 13:54 | DLevin
用StarUML@jptan
  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: