7
7

More than 5 years have passed since last update.

apache+passengerでproxyが使えない

Posted at

gemsのhttpclientを利用しているrailsアプリで、起動するサーバーアプリを変更したら、railsアプリがproxyへリクエストしてくれなくてハマったのでメモ。

症状

  • 前提

    • 環境変数のhttp_proxyに、リクエストを流したいproxyを設定しておく
  • thinでrailsアプリを起動

    • その中でhttpclientを叩くとproxyへリクエストを流してくれる
  • apache+passengerでrailsアプリを起動

    • その中でhttpclientを叩くとproxyへリクエストを流してくれない

下記のようなメッセージがログに残っている

SocketError : getaddrinfo: No address associated with hostname
gems/httpclient-2.3.4.1/lib/httpclient/session.rb:803:in `initialize'
gems/httpclient-2.3.4.1/lib/httpclient/session.rb:803:in `new'
gems/httpclient-2.3.4.1/lib/httpclient/session.rb:803:in `create_socket'
gems/httpclient-2.3.4.1/lib/httpclient/session.rb:752:in `block in connect'

proxyに流れなかった理由

  • 該当コード付近
    • gems/httpclient-2.3.4.1/lib/httpclient/session.rb:856
    def create_socket(site)
      socket = nil
      begin
        @debug_dev << "! CONNECT TO #{site.host}:#{site.port}\n" if @debug_dev
        if str = @test_loopback_http_response.shift
          socket = LoopBackSocket.new(site.host, site.port, str)
        elsif @socket_local == Site::EMPTY
          socket = TCPSocket.new(site.host, site.port)

TCPSocket.newのところで、エラーが出ているようです。
もう少し遡ってみましょう

  • gems/httpclient-2.3.4.1/lib/httpclient/session.rb:747
    # Connect to the server
    def connect
      site = @proxy || @dest
      retry_number = 0
      begin
        timeout(@connect_timeout, ConnectTimeoutError) do
          @socket = create_socket(site)

どうやらこの@proxyがnilになってしまっていて、意図通りになっていない様子
@proxyが設定されている場所を探してきます

  • gems/httpclient-2.3.4.1/lib/httpclient.rb:1156
  def load_environment
    # http_proxy
    if getenv('REQUEST_METHOD')
      # HTTP_PROXY conflicts with the environment variable usage in CGI where
      # HTTP_* is used for HTTP header information.  Unlike open-uri, we
      # simply ignore http_proxy in CGI env and use cgi_http_proxy instead.
      self.proxy = getenv('cgi_http_proxy')
    else
      self.proxy = getenv('http_proxy')
    end
    # no_proxy
    self.no_proxy = getenv('no_proxy')
  end

ここで設定されるようですね。
今回の場合、以下になっていたようです。

  • apache+passengerの場合
    • 今回はgetenv('REQUEST_METHOD')に'GET'が入る
    • cgi_http_proxyという環境変数は設定していないので、self.proxy = nilとなり、結果proxyには流れない
  • thinの場合
    • getenv('REQUEST_METHOD')がnilなので、getenv('http_proy')が読まれる

コードのコメントによると、衝突回避のようですね。
というわけで、環境変数を設定します

  • /etc/httpd/conf.d/myenv.conf
  SetEnv CGI_HTTP_PROXY http://proxy.example.com:8080

apacheを再起動して、意図通りに処理される事を確認しましたとさ

まとめ

  • railsからhttpclientをproxy経由で使いたい場合は、cgi_http_proxyを使いましょう。
  • 使おうとしているライブラリはちゃんと読めって事ですね。

要らんとこでハマりましたね〜(=w=;
ニッチすぎて自分以外が必要としないメモですね・・・w

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7