module Msf::Exploit::Git::SmartHttp
  class Request < Rex::Proto::Http::Request

    include Msf::Exploit::Git::PktLine

    attr_reader :uri, :type, :method, :service, :wants, :haves

    def initialize(opts = {})
      @uri = opts[:uri] || '/'
      @type = opts[:type]
      @method = opts[:method]

      super(@method, @uri)
      @service = opts[:service]
      @body = opts[:body] || ''
      @wants = opts[:wants] || []
      @haves = opts[:haves] || []
    end

    def populate_wants_haves
      pkt_lines = Msf::Exploit::Git::PktLine.get_pkt_lines(@body)
      if pkt_lines.empty?
        return
      end

      pkt_lines.each do |line|
        data = Msf::Exploit::Git::PktLine.get_pkt_line_data(line)
        values = data.split
        @wants << values[1] if values[0] == 'want'
        @haves << values[1] if values[0] == 'have'
      end
    end

    def self.parse_raw_request(request)
      return nil unless request

      opts = {}
      opts[:uri] = request.raw_uri
      opts[:method] = request.method
      opts[:body] = request.body

      # only the ref-discovery request should have a query
      # string and no body
      service_str = request.uri_parts['QueryString']
      if service_str['service'] && !service_str['service'].empty?
        opts[:service] = service_str['service']
        opts[:type] = 'ref-discovery'
        opts[:uri] = request.raw_uri
        return Request.new(opts)
      end

      type_str = request.raw_uri.split('/').last
      if type_str =~ /git-(\w+-\w+)/
        opts[:type] = $1
      else
        opts[:type] = 'other'
      end

      Request.new(opts)
    end
  end
end
