# module WEBrick::HTTPUtils

`HTTPUtils` provides utility methods for working with the HTTP protocol.

This module is generally used internally by `WEBrick`

### Constants

DefaultMimeTypes

  Default mime types

### Public Class Methods

dequote(str) click to toggle source

Removes quotes and escapes from `str`

    # File lib/webrick/httputils.rb, line 224
    def dequote(str)
      ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
      ret.gsub!(/\\(.)/, "\\1")
      ret
    end

load_mime_types(file) click to toggle source

Loads Apache-compatible mime.types in `file`.

    # File lib/webrick/httputils.rb, line 110
    def load_mime_types(file)
      # note: +file+ may be a "| command" for now; some people may
      # rely on this, but currently we do not use this method by default.
      open(file){ |io|
        hash = Hash.new
        io.each{ |line|
          next if /^#/ =~ line
          line.chomp!
          mimetype, ext0 = line.split(/\s+/, 2)
          next unless ext0
          next if ext0.empty?
          ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype }
        }
        hash
      }
    end

mime_type(filename, mime_tab) click to toggle source

Returns the mime type of `filename` from the list in `mime_tab`. If no mime type was found application/octet-stream is returned.

    # File lib/webrick/httputils.rb, line 132
    def mime_type(filename, mime_tab)
      suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
      suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
      mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
    end

normalize_path(path) click to toggle source

Normalizes a request path. Raises an exception if the path cannot be normalized.

    # File lib/webrick/httputils.rb, line 31
    def normalize_path(path)
      raise "abnormal path `#{path}'" if path[0] != ?/
      ret = path.dup

      ret.gsub!(%r{/+}o, '/')                    # //      => /
      while ret.sub!(%r'/\.(?:/|\Z)', '/'); end  # /.      => /
      while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo

      raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
      ret
    end

parse_form_data(io, boundary) click to toggle source

Parses form data in `io` with the given `boundary`

    # File lib/webrick/httputils.rb, line 396
    def parse_form_data(io, boundary)
      boundary_regexp = /\A--#{Regexp.quote(boundary)}(--)?#{CRLF}\z/
      form_data = Hash.new
      return form_data unless io
      data = nil
      io.each_line{|line|
        if boundary_regexp =~ line
          if data
            data.chop!
            key = data.name
            if form_data.has_key?(key)
              form_data[key].append_data(data)
            else
              form_data[key] = data
            end
          end
          data = FormData.new
          next
        else
          if data
            data << line
          end
        end
      }
      return form_data
    end

parse_header(raw) click to toggle source

Parses an HTTP header `raw` into a hash of header fields with an `Array` of values.

    # File lib/webrick/httputils.rb, line 143
    def parse_header(raw)
      header = Hash.new([].freeze)
      field = nil
      raw.each_line{|line|
        case line
        when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om
          field, value = $1, $2
          field.downcase!
          header[field] = [] unless header.has_key?(field)
          header[field] << value
        when /^\s+(.*?)\s*\z/om
          value = $1
          unless field
            raise HTTPStatus::BadRequest, "bad header '#{line}'."
          end
          header[field][-1] << " " << value
        else
          raise HTTPStatus::BadRequest, "bad header '#{line}'."
        end
      }
      header.each{|key, values|
        values.each{|value|
          value.strip!
          value.gsub!(/\s+/, " ")
        }
      }
      header
    end

parse_query(str) click to toggle source

Parses the query component of a `URI` in `str`

    # File lib/webrick/httputils.rb, line 372
    def parse_query(str)
      query = Hash.new
      if str
        str.split(/[&;]/).each{|x|
          next if x.empty?
          key, val = x.split(/=/,2)
          key = unescape_form(key)
          val = unescape_form(val.to_s)
          val = FormData.new(val)
          val.name = key
          if query.has_key?(key)
            query[key].append_data(val)
            next
          end
          query[key] = val
        }
      end
      query
    end

parse_qvalues(value) click to toggle source

Parses q values in `value` as used in Accept headers.

    # File lib/webrick/httputils.rb, line 203
    def parse_qvalues(value)
      tmp = []
      if value
        parts = value.split(/,\s*/)
        parts.each {|part|
          if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
            val = m[1]
            q = (m[2] or 1).to_f
            tmp.push([val, q])
          end
        }
        tmp = tmp.sort_by{|val, q| -q}
        tmp.collect!{|val, q| val}
      end
      return tmp
    end

parse_range_header(ranges_specifier) click to toggle source

Parses a `Range` header value `ranges_specifier`

    # File lib/webrick/httputils.rb, line 185
    def parse_range_header(ranges_specifier)
      if /^bytes=(.*)/ =~ ranges_specifier
        byte_range_set = split_header_value($1)
        byte_range_set.collect{|range_spec|
          case range_spec
          when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i
          when /^(\d+)-/      then $1.to_i .. -1
          when /^-(\d+)/      then -($1.to_i) .. -1
          else return nil
          end
        }
      end
    end

quote(str) click to toggle source

Quotes and escapes quotes in `str`

    # File lib/webrick/httputils.rb, line 234
    def quote(str)
      '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
    end

split_header_value(str) click to toggle source

Splits a header value `str` according to HTTP specification.

    # File lib/webrick/httputils.rb, line 176
    def split_header_value(str)
      str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
                    (?:,\s*|\Z)'xn).flatten
    end

### Public Instance Methods

escape(str) click to toggle source

Escapes HTTP reserved and unwise characters in `str`

    # File lib/webrick/httputils.rb, line 468
    def escape(str)
      _escape(str, UNESCAPED)
    end

escape8bit(str) click to toggle source

Escapes 8 bit characters in `str`

    # File lib/webrick/httputils.rb, line 509
    def escape8bit(str)
      _escape(str, NONASCII)
    end

escape_form(str) click to toggle source

Escapes form reserved characters in `str`

    # File lib/webrick/httputils.rb, line 482
    def escape_form(str)
      ret = _escape(str, UNESCAPED_FORM)
      ret.gsub!(/ /, "+")
      ret
    end

escape_path(str) click to toggle source

Escapes path `str`

    # File lib/webrick/httputils.rb, line 498
    def escape_path(str)
      result = ""
      str.scan(%r{/([^/]*)}).each{|i|
        result << "/" << _escape(i[0], UNESCAPED_PCHAR)
      }
      return result
    end

unescape(str) click to toggle source

Unescapes HTTP reserved and unwise characters in `str`

    # File lib/webrick/httputils.rb, line 475
    def unescape(str)
      _unescape(str, ESCAPED)
    end

unescape_form(str) click to toggle source

Unescapes form reserved characters in `str`

    # File lib/webrick/httputils.rb, line 491
    def unescape_form(str)
      _unescape(str.gsub(/\+/, " "), ESCAPED)
    end

### Private Instance Methods

dequote(str) click to toggle source

Removes quotes and escapes from `str`

    # File lib/webrick/httputils.rb, line 224
    def dequote(str)
      ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
      ret.gsub!(/\\(.)/, "\\1")
      ret
    end

load_mime_types(file) click to toggle source

Loads Apache-compatible mime.types in `file`.

    # File lib/webrick/httputils.rb, line 110
    def load_mime_types(file)
      # note: +file+ may be a "| command" for now; some people may
      # rely on this, but currently we do not use this method by default.
      open(file){ |io|
        hash = Hash.new
        io.each{ |line|
          next if /^#/ =~ line
          line.chomp!
          mimetype, ext0 = line.split(/\s+/, 2)
          next unless ext0
          next if ext0.empty?
          ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype }
        }
        hash
      }
    end

mime_type(filename, mime_tab) click to toggle source

Returns the mime type of `filename` from the list in `mime_tab`. If no mime type was found application/octet-stream is returned.

    # File lib/webrick/httputils.rb, line 132
    def mime_type(filename, mime_tab)
      suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
      suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
      mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
    end

normalize_path(path) click to toggle source

Normalizes a request path. Raises an exception if the path cannot be normalized.

    # File lib/webrick/httputils.rb, line 31
    def normalize_path(path)
      raise "abnormal path `#{path}'" if path[0] != ?/
      ret = path.dup

      ret.gsub!(%r{/+}o, '/')                    # //      => /
      while ret.sub!(%r'/\.(?:/|\Z)', '/'); end  # /.      => /
      while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo

      raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
      ret
    end

parse_form_data(io, boundary) click to toggle source

Parses form data in `io` with the given `boundary`

    # File lib/webrick/httputils.rb, line 396
    def parse_form_data(io, boundary)
      boundary_regexp = /\A--#{Regexp.quote(boundary)}(--)?#{CRLF}\z/
      form_data = Hash.new
      return form_data unless io
      data = nil
      io.each_line{|line|
        if boundary_regexp =~ line
          if data
            data.chop!
            key = data.name
            if form_data.has_key?(key)
              form_data[key].append_data(data)
            else
              form_data[key] = data
            end
          end
          data = FormData.new
          next
        else
          if data
            data << line
          end
        end
      }
      return form_data
    end

parse_header(raw) click to toggle source

Parses an HTTP header `raw` into a hash of header fields with an `Array` of values.

    # File lib/webrick/httputils.rb, line 143
    def parse_header(raw)
      header = Hash.new([].freeze)
      field = nil
      raw.each_line{|line|
        case line
        when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om
          field, value = $1, $2
          field.downcase!
          header[field] = [] unless header.has_key?(field)
          header[field] << value
        when /^\s+(.*?)\s*\z/om
          value = $1
          unless field
            raise HTTPStatus::BadRequest, "bad header '#{line}'."
          end
          header[field][-1] << " " << value
        else
          raise HTTPStatus::BadRequest, "bad header '#{line}'."
        end
      }
      header.each{|key, values|
        values.each{|value|
          value.strip!
          value.gsub!(/\s+/, " ")
        }
      }
      header
    end

parse_query(str) click to toggle source

Parses the query component of a `URI` in `str`

    # File lib/webrick/httputils.rb, line 372
    def parse_query(str)
      query = Hash.new
      if str
        str.split(/[&;]/).each{|x|
          next if x.empty?
          key, val = x.split(/=/,2)
          key = unescape_form(key)
          val = unescape_form(val.to_s)
          val = FormData.new(val)
          val.name = key
          if query.has_key?(key)
            query[key].append_data(val)
            next
          end
          query[key] = val
        }
      end
      query
    end

parse_qvalues(value) click to toggle source

Parses q values in `value` as used in Accept headers.

    # File lib/webrick/httputils.rb, line 203
    def parse_qvalues(value)
      tmp = []
      if value
        parts = value.split(/,\s*/)
        parts.each {|part|
          if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
            val = m[1]
            q = (m[2] or 1).to_f
            tmp.push([val, q])
          end
        }
        tmp = tmp.sort_by{|val, q| -q}
        tmp.collect!{|val, q| val}
      end
      return tmp
    end

parse_range_header(ranges_specifier) click to toggle source

Parses a `Range` header value `ranges_specifier`

    # File lib/webrick/httputils.rb, line 185
    def parse_range_header(ranges_specifier)
      if /^bytes=(.*)/ =~ ranges_specifier
        byte_range_set = split_header_value($1)
        byte_range_set.collect{|range_spec|
          case range_spec
          when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i
          when /^(\d+)-/      then $1.to_i .. -1
          when /^-(\d+)/      then -($1.to_i) .. -1
          else return nil
          end
        }
      end
    end

quote(str) click to toggle source

Quotes and escapes quotes in `str`

    # File lib/webrick/httputils.rb, line 234
    def quote(str)
      '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
    end

split_header_value(str) click to toggle source

Splits a header value `str` according to HTTP specification.

    # File lib/webrick/httputils.rb, line 176
    def split_header_value(str)
      str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
                    (?:,\s*|\Z)'xn).flatten
    end