深入Jetty源码之HttpGenerator

基于抽象和聚合原则,Jetty中需要一个单独的类来专门处理HTTP响应消息和请求消息的生成和发送,Jetty的作者将该抽象(接口)命名为Generator,它有两个实现类:HttpGenerator和NestedGenerator。其类图如下:

Generator接口

HTTP请求消息分为请求行、消息报头、请求正文三部分,HTTP响应消息分为状态行、消息报头、消息正文。在HTTP请求消息和响应消息格式的唯一区别是请求行和状态行,因而只需要将这一行的内容区分开来,其他的可以共享逻辑。

请求行和响应行设置
请求行包括请求方法、URI、HTTP协议版本,响应行包括HTTP协议版本、状态码、状态短语,因而在Generator接口中定义了各自的设置方法:

    // 设置_method、_uri字段,如果当前_version是HTTP/0.9,则_noContent置为true
    void setRequest(String method, String uri);
    // 设置_status、_reason字段,对_reason字段,将所有'\r', '\n'替换成空格(' ')。清除_method字段。如果Generator已经开始生成效应消息,则不可再调用该方法。
    void setResponse(int status, String reason);
    // 设置HTTP协议版本,这里的值9表示HTTP/0.9, 10表示HTTP/1.0,11表示HTTP/1.1。对HTTP/0.9的请求消息,不能包含请求内容。如果Generator已经开始生成效应消息,则不可再调用该方法。
    void setVersion(int version);

HTTP消息报头设置
在Generator中,通过completeHeader中的HttpFields参数传入HTTP消息报头,而其中的allContentAdded参数用于检查并设置_last字段状态。

//通过传入的HttpFields参数设置HTTP消息报头,allContentAdded参数用于检查并设置_last字段状态。
public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
void setDate(Buffer timeStampBuffer);
void setSendServerVersion(boolean sendServerVersion);
void setContentLength(long length);
void setPersistent(boolean persistent);
在该方法的实现中:
1. 向_header缓存中写入请求行或响应行(对HTTP/0.9的特殊处理不详述)。对HTTP响应消息,如果状态码是[100-200)、204、304,这些响应消息不能有响应消息体。对状态码是100的响应消息还不能有其他消息头。
2. 如果设置了_date值(状态码在200及以上,这里貌似木有考虑请求消息),在消息头中包含"Date"消息头。
3. 对fields参数中的所有消息头,依次写入到_header缓存中(消息头名移除'\r', '\n', ':'字符,消息头值移除'\r', '\n'字符)。对"Content-Length"头,记录_contentLength字段;对"Content-Type"为"multipart/byteranges"头,设置_contentLength为SLEF_DEFINING_CONTENT;对"Transfer-Encoding"头,并且_contentLength的值为CHUNKED_CONTENT,则添加"Transfer-Encoding: chunked\r\n"头(或用户自定义的以"chunked"开头的值);对"Server"头,且设置了"sendServerVersion"字段,则添加"Server"头;对"Connection"头,在请求消息中直接设置该头,同时更新"keep_alive"的值("close"->keep_alive=false, "keep-alive"->keep_alive=true),在响应消息中,更新"keep_alive"和"_persistent"的值,对"upgrade"值,直接添加,而对其他值,根据"keep_alive"和"_persistent"的值以及HTTP版本号添加"close"或"keep-alive"的值,以及用户自定义的值;根据当前_contentLength值设置"Content-Length"头;最后添加"\r\n"到_header缓存表示消息头结束。
4. 将_state状态从STATE_HEADER更新到STATE_CONTENT。

HTTP消息体设置
Generator中有两个方法用于向其添加HTTP消息体:

void addContent(Buffer content, boolean last) throws IOException;
boolean addContent(byte b) throws IOException;
这两个方法的实现:
1. 如果当前已存在未刷新的_content内容或者_contentLength为CHUNKED_CONTENT,则先刷新缓存。
2. 更新_content字段和_contentWritten字段。
3. 将_content的值写入_buffer字段中。
在刷新缓存时:
1. 准备Buffer:将_content值写入_buffer中,并清除_content引用;如果_contentLength为CHUNKED_CONTENT,设置_bufferChunk为true,并且对chunked内容,先写入16进制的size,紧跟"\r\n",然后是正真的内容;对最后一个chunk,添加"\r\n\r\n"。
2. 然后根据_header, _buffer, _content状态,将它们中的内容写入到Endpoint中。
3. 如果当前状态是STATE_FLUSHING,则将_state状态置为STATE_END。

HTTP消息完成生成
Generator调用complete方法表示生成已经完成:

public void complete() throws IOException
在该方法中,它将_state状态设置为STATE_FLUSHING,并刷新缓存。

Generator中的其他方法
在Generator/HttpGenerator中还有一些发送响应消息的方法:

void sendError(int code, String reason, String content, boolean close) throws IOException;
public void send1xx(int code) throws IOException
public void sendResponse(Buffer response) throws IOException
其中sendError是Generator接口中的方法,它是一个工具方法用于一次将一个HTTP响应消息写入到Endpoint中:

    public void sendError(int code, String reason, String content, boolean close) throws IOException {
        if (close)
            _persistent=false;
        if (!isCommitted()) {
            setResponse(code, reason);
            if (content != null)  {
                completeHeader(null, false);
                addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
            } else {
                completeHeader(null, true);
            }
            complete();
        }
    }
sendResponse方法是HttpGenerator中的方法,它将response参数直接作为响应消息体,并设置_state为STATE_FLUSHING,是一个工具方法。
send1xx方法是HttpGenerator中的方法,它将1xx的响应消息直接写入到Endpoint中。

时间: 2024-11-08 19:07:42

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

深入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源码之HttpParser

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

深入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交互

深入Jetty源码之Servlet框架及实现(Servlet、Filter、Registration)

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