<commit_before>##
# Request class for midori
# @attr [String] ip client ip address
# @attr [Integer] port client port
# @attr [String] protocol protocol version of HTTP request
# @attr [Symbol] method HTTP method
# @attr [String] path request path
# @attr [Hash] query_param parameter parsed from query string
# @attr [String | nil] query_string request query string
# @attr [Hash] header request header
# @attr [String] body request body
# @attr [Boolean] parsed whether the request header parsed
# @attr [Boolean] body_parsed whether the request body parsed
# @attr [Hash] params params in the url
class Midori::Request
  attr_accessor :ip, :port,
                :protocol, :method, :path, :query_params, :query_string,
                :header, :body, :parsed, :body_parsed, :params

  # Init Request
  def initialize
    @parsed = false
    @body_parsed = false
    @is_websocket = false
    @is_eventsource = false
    @parser = Http::Parser.new
    @params = {}
    @query_params = Hash.new(Array.new)
    @body = ''
    @parser.on_headers_complete = proc do
      @protocol = @parser.http_version
      @method = @parser.http_method
      @path = @parser.request_url
      @header = @parser.headers

      @query_string = @path.match(/\?(.*?)$/)
      unless @query_string.nil?
        @query_string = @query_string[1]
        @query_params = CGI::parse(@query_string)
      end
      @path.gsub!(/\?(.*?)$/, '')
      @method = @method.to_sym
      @parsed = true
      :stop
    end
  end

  # Init an request with String data
  # @param [String] data
  # @return [nil] nil
  def parse(data)
    # Call parser if header not parsed
    if @parsed
      @body += data
    else
      offset = @parser << data
      @body += data[offset..-1] if @parsed
    end

    # Set body parsed if body reaches content length
    if (@header['Content-Length'].to_i || 0) <= @body.bytesize
      @body_parsed = true
      pre_proceed
    end
    nil
  end

  # Preproceed the request after parsed
  # @return [nil] nil
  def pre_proceed
    # Deal with WebSocket
    if @header['Upgrade'] == 'websocket' && @header['Connection'] == 'Upgrade'
      @method = :WEBSOCKET
      @is_websocket = true
    end

    # Deal with EventSource
    if @header['Accept'] == 'text/event-stream'
      @method = :EVENTSOURCE
      @is_eventsource = true
    end

    @method = @method.to_sym
    nil
  end

  # Syntactic sugar for whether a request header is parsed
  # @return [Boolean] parsed or not
  def parsed?
    @parsed
  end

  # Syntactic sugar for whether a request body is parsed
  # @return [Boolean] parsed or not
  def body_parsed?
    @body_parsed
  end

  # Syntactic sugar for whether a request is a websocket request
  # @return [Boolean] websocket or not
  def websocket?
    @is_websocket
  end

  # Syntactic sugar for whether a request is an eventsource request
  # @return [Boolean] eventsource or not
  def eventsource?
    @is_eventsource
  end
end
<commit_msg>Parse body only when headers parsed first<commit_after>##
# Request class for midori
# @attr [String] ip client ip address
# @attr [Integer] port client port
# @attr [String] protocol protocol version of HTTP request
# @attr [Symbol] method HTTP method
# @attr [String] path request path
# @attr [Hash] query_param parameter parsed from query string
# @attr [String | nil] query_string request query string
# @attr [Hash] header request header
# @attr [String] body request body
# @attr [Boolean] parsed whether the request header parsed
# @attr [Boolean] body_parsed whether the request body parsed
# @attr [Hash] params params in the url
class Midori::Request
  attr_accessor :ip, :port,
                :protocol, :method, :path, :query_params, :query_string,
                :header, :body, :parsed, :body_parsed, :params

  # Init Request
  def initialize
    @parsed = false
    @body_parsed = false
    @is_websocket = false
    @is_eventsource = false
    @parser = Http::Parser.new
    @params = {}
    @query_params = Hash.new(Array.new)
    @body = ''
    @parser.on_headers_complete = proc do
      @protocol = @parser.http_version
      @method = @parser.http_method
      @path = @parser.request_url
      @header = @parser.headers

      @query_string = @path.match(/\?(.*?)$/)
      unless @query_string.nil?
        @query_string = @query_string[1]
        @query_params = CGI::parse(@query_string)
      end
      @path.gsub!(/\?(.*?)$/, '')
      @method = @method.to_sym
      @parsed = true
      :stop
    end
  end

  # Init an request with String data
  # @param [String] data
  # @return [nil] nil
  def parse(data)
    # Call parser if header not parsed
    if @parsed
      @body += data
    else
      offset = @parser << data
      @body += data[offset..-1] if @parsed
    end

    # Set body parsed if body reaches content length
    if @parsed && (@header['Content-Length'].to_i || 0) <= @body.bytesize
      @body_parsed = true
      pre_proceed
    end
    nil
  end

  # Preproceed the request after parsed
  # @return [nil] nil
  def pre_proceed
    # Deal with WebSocket
    if @header['Upgrade'] == 'websocket' && @header['Connection'] == 'Upgrade'
      @method = :WEBSOCKET
      @is_websocket = true
    end

    # Deal with EventSource
    if @header['Accept'] == 'text/event-stream'
      @method = :EVENTSOURCE
      @is_eventsource = true
    end

    @method = @method.to_sym
    nil
  end

  # Syntactic sugar for whether a request header is parsed
  # @return [Boolean] parsed or not
  def parsed?
    @parsed
  end

  # Syntactic sugar for whether a request body is parsed
  # @return [Boolean] parsed or not
  def body_parsed?
    @body_parsed
  end

  # Syntactic sugar for whether a request is a websocket request
  # @return [Boolean] websocket or not
  def websocket?
    @is_websocket
  end

  # Syntactic sugar for whether a request is an eventsource request
  # @return [Boolean] eventsource or not
  def eventsource?
    @is_eventsource
  end
end

{'fraction_non_alphanumeric': 0.10437259172390685, 'fraction_numerical': 0.0010051934997487016, 'mean_word_length': 2.8943248532289627, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2446860', 'n_tokens_mistral': 1848, 'n_tokens_neox': 1842, 'n_words': 621}