当前位置: 首页 > news >正文

洛阳霞光网络建站公司如何制作一个简易网站

洛阳霞光网络建站公司,如何制作一个简易网站,漳州做网站的公司,做足球采集软件和预测软件的网站前言 HTTP2终于支持对头部进行压缩传输了,Netty很早就支持HTTP2了,看下Netty对HPACK的实现源码,可以对HPACK理解的更深一下。 HpackDecoder Netty内置的编解码器Http2FrameCodec专门用来对HTTP2的各种Frame进行编解码,其中就包…

前言

HTTP2终于支持对头部进行压缩传输了,Netty很早就支持HTTP2了,看下Netty对HPACK的实现源码,可以对HPACK理解的更深一下。

HpackDecoder

Netty内置的编解码器Http2FrameCodec专门用来对HTTP2的各种Frame进行编解码,其中就包含将ByteBuf解码为HeadersFrame,解码的工作最终交给了io.netty.handler.codec.http2.HpackDecoder

状态

HpackDecoder维护了一组状态常量,代表的是当前对Header的读取状态,不同的状态做的事情是不一样的,HpackDecoder通过一个While循环来读取Header,因为一个Frame里面包含若干个Header,根据读取到的数据判断,State会不断变化流转,理解了这些State,再看代码就简单的多了。

State说明
READ_HEADER_REPRESENTATION读取header的初试状态
READ_INDEXED_HEADER读取被索引的完整header,即name和value均被索引
READ_INDEXED_HEADER_NAME读取被索引的header name
READ_LITERAL_HEADER_NAME_LENGTH_PREFIXname未被索引,读取name长度前缀,判断是否使用哈夫曼编码
READ_LITERAL_HEADER_NAME_LENGTHname未被索引,读取name长度
READ_LITERAL_HEADER_NAMEname未被索引,读取header name
READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX读取value长度前缀,判断是否使用哈夫曼编码
READ_LITERAL_HEADER_VALUE_LENGTH读取value长度
READ_LITERAL_HEADER_VALUEvalue未被索引,读取value

decode()

解码的方法是io.netty.handler.codec.http2.HpackDecoder#decode(),这里直接贴出源码,核心代码已写注释:

private void decode(ByteBuf in, Http2HeadersSink sink) throws Http2Exception {int index = 0;int nameLength = 0;int valueLength = 0;byte state = READ_HEADER_REPRESENTATION;// 初始状态 准备读取Headerboolean huffmanEncoded = false;// 是否使用哈夫曼编码 长度的第1个Bit来标记AsciiString name = null;IndexType indexType = IndexType.NONE;// 索引类型while (in.isReadable()) {// 只要有数据,就循环读switch (state) {case READ_HEADER_REPRESENTATION:byte b = in.readByte();// 读取首字节if (maxDynamicTableSizeChangeRequired && (b & 0xE0) != 0x20) {// HpackEncoder MUST signal maximum dynamic table size changethrow MAX_DYNAMIC_TABLE_SIZE_CHANGE_REQUIRED;}if (b < 0) {// 小于0 即最高位是1,代表name和value均被索引// Indexed Header Fieldindex = b & 0x7F;switch (index) {case 0:throw DECODE_ILLEGAL_INDEX_VALUE;case 0x7F: // 索引号超过了1字节,需要继续读取 才能获取最终索引号state = READ_INDEXED_HEADER;break;default:// 索引号没超 直接从静态/动态表读取即可HpackHeaderField indexedHeader = getIndexedHeader(index);sink.appendToHeaderList((AsciiString) indexedHeader.name,(AsciiString) indexedHeader.value);}} else if ((b & 0x40) == 0x40) {// 01开头 header需要加入到动态表// Literal Header Field with Incremental IndexingindexType = IndexType.INCREMENTAL;index = b & 0x3F;switch (index) {case 0:// name未被索引,读取name长度 再读namestate = READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;break;case 0x3F:// name 索引号超了1字节 需要继续读state = READ_INDEXED_HEADER_NAME;break;default:// name被索引,继续读valuename = readName(index);nameLength = name.length();state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;}} else if ((b & 0x20) == 0x20) {// Dynamic Table Size Update// See https://www.rfc-editor.org/rfc/rfc7541.html#section-4.2throw connectionError(COMPRESSION_ERROR, "Dynamic table size update must happen " +"at the beginning of the header block");} else {// Literal Header Field without Indexing / never IndexedindexType = (b & 0x10) == 0x10 ? IndexType.NEVER : IndexType.NONE;index = b & 0x0F;switch (index) {case 0:state = READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;break;case 0x0F:state = READ_INDEXED_HEADER_NAME;break;default:// Index was stored as the prefixname = readName(index);nameLength = name.length();state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;}}break;case READ_INDEXED_HEADER:// 被索引的header,读取可变长度的索引号,从表中获取headerHpackHeaderField indexedHeader = getIndexedHeader(decodeULE128(in, index));sink.appendToHeaderList((AsciiString) indexedHeader.name,(AsciiString) indexedHeader.value);state = READ_HEADER_REPRESENTATION;break;case READ_INDEXED_HEADER_NAME:// Header Name matches an entry in the Header Tablename = readName(decodeULE128(in, index));nameLength = name.length();state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;break;case READ_LITERAL_HEADER_NAME_LENGTH_PREFIX:// 读取name前缀 判断是否使用哈夫曼编码b = in.readByte();huffmanEncoded = (b & 0x80) == 0x80;index = b & 0x7F;if (index == 0x7f) {state = READ_LITERAL_HEADER_NAME_LENGTH;} else {nameLength = index;state = READ_LITERAL_HEADER_NAME;}break;case READ_LITERAL_HEADER_NAME_LENGTH:// Header Name is a Literal StringnameLength = decodeULE128(in, index);state = READ_LITERAL_HEADER_NAME;break;case READ_LITERAL_HEADER_NAME:// Wait until entire name is readableif (in.readableBytes() < nameLength) {throw notEnoughDataException(in);}name = readStringLiteral(in, nameLength, huffmanEncoded);state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;break;case READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX:b = in.readByte();huffmanEncoded = (b & 0x80) == 0x80;index = b & 0x7F;switch (index) {case 0x7f:state = READ_LITERAL_HEADER_VALUE_LENGTH;break;case 0:insertHeader(sink, name, EMPTY_STRING, indexType);state = READ_HEADER_REPRESENTATION;break;default:valueLength = index;state = READ_LITERAL_HEADER_VALUE;}break;case READ_LITERAL_HEADER_VALUE_LENGTH:// Header Value is a Literal StringvalueLength = decodeULE128(in, index);state = READ_LITERAL_HEADER_VALUE;break;case READ_LITERAL_HEADER_VALUE:// Wait until entire value is readableif (in.readableBytes() < valueLength) {throw notEnoughDataException(in);}AsciiString value = readStringLiteral(in, valueLength, huffmanEncoded);insertHeader(sink, name, value, indexType);state = READ_HEADER_REPRESENTATION;break;default:throw new Error("should not reach here state: " + state);}}if (state != READ_HEADER_REPRESENTATION) {throw connectionError(COMPRESSION_ERROR, "Incomplete header block fragment.");}
}

该方法做的事情:

  1. 读取首字节,判断最高位是否是1开头。如果是代表name和value都是被索引的,继续读取索引号从静态/动态表获取header即可。
  2. 判断高位是否是01开头,是的话就需要把读取到的header添加到动态表中,进行维护。
  3. 如果name被索引,则读取索引号,从静态/动态表获取。如果没有被索引,则判断长度的第1Bit是否是1,如果是代表使用了哈夫曼编码,否则使用常规的ASCII字符编码。
  4. 读取value的规则类似,也是先判断是否使用哈夫曼编码,再按规则读取。

静态表

Netty通过io.netty.handler.codec.http2.HpackStaticTable类来维护静态表,硬编码写死的,不支持动态修改。

final class HpackStaticTable {static final int NOT_FOUND = -1;// Appendix A: Static Table// https://tools.ietf.org/html/rfc7541#appendix-Aprivate static final List<HpackHeaderField> STATIC_TABLE = Arrays.asList(/*  1 */ newEmptyHeaderField(":authority"),/*  2 */ newHeaderField(":method", "GET"),/*  3 */ newHeaderField(":method", "POST"),/*  4 */ newHeaderField(":path", "/"),/*  5 */ newHeaderField(":path", "/index.html"),/*  6 */ newHeaderField(":scheme", "http"),/*  7 */ newHeaderField(":scheme", "https"),/* 61 */ newEmptyHeaderField("www-authenticate")。。。。。。);
}

动态表

Netty通过io.netty.handler.codec.http2.HpackDynamicTable类来维护动态表,动态表初始是空的,只有读到01开头的Header才会加入到动态表中维护。

final class HpackDynamicTable {// a circular queue of header fieldsHpackHeaderField[] hpackHeaderFields;int head;int tail;private long size;private long capacity = -1;public void add(HpackHeaderField header) {int headerSize = header.size();if (headerSize > capacity) {clear();return;}while (capacity - size < headerSize) {remove();}hpackHeaderFields[head++] = header;size += headerSize;if (head == hpackHeaderFields.length) {head = 0;}}。。。。。。
}
http://www.yidumall.com/news/63127.html

相关文章:

  • 网站主页作品欣赏seo优化排名
  • 东莞网站开发报价品牌企业seo咨询
  • 重庆城乡建设局网站农产品品牌推广方案
  • 电子政务门户网站建设方案做一个企业网站需要多少钱
  • 沧州网站建设价格新东方教育培训机构
  • 做企业网站服务商淄博seo网站推广
  • 哈 做网站seo+网站排名
  • 网站运营者网址平台推广员是做什么的
  • 网站制作与网站建设公司域名注册步骤
  • 南阳响应式网站制作今日头条热搜榜
  • 北京网站建设找降龙广州网站优化服务
  • 网站加入搜索引擎怎么做网络营销策划需要包括哪些内容
  • 辽阳seoseo研究所
  • 做网站前景天猫店铺申请条件及费用
  • 地方房地产网站seo实战案例分享上海优化seo排名
  • 带论坛的网站模板下载地址百度开户推广多少钱
  • 建设工程有限公司是做什么的seo优化有百度系和什么
  • 谷歌网站提交网站宣传费用
  • 小榄网站建设推广网站seo推广方案
  • 网站关键词百度自然排名优化怎么知道自己的域名
  • 企业网站规范免费推广网站2023
  • 网站开发有哪些职位域名注册商有哪些
  • 委托网站建设合同推广赚钱一个50元
  • 连云港做网站制作推广文案
  • 滨海住房和城乡建设局网站上海网络推广软件
  • 做头像的网站自己的名字原画培训班一般学费多少
  • 没有网站怎么做百度优化服务营销包括哪些内容
  • wordpress国外主题下载地址电脑优化设置
  • 做网站的主要内容免费推广公司的网站
  • wordpress docker安装seo基础