def generate(frame)
      bytes  = Buffer.new
      length = 0

      frame[:flags] ||= []
      frame[:stream] ||= 0

      case frame[:type]
      when :data
        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :headers
        if frame[:weight] || frame[:stream_dependency] || !frame[:exclusive].nil?
          unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
            fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
          end
          frame[:flags] += [:priority] unless frame[:flags].include? :priority
        end

        if frame[:flags].include? :priority
          bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
          bytes << [frame[:weight] - 1].pack(UINT8)
          length += 5
        end

        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :priority
        unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
          fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
        end
        bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
        bytes << [frame[:weight] - 1].pack(UINT8)
        length += 5

      when :rst_stream
        bytes << pack_error(frame[:error])
        length += 4

      when :settings
        if (frame[:stream]).nonzero?
          fail CompressionError, "Invalid stream ID (#{frame[:stream]})"
        end

        frame[:payload].each do |(k, v)|
          if k.is_a? Integer
            DEFINED_SETTINGS.value?(k) || next
          else
            k = DEFINED_SETTINGS[k]

            fail CompressionError, "Unknown settings ID for #{k}" if k.nil?
          end

          bytes << [k].pack(UINT16)
          bytes << [v].pack(UINT32)
          length += 6
        end

      when :push_promise
        bytes << [frame[:promise_stream] & RBIT].pack(UINT32)
        bytes << frame[:payload]
        length += 4 + frame[:payload].bytesize

      when :ping
        if frame[:payload].bytesize != 8
          fail CompressionError, "Invalid payload size (#{frame[:payload].size} != 8 bytes)"
        end
        bytes << frame[:payload]
        length += 8

      when :goaway
        bytes << [frame[:last_stream] & RBIT].pack(UINT32)
        bytes << pack_error(frame[:error])
        length += 8

        if frame[:payload]
          bytes << frame[:payload]
          length += frame[:payload].bytesize
        end

      when :window_update
        bytes << [frame[:increment] & RBIT].pack(UINT32)
        length += 4

      when :continuation
        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :altsvc
        bytes << [frame[:max_age], frame[:port]].pack(UINT32 + UINT16)
        length += 6
        if frame[:proto]
          fail CompressionError, 'Proto too long' if frame[:proto].bytesize > 255
          bytes << [frame[:proto].bytesize].pack(UINT8)
          bytes << frame[:proto].force_encoding(Encoding::BINARY)
          length += 1 + frame[:proto].bytesize
        else
          bytes << [0].pack(UINT8)
          length += 1
        end
        if frame[:host]
          fail CompressionError, 'Host too long' if frame[:host].bytesize > 255
          bytes << [frame[:host].bytesize].pack(UINT8)
          bytes << frame[:host].force_encoding(Encoding::BINARY)
          length += 1 + frame[:host].bytesize
        else
          bytes << [0].pack(UINT8)
          length += 1
        end
        if frame[:origin]
          bytes << frame[:origin]
          length += frame[:origin].bytesize
        end
      end

      # Process padding.
      #  frame[:padding] gives number of extra octets to be added.
      # - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.1
      if frame[:padding]
        unless FRAME_TYPES_WITH_PADDING.include?(frame[:type])
          fail CompressionError, "Invalid padding flag for #{frame[:type]}"
        end

        padlen = frame[:padding]

        if padlen <= 0 || padlen > 256 || padlen + length > @max_frame_size
          fail CompressionError, "Invalid padding #{padlen}"
        end

        length += padlen
        bytes.prepend([padlen -= 1].pack(UINT8))
        frame[:flags] << :padded

        # Padding:  Padding octets that contain no application semantic value.
        # Padding octets MUST be set to zero when sending and ignored when
        # receiving.
        bytes << "\0" * padlen
      end

      frame[:length] = length
      bytes.prepend(common_header(frame))
    end
def generate(frame)
      bytes  = Buffer.new
      length = 0

      frame[:flags] ||= []
      frame[:stream] ||= 0

      case frame[:type]
      when :data
        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :headers
        if frame[:weight] || frame[:stream_dependency] || !frame[:exclusive].nil?
          unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
            fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
          end
          frame[:flags] += [:priority] unless frame[:flags].include? :priority
        end

        if frame[:flags].include? :priority
          bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
          bytes << [frame[:weight] - 1].pack(UINT8)
          length += 5
        end

        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :priority
        unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
          fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
        end
        bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
        bytes << [frame[:weight] - 1].pack(UINT8)
        length += 5

      when :rst_stream
        bytes << pack_error(frame[:error])
        length += 4

      when :settings
        if (frame[:stream]).nonzero?
          fail CompressionError, "Invalid stream ID (#{frame[:stream]})"
        end

        frame[:payload].each do |(k, v)|
          if k.is_a? Integer
            DEFINED_SETTINGS.value?(k) || next
          else
            k = DEFINED_SETTINGS[k]

            fail CompressionError, "Unknown settings ID for #{k}" if k.nil?
          end

          bytes << [k].pack(UINT16)
          bytes << [v].pack(UINT32)
          length += 6
        end

      when :push_promise
        bytes << [frame[:promise_stream] & RBIT].pack(UINT32)
        bytes << frame[:payload]
        length += 4 + frame[:payload].bytesize

      when :ping
        if frame[:payload].bytesize != 8
          fail CompressionError, "Invalid payload size (#{frame[:payload].size} != 8 bytes)"
        end
        bytes << frame[:payload]
        length += 8

      when :goaway
        bytes << [frame[:last_stream] & RBIT].pack(UINT32)
        bytes << pack_error(frame[:error])
        length += 8

        if frame[:payload]
          bytes << frame[:payload]
          length += frame[:payload].bytesize
        end

      when :window_update
        bytes << [frame[:increment] & RBIT].pack(UINT32)
        length += 4

      when :continuation
        bytes << frame[:payload]
        length += frame[:payload].bytesize

      when :altsvc
        bytes << [frame[:max_age], frame[:port]].pack(UINT32 + UINT16)
        length += 6
        if frame[:proto]
          fail CompressionError, 'Proto too long' if frame[:proto].bytesize > 255
          bytes << [frame[:proto].bytesize].pack(UINT8)
          bytes << frame[:proto].force_encoding(Encoding::BINARY)
          length += 1 + frame[:proto].bytesize
        else
          bytes << [0].pack(UINT8)
          length += 1
        end
        if frame[:host]
          fail CompressionError, 'Host too long' if frame[:host].bytesize > 255
          bytes << [frame[:host].bytesize].pack(UINT8)
          bytes << frame[:host].force_encoding(Encoding::BINARY)
          length += 1 + frame[:host].bytesize
        else
          bytes << [0].pack(UINT8)
          length += 1
        end
        if frame[:origin]
          bytes << frame[:origin]
          length += frame[:origin].bytesize
        end
      end

      # Process padding.
      #  frame[:padding] gives number of extra octets to be added.
      # - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.1
      if frame[:padding]
        unless FRAME_TYPES_WITH_PADDING.include?(frame[:type])
          fail CompressionError, "Invalid padding flag for #{frame[:type]}"
        end

        padlen = frame[:padding]

        if padlen <= 0 || padlen > 256 || padlen + length > @max_frame_size
          fail CompressionError, "Invalid padding #{padlen}"
        end

        length += padlen
        bytes.prepend([padlen -= 1].pack(UINT8))
        frame[:flags] << :padded

        # Padding:  Padding octets that contain no application semantic value.
        # Padding octets MUST be set to zero when sending and ignored when
        # receiving.
        bytes << "\0" * padlen
      end

      frame[:length] = length
      bytes.prepend(common_header(frame))
    end
Generates encoded HTTP/2 frame.
 - http://tools.ietf.org/html/draft-ietf-httpbis-http2

 @param frame [Hash]