gregbeech/xenon

View on GitHub
xenon-http/lib/xenon/headers/accept_encoding.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'xenon/headers'
require 'xenon/parsers/header_rules'

module Xenon
  class ContentCodingRange
    attr_reader :coding, :q

    DEFAULT_Q = 1.0

    def initialize(coding, q = DEFAULT_Q)
      @coding = coding
      @q = Float(q) || DEFAULT_Q
    end

    def <=>(other)
      @q <=> other.q
    end

    def to_s
      s = @coding.dup
      s << "; q=#{@q}" if @q != DEFAULT_Q
      s
    end
  end

  class Headers
    # http://tools.ietf.org/html/rfc7231#section-5.3.4
    class AcceptEncoding < ListHeader 'Accept-Encoding'
      def initialize(*coding_ranges)
        super(coding_ranges.sort_by.with_index { |mr, i| [mr, -i] }.reverse)
      end

      alias_method :coding_ranges, :values

      def self.parse(s)
        tree = Parsers::AcceptEncodingHeader.new.parse(s)
        Parsers::AcceptEncodingHeaderTransform.new.apply(tree)
      end
    end
  end

  module Parsers
    class AcceptEncodingHeader < Parslet::Parser
      include HeaderRules
      %w(identity compress x-compress deflate gzip x-gzip).each do |c|
        rule(c.tr('-', '_').to_sym) { str(c).as(:coding) >> sp? }
      end
      rule(:coding) { compress | x_compress | deflate | gzip | x_gzip }
      rule(:wildcard) { str('*').as(:coding) >> sp? }
      rule(:coding_range) { (coding | identity | wildcard) >> weight.maybe }
      rule(:accept_encoding) { (coding_range >> (list_sep >> coding_range).repeat).maybe.as(:accept_encoding) }
      root(:accept_encoding)
    end

    class AcceptEncodingHeaderTransform < HeaderTransform
      rule(coding: simple(:c), q: simple(:q)) { ContentCodingRange.new(c, q) }
      rule(coding: simple(:c)) { ContentCodingRange.new(c) }
      rule(accept_encoding: sequence(:er)) { Headers::AcceptEncoding.new(*er) }
      rule(accept_encoding: simple(:cc)) { Headers::AcceptEncoding.new(cc) }
      rule(accept_encoding: nil) { Headers::AcceptEncoding.new }
    end
  end
end