Class: HTTP2::Header::Compressor
- Inherits:
-
Object
- Object
- HTTP2::Header::Compressor
- Defined in:
- lib/http/2/compressor.rb
Overview
Responsible for encoding header key-value pairs using HPACK algorithm. Compressor must be initialized with appropriate starting context based on local role: client or server.
Instance Method Summary collapse
-
#encode(headers) ⇒ String
Encodes provided list of HTTP headers.
-
#header(h, buffer = "") ⇒ Object
Encodes header command with appropriate header representation.
-
#initialize(type) ⇒ Compressor
constructor
A new instance of Compressor.
-
#integer(i, n) ⇒ String
Encodes provided value via integer representation.
-
#string(str) ⇒ String
Encodes provided value via string literal representation.
Constructor Details
#initialize(type) ⇒ Compressor
Returns a new instance of Compressor.
291 292 293 |
# File 'lib/http/2/compressor.rb', line 291 def initialize(type) @cc = CompressionContext.new(type) end |
Instance Method Details
#encode(headers) ⇒ String
Encodes provided list of HTTP headers.
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# File 'lib/http/2/compressor.rb', line 387 def encode(headers) commands = [] @cc.update_sets # Remove missing headers from the working set @cc.workset.each do |idx, (wk,wv)| if headers.find {|(hk,hv)| hk == wk && hv == wv }.nil? commands.push @cc.removecmd idx end end # Add missing headers to the working set headers.each do |(hk,hv)| if @cc.workset.find {|i,(wk,wv)| hk == wk && hv == wv}.nil? commands.push @cc.addcmd [hk, hv] end end commands.map do |cmd| @cc.process cmd.dup header cmd end.join end |
#header(h, buffer = "") ⇒ Object
Encodes header command with appropriate header representation.
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/http/2/compressor.rb', line 351 def header(h, buffer = "") rep = HEADREP[h[:type]] if h[:type] == :indexed buffer << integer(h[:name], rep[:prefix]) else if h[:name].is_a? Integer buffer << integer(h[:name]+1, rep[:prefix]) else buffer << integer(0, rep[:prefix]) buffer << string(h[:name]) end if h[:type] == :substitution buffer << integer(h[:index], 0) end if h[:value].is_a? Integer buffer << integer(h[:value], 0) else buffer << string(h[:value]) end end # set header representation pattern on first byte fb = buffer[0].unpack("C").first | rep[:pattern] buffer.setbyte(0, fb) buffer end |
#integer(i, n) ⇒ String
Encodes provided value via integer representation.
-
tools.ietf.org/html/draft-ietf-httpbis-header-compression-01#section-4.2.1
If I < 2^N - 1, encode I on N bits Else, encode 2^N - 1 on N bits and do the following steps:
Set I to (I - (2^N - 1)) and Q to 1 While Q > 0 Compute Q and R, quotient and remainder of I divided by 2^7 If Q is strictly greater than 0, write one 1 bit; otherwise, write one 0 bit Encode R on the next 7 bits I = Q
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/http/2/compressor.rb', line 310 def integer(i, n) limit = 2**n - 1 return [i].pack('C') if (i < limit) bytes = [] bytes.push limit if !n.zero? i -= limit q = 1 while (q > 0) do q, r = i.divmod(128) r += 128 if (q > 0) i = q bytes.push(r) end bytes.pack('C*') end |
#string(str) ⇒ String
Encodes provided value via string literal representation.
-
tools.ietf.org/html/draft-ietf-httpbis-header-compression-01#section-4.2.2
-
The string length, defined as the number of bytes needed to store its UTF-8 representation, is represented as an integer with a zero bits prefix. If the string length is strictly less than 128, it is represented as one byte.
-
The string value represented as a list of UTF-8 character
342 343 344 |
# File 'lib/http/2/compressor.rb', line 342 def string(str) integer(str.bytesize, 0) + str.dup.force_encoding('binary') end |