规范化 HTTP URI

Normalize HTTP URI

我从 Akamai 的日志文件中获取 URI,其中包含如下条目:

/foo/jim/jam
/foo/jim/jam?
/foo/./jim/jam
/foo/bar/../jim/jam
/foo/jim/jam?autho=<randomstring>&file=jam

我想将所有这些规范化为同一个条目,规则如下:

我原以为 Ruby 的 URI 库会涵盖这个,但是:

所以,在官方库失败的情况下,我发现自己正在编写一个基于正则表达式的解决方案。

def normalize(path)
  result = path.dup
  path.sub! /(?<=\?).+$/ do |query|
    query.split('&').reject do |kv|
      %w[ autho file ].include?(kv[/^[^=]+/])
    end.join('&')
  end
  path.sub! /\?$/, ''
  path.sub!(/^[^?]+/){ |path| path.gsub(%r{[^/]+/\.\.},'').gsub('/./','/') }
end

它恰好适用于我上面列出的测试用例,但有 450,000 条路径需要清理,我无法手动检查它们。

addressable gem 将为您规范化这些:

require 'addressable/uri'

# normalize relative paths
uri = Addressable::URI.parse('http://example.com/foo/bar/../jim/jam')
puts uri.normalize.to_s #=> "http://example.com/foo/jim/jam"

# removes trailing ?
uri = Addressable::URI.parse('http://example.com/foo/jim/jam?')
puts uri.normalize.to_s #=> "http://example.com/foo/jim/jam"

# leaves empty parameters alone
uri = Addressable::URI.parse('http://example.com/foo/jim/jam?jim')
puts uri.normalize.to_s #=> "http://example.com/foo/jim/jam?jim"

# remove specific query parameters
uri = Addressable::URI.parse('http://example.com/foo/jim/jam?autho=<randomstring>&file=jam')
cleaned_query = uri.query_values
cleaned_query.delete('autho')
cleaned_query.delete('file')
uri.query_values = cleaned_query
uri.normalize.to_s #=> "http://example.com/foo/jim/jam"

真正重要的东西,比如ESSENTIAL要记住的是,URL/URI是一个协议,一个host,资源的文件路径,后跟 options/parameters 被传递给被引用的资源。 (对于迂腐的人来说,那里还有其他可选的东西,但这就足够了。)

我们可以通过使用 URI class, and using the path 方法解析 URL 来提取路径。一旦我们有了路径,我们就会有一个绝对路径或一个基于站点根目录的相对路径。处理绝对路径很简单:

require 'uri'

%w[
  /foo/jim/jam
  /foo/jim/jam?
  /foo/./jim/jam
  /foo/bar/../jim/jam
  /foo/jim/jam?autho=<randomstring>&file=jam
].each do |url|
  uri = URI.parse(url)
  path = uri.path
  puts File.absolute_path(path)
end
# >> /foo/jim/jam
# >> /foo/jim/jam
# >> /foo/jim/jam
# >> /foo/jim/jam
# >> /foo/jim/jam

因为路径是基于服务器根目录的文件路径,我们玩游戏可以使用Ruby的File.absolute_path方法将'.'归一化。和'..'离开并获得真正的绝对路径。如果 ..(父目录)多于目录链,这将中断,但您不应该在提取的路径中找到它,因为这也会破坏 server/browser 到 serve/request/receive 的能力资源。

处理相对路径时 "interesting" 会多一些,但 File 仍然是我们的朋友,但这是一个不同的问题。