web-dev-qa-db-ja.com

Rubyでアンダースコアを含むURLを開く回避策はありますか?

Open-uriを使用してURLを開いています。

resp = open("http://sub_domain.domain.com")

アンダースコアが含まれていると、エラーが発生します。

 URI :: InvalidURIError:スキームhttpはレジストリ部分を受け入れません:sub_domain.domain.com(または不正なホスト名?)

これは、RFCによると、URLには文字と数字のみを含めることができるためです。回避策はありますか?

32
Arty

これはURIのバグのように見え、uri-open、HTTParty、および他の多くのgemはURI.parseを使用しています。

回避策は次のとおりです。

require 'net/http'
require 'open-uri'

def hopen(url)
  begin
    open(url)
  rescue URI::InvalidURIError
    Host = url.match(".+\:\/\/([^\/]+)")[1]
    path = url.partition(Host)[2] || "/"
    Net::HTTP.get Host, path
  end
end

resp = hopen("http://dear_raed.blogspot.com/2009_01_01_archive.html")
19
stef

URIは、URLがどのように見えるかという昔ながらの考えを持っています。

最近私はaddressable を使用してそれを回避しています:

require 'open-uri'
require 'addressable/uri'

class URI::Parser
  def split url
    a = Addressable::URI::parse url
    [a.scheme, a.userinfo, a.Host, a.port, nil, a.path, nil, a.query, a.fragment]
  end
end

resp = open("http://sub_domain.domain.com") # Yay!

gem install addressableを忘れずに

17
pguardiario

このRailsアプリの初期化子は、少なくともURI.parseを機能させるようです:

# config/initializers/uri_underscore.rb
class URI::Generic
  def initialize_with_registry_check(scheme,
                 userinfo, Host, port, registry,
                 path, opaque,
                 query,
                 fragment,
                 parser = DEFAULT_PARSER,
                 arg_check = false)
    if %w(http https).include?(scheme) && Host.nil? && registry =~ /_/
      initialize_without_registry_check(scheme, userinfo, registry, port, nil, path, opaque, query, fragment, parser, arg_check)
    else
      initialize_without_registry_check(scheme, userinfo, Host, port, registry, path, opaque, query, fragment, parser, arg_check)
    end
  end
  alias_method_chain :initialize, :registry_check
end
14
cluesque

このようなドメイン名にアンダースコアを含めることはできません。これはDNS標準の一部です。ダッシュ(-)を使用するつもりでしたか?

Open-uriがエラーをスローしなかったとしても、そのようなコマンドは無意味です。どうして?そのようなドメイン名を解決できる方法がないためです。せいぜいunknown Hostエラーが発生します。 _を使用してドメイン名を登録する方法はなく、独自のプライベートDNSサーバーを実行している場合でも、_を使用することは仕様に反しています。ルールを曲げて許可することもできますが(DNSサーバーソフトウェアを変更することにより)、オペレーティングシステムのDNSリゾルバーはこれをサポートせず、ルーターのDNSソフトウェアもサポートしません。

解決策:DNS名に_を使用しないでください。それはどこでも機能せず、仕様に違反しています

3
Earlz

以下は、外部gemを使用したり、URI.parseの一部をオーバーライドしたりせずに、さまざまな状況(rest-client、open-uriなど)の問題を解決するパッチです。

module URI
  DEFAULT_PARSER = Parser.new(:HOSTNAME => "(?:(?:[a-zA-Z\\d](?:[-\\_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.)*(?:[a-zA-Z](?:[-\\_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.?")
end

ソース: lib/uri/rfc2396_parser.rb#L86

Ruby-coreには未解決の問題があります: https://bugs.Ruby-lang.org/issues/8241

3
Larry Kyrala

Gem update/gem installなどを使用しようとしたときに同じエラーが発生したため、代わりにIPアドレスを使用しましたが、現在は問題ありません。

2
Julian Mann

ここに別の醜いハックがあります、宝石は必要ありません:

def parse(url = nil)
    begin
        URI.parse(url)
    rescue URI::InvalidURIError
        Host = url.match(".+\:\/\/([^\/]+)")[1]
        uri = URI.parse(url.sub(Host, 'dummy-Host'))
        uri.instance_variable_set('@Host', Host)
        uri
    end
end
2
sheerun

Curb gemを使用することをお勧めします: https://github.com/taf2/curb これはlibcurlをラップするだけです。これは、リダイレクトを自動的に追跡し、応答コードと応答本文を出力する簡単な例です。

rsp = Curl::Easy.http_get(url){|curl| curl.follow_location = true; curl.max_redirects=10;}
puts rsp.response_code
puts rsp.body_str

私は通常、Ruby URIクラスは、Webが野生の西であることがわかるように仕様が厳しすぎるため、避けます。).

0
TomDavies