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 222
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 111
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 133
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 394
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 144
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(&:strip!)
  }
  header
end
parse_query(str) click to toggle source

Parses the query component of a URI in str

# File lib/webrick/httputils.rb, line 370
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 201
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 183
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 232
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 174
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 466
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 507
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 480
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 496
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 473
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 489
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 222
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 111
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 133
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 394
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 144
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(&:strip!)
  }
  header
end
parse_query(str) click to toggle source

Parses the query component of a URI in str

# File lib/webrick/httputils.rb, line 370
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 201
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 183
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 232
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 174
def split_header_value(str)
  str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
                (?:,\s*|\Z)'xn).flatten
end