def parse_http_request(request)
      # parse method
      if request.to_s !~ /\A(GET|HEAD|DELETE|POST|PUT|OPTIONS) /
        logger.warn('HTTP request method is not supported')
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              'HTTP request method is not supported.'
      end

      # parse client request
      begin
        req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
        req.parse(StringIO.new(request))
      rescue
        logger.warn('HTTP request is malformed.')
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              'HTTP request is malformed.'
      end

      # validate host
      if request.to_s !~ %r{\A(GET|HEAD|DELETE|POST|PUT|OPTIONS) https?://}
        if request.to_s =~ /^Host: ([^\s]+)\r?\n/
          logger.info("Using host header: #{$1}")
        else
          logger.warn('HTTP request is malformed : No host specified.')
          raise SSRFProxy::HTTP::Error::InvalidClientRequest,
                'HTTP request is malformed : No host specified.'
        end
      end

      # return request hash
      uri = req.request_uri
      method = req.request_method
      headers = req.header
      begin
        body = req.body.to_s
      rescue WEBrick::HTTPStatus::BadRequest => e
        logger.warn("HTTP request is malformed : #{e.message}")
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              "HTTP request is malformed : #{e.message}"
      rescue WEBrick::HTTPStatus::LengthRequired
        logger.warn("HTTP request is malformed : Request body without 'Content-Length' header.")
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              "HTTP request is malformed : Request body without 'Content-Length' header."
      end

      { 'uri'     => uri,
        'method'  => method,
        'headers' => headers,
        'body'    => body }
    end
def parse_http_request(request)
      # parse method
      if request.to_s !~ /\A(GET|HEAD|DELETE|POST|PUT|OPTIONS) /
        logger.warn('HTTP request method is not supported')
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              'HTTP request method is not supported.'
      end

      # parse client request
      begin
        req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
        req.parse(StringIO.new(request))
      rescue
        logger.warn('HTTP request is malformed.')
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              'HTTP request is malformed.'
      end

      # validate host
      if request.to_s !~ %r{\A(GET|HEAD|DELETE|POST|PUT|OPTIONS) https?://}
        if request.to_s =~ /^Host: ([^\s]+)\r?\n/
          logger.info("Using host header: #{$1}")
        else
          logger.warn('HTTP request is malformed : No host specified.')
          raise SSRFProxy::HTTP::Error::InvalidClientRequest,
                'HTTP request is malformed : No host specified.'
        end
      end

      # return request hash
      uri = req.request_uri
      method = req.request_method
      headers = req.header
      begin
        body = req.body.to_s
      rescue WEBrick::HTTPStatus::BadRequest => e
        logger.warn("HTTP request is malformed : #{e.message}")
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              "HTTP request is malformed : #{e.message}"
      rescue WEBrick::HTTPStatus::LengthRequired
        logger.warn("HTTP request is malformed : Request body without 'Content-Length' header.")
        raise SSRFProxy::HTTP::Error::InvalidClientRequest,
              "HTTP request is malformed : Request body without 'Content-Length' header."
      end

      { 'uri'     => uri,
        'method'  => method,
        'headers' => headers,
        'body'    => body }
    end
SSRFProxy::HTTP accepts SSRF connection information,
 and configuration options for request modification
 and response modification.

 @param url [String] Target URL vulnerable to SSRF

 @param file [String] Load HTTP request from a file

 @param proxy [String] Use a proxy to connect to the server.
                       (Supported proxies: http, https, socks)

 @param ssl [Boolean] Connect using SSL/TLS

 @param method [String] HTTP method (GET/HEAD/DELETE/POST/PUT/OPTIONS)
                        (Default: GET)

 @param post_data [String] HTTP post data

 @param user [String] HTTP basic authentication credentials

 @param rules [String] Rules for parsing client request
                       (separated by ',') (Default: none)

 @param no_urlencode [Boolean] Do not URL encode client request

 @param ip_encoding [String] Encode client request host IP address.
                             (Modes: int, ipv6, oct, hex, dotted_hex)

 @param match [String] Regex to match response body content.
                       (Default: \A(.*)\z)

 @param strip [String] Headers to remove from the response.
                       (separated by ',') (Default: none)

 @param decode_html [Boolean] Decode HTML entities in response body

 @param unescape [Boolean] Unescape special characters in response body

 @param guess_status [Boolean] Replaces response status code and message
                               headers (determined by common strings in the
                               response body, such as 404 Not Found.)

 @param guess_mime [Boolean] Replaces response content-type header with the
                             appropriate mime type (determined by the file
                             extension of the requested resource.)

 @param sniff_mime [Boolean] Replaces response content-type header with the
                             appropriate mime type (determined by magic bytes
                             in the response body.)

 @param timeout_ok [Boolean] Replaces timeout HTTP status code 504 with 200.

 @param detect_headers [Boolean] Replaces response headers if response headers
                                 are identified in the response body.

 @param fail_no_content [Boolean] Return HTTP status 502 if response body
                                  is empty.

 @param forward_method [Boolean] Forward client request method

 @param forward_headers [Boolean] Forward all client request headers

 @param forward_body [Boolean] Forward client request body

 @param forward_cookies [Boolean] Forward client request cookies

 @param body_to_uri [Boolean] Add client request body to URI query string

 @param auth_to_uri [Boolean] Use client request basic authentication
                              credentials in request URI.

 @param cookies_to_uri [Boolean] Add client request cookies to URI query string

 @param cache_buster [Boolean] Append a random value to the client request
                               query string

 @param timeout [Integer] Connection timeout in seconds (Default: 10)

 @param user_agent [String] HTTP user-agent (Default: none)

 @param insecure [Boolean] Skip server SSL certificate validation



 @example Configure SSRF with URL, GET method
   SSRFProxy::HTTP.new(url: 'http://example.local/?url=xxURLxx')

 @example Configure SSRF with URL, POST method
   SSRFProxy::HTTP.new(url: 'http://example.local/',
                       method: 'POST',
                       post_data: 'url=xxURLxx')

 @example Configure SSRF with raw HTTP request file
   SSRFProxy::HTTP.new(file: 'ssrf.txt')

 @example Configure SSRF with raw HTTP request file and force SSL/TLS
   SSRFProxy::HTTP.new(file: 'ssrf.txt', ssl: true)

 @example Configure SSRF with raw HTTP request StringIO
   SSRFProxy::HTTP.new(file: StringIO.new("GET http://example.local/?url=xxURLxx HTTP/1.1\n\n"))

 @raise [SSRFProxy::HTTP::Error::InvalidSsrfRequest]
        Invalid SSRF request specified.

 @raise [SSRFProxy::HTTP::Error::InvalidUpstreamProxy]
        Invalid upstream proxy specified.

 @raise [SSRFProxy::HTTP::Error::InvalidSsrfRequestMethod]
        Invalid SSRF request method specified.
        Supported methods: GET, HEAD, DELETE, POST, PUT, OPTIONS.

 @raise [SSRFProxy::HTTP::Error::NoUrlPlaceholder]
        'xxURLxx' URL placeholder must be specified in the
         SSRF request URL or body.

 @raise [SSRFProxy::HTTP::Error::InvalidIpEncoding]
        Invalid IP encoding method specified.


 Parse a raw HTTP request as a string

 @param [String] request raw HTTP request

 @raise [SSRFProxy::HTTP::Error::InvalidClientRequest]
        An invalid client HTTP request was supplied.

 @return [Hash] HTTP request hash (url, method, headers, body)