博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入Jetty源码之HttpGenerator
阅读量:6955 次
发布时间:2019-06-27

本文共 3578 字,大约阅读时间需要 11 分钟。

基于抽象和聚合原则,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中。

转载地址:http://zfnil.baihongyu.com/

你可能感兴趣的文章
Windows Phone(三)WP7版 " 记账本" 开发(使用SQLite数据库)
查看>>
CSS 几款比较常用的翻转特效(转载)
查看>>
html5 拖拽事件
查看>>
Spring创建对象的三种方式以及创建时间
查看>>
IO多路复用, 基于IO多路复用+socket实现并发请求(一个线程100个请求), 协程
查看>>
大白话Vue源码系列(03):生成AST
查看>>
vi / vim 删除以及其它命令
查看>>
Codeforces Round #564 (Div. 2) B. Nauuo and Chess
查看>>
Android 微信第三方登录
查看>>
Jsoup后台解析html、jsp网页
查看>>
JsonModel 的使用
查看>>
病毒分裂 NOIP模拟 矩阵快速幂 分治数列求和
查看>>
[WorldFinal 2012E]Infiltration(dfs+图论)
查看>>
【BZOJ】1443: [JSOI2009]游戏Game
查看>>
获取控制器 nextResponder的简单应用
查看>>
2014.5.17—所谓生活,就是让自己变得更好
查看>>
TensorFlow官方文档学习02-MNIST初级课程
查看>>
OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现
查看>>
Predicate和Consumer应用
查看>>
分金币 Uva 11300
查看>>