stella 0.7.0.004 → 0.7.0.005
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/stella +16 -20
 - data/examples/essentials/logo.png +0 -0
 - data/examples/{basic → essentials}/plan.rb +7 -3
 - data/examples/{basic → essentials}/search_terms.csv +0 -0
 - data/examples/example_webapp.rb +7 -4
 - data/examples/example_webapp.ru +3 -0
 - data/lib/stella.rb +18 -26
 - data/lib/stella/cli.rb +4 -1
 - data/lib/stella/client.rb +49 -26
 - data/lib/stella/data.rb +35 -9
 - data/lib/stella/data/http.rb +1 -1
 - data/lib/stella/data/http/request.rb +3 -14
 - data/lib/stella/engine.rb +10 -4
 - data/lib/stella/engine/functional.rb +2 -4
 - data/lib/stella/engine/load.rb +24 -21
 - data/lib/stella/mixins.rb +1 -1
 - data/lib/stella/stats.rb +17 -4
 - data/lib/stella/testplan/usecase.rb +2 -2
 - data/lib/stella/utils.rb +16 -1
 - data/lib/stella/version.rb +1 -1
 - data/stella.gemspec +17 -4
 - data/vendor/httpclient-2.1.5.2/httpclient.rb +1025 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/auth.rb +522 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/cacert.p7s +1579 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/cacert_sha1.p7s +1579 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/connection.rb +84 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/cookie.rb +562 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/http.rb +867 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/session.rb +864 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/ssl_config.rb +417 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/stats.rb +90 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/timeout.rb +136 -0
 - data/vendor/httpclient-2.1.5.2/httpclient/util.rb +86 -0
 - metadata +18 -5
 - data/lib/stella/dsl.rb +0 -5
 
    
        data/lib/stella/data/http.rb
    CHANGED
    
    
| 
         @@ -25,7 +25,7 @@ module Stella::Data::HTTP 
     | 
|
| 
       25 
25 
     | 
    
         
             
                field :content_type
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                def has_body?
         
     | 
| 
       28 
     | 
    
         
            -
                  !@body.nil? 
     | 
| 
      
 28 
     | 
    
         
            +
                  !@body.nil?
         
     | 
| 
       29 
29 
     | 
    
         
             
                end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                def initialize (method, uri_str, version="1.1", &definition)
         
     | 
| 
         @@ -70,7 +70,7 @@ module Stella::Data::HTTP 
     | 
|
| 
       70 
70 
     | 
    
         
             
                  if definition.nil?
         
     | 
| 
       71 
71 
     | 
    
         
             
                    @response_handler
         
     | 
| 
       72 
72 
     | 
    
         
             
                  else
         
     | 
| 
       73 
     | 
    
         
            -
                    args <<  
     | 
| 
      
 73 
     | 
    
         
            +
                    args << /.+/ if args.empty?
         
     | 
| 
       74 
74 
     | 
    
         
             
                    args.each do |status|
         
     | 
| 
       75 
75 
     | 
    
         
             
                      @response_handler[status] = definition
         
     | 
| 
       76 
76 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -80,18 +80,7 @@ module Stella::Data::HTTP 
     | 
|
| 
       80 
80 
     | 
    
         
             
                # +content+ can be literal content or a file path
         
     | 
| 
       81 
81 
     | 
    
         
             
                def body(*args)
         
     | 
| 
       82 
82 
     | 
    
         
             
                  return @body if args.empty?
         
     | 
| 
       83 
     | 
    
         
            -
                   
     | 
| 
       84 
     | 
    
         
            -
                  
         
     | 
| 
       85 
     | 
    
         
            -
                  @body.form_param = form_param if form_param
         
     | 
| 
       86 
     | 
    
         
            -
                  @body.content_type = content_type if content_type
         
     | 
| 
       87 
     | 
    
         
            -
                  
         
     | 
| 
       88 
     | 
    
         
            -
                  if File.exists?(content)
         
     | 
| 
       89 
     | 
    
         
            -
                    @body.content = File.new(content)
         
     | 
| 
       90 
     | 
    
         
            -
                    @body.content_type ||= "application/x-www-form-urlencoded"
         
     | 
| 
       91 
     | 
    
         
            -
                  else
         
     | 
| 
       92 
     | 
    
         
            -
                    @body.content = content
         
     | 
| 
       93 
     | 
    
         
            -
                  end
         
     | 
| 
       94 
     | 
    
         
            -
                  
         
     | 
| 
      
 83 
     | 
    
         
            +
                  @body = args.first
         
     | 
| 
       95 
84 
     | 
    
         
             
                end
         
     | 
| 
       96 
85 
     | 
    
         | 
| 
       97 
86 
     | 
    
         
             
                def inspect
         
     | 
    
        data/lib/stella/engine.rb
    CHANGED
    
    | 
         @@ -19,12 +19,16 @@ module Stella::Engine 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  end
         
     | 
| 
       20 
20 
     | 
    
         
             
                end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                def  
     | 
| 
      
 22 
     | 
    
         
            +
                def update_prepare_request(client_id, usecase, req, counter)
         
     | 
| 
       23 
23 
     | 
    
         
             
                  notice = "repeat: #{counter-1}" if counter > 1
         
     | 
| 
       24 
24 
     | 
    
         
             
                  Stella.li2 ' ' << " %-46s %16s ".att(:reverse) % [req.desc, notice]
         
     | 
| 
       25 
25 
     | 
    
         
             
                end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                def  
     | 
| 
      
 27 
     | 
    
         
            +
                def update_send_request(client_id, usecase, uri, req, params, counter)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                def update_receive_response(client_id, usecase, uri, req, params, container)
         
     | 
| 
       28 
32 
     | 
    
         
             
                  Stella.li '  %-59s %3d' % [uri, container.status]
         
     | 
| 
       29 
33 
     | 
    
         
             
                  Stella.li2 "  Method: " << req.http_method
         
     | 
| 
       30 
34 
     | 
    
         
             
                  Stella.li2 "  Params: " << params.inspect
         
     | 
| 
         @@ -42,14 +46,16 @@ module Stella::Engine 
     | 
|
| 
       42 
46 
     | 
    
         | 
| 
       43 
47 
     | 
    
         
             
                def update_error_execute_response_handler(client_id, ex, req, container)
         
     | 
| 
       44 
48 
     | 
    
         
             
                  Stella.le ex.message
         
     | 
| 
      
 49 
     | 
    
         
            +
                  Stella.ld ex.backtrace
         
     | 
| 
       45 
50 
     | 
    
         
             
                end
         
     | 
| 
       46 
51 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
                def update_request_error(client_id, usecase,  
     | 
| 
      
 52 
     | 
    
         
            +
                def update_request_error(client_id, usecase, uri, req, params, ex)
         
     | 
| 
       48 
53 
     | 
    
         
             
                  desc = "#{usecase.desc} > #{req.desc}"
         
     | 
| 
       49 
54 
     | 
    
         
             
                  Stella.le '  Client%-3s %-45s %s' % [client_id, desc, ex.message]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Stella.ld ex.backtrace
         
     | 
| 
       50 
56 
     | 
    
         
             
                end
         
     | 
| 
       51 
57 
     | 
    
         | 
| 
       52 
58 
     | 
    
         
             
              end
         
     | 
| 
       53 
59 
     | 
    
         
             
            end
         
     | 
| 
       54 
60 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
            Stella::Utils.require_glob( 
     | 
| 
      
 61 
     | 
    
         
            +
            Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'engine', '*.rb')
         
     | 
| 
         @@ -19,8 +19,8 @@ module Stella::Engine 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  client.enable_benchmark_mode if opts[:benchmark]
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                  Stella.li $/, "Starting test...", $/
         
     | 
| 
       22 
     | 
    
         
            -
                   
     | 
| 
       23 
     | 
    
         
            -
                  sleep 0. 
     | 
| 
      
 22 
     | 
    
         
            +
                  Stella.lflush
         
     | 
| 
      
 23 
     | 
    
         
            +
                  sleep 0.3
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  plan.usecases.each_with_index do |uc,i|
         
     | 
| 
       26 
26 
     | 
    
         
             
                    desc = (uc.desc || "Usecase ##{i+1}")
         
     | 
| 
         @@ -28,8 +28,6 @@ module Stella::Engine 
     | 
|
| 
       28 
28 
     | 
    
         
             
                    Stella.rescue { client.execute uc }
         
     | 
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                  Drydock::Screen.flush
         
     | 
| 
       32 
     | 
    
         
            -
                  
         
     | 
| 
       33 
31 
     | 
    
         
             
                  !plan.errors?
         
     | 
| 
       34 
32 
     | 
    
         
             
                end
         
     | 
| 
       35 
33 
     | 
    
         | 
    
        data/lib/stella/engine/load.rb
    CHANGED
    
    | 
         @@ -7,40 +7,37 @@ module Stella::Engine 
     | 
|
| 
       7 
7 
     | 
    
         
             
                def run(plan, opts={})
         
     | 
| 
       8 
8 
     | 
    
         
             
                  opts = {
         
     | 
| 
       9 
9 
     | 
    
         
             
                    :hosts        => [],
         
     | 
| 
       10 
     | 
    
         
            -
                    : 
     | 
| 
      
 10 
     | 
    
         
            +
                    :clients        => 1,
         
     | 
| 
       11 
11 
     | 
    
         
             
                    :time         => nil,
         
     | 
| 
       12 
12 
     | 
    
         
             
                    :benchmark    => false,
         
     | 
| 
       13 
13 
     | 
    
         
             
                    :repetitions  => 1
         
     | 
| 
       14 
14 
     | 
    
         
             
                  }.merge! opts
         
     | 
| 
       15 
     | 
    
         
            -
                  opts[: 
     | 
| 
       16 
     | 
    
         
            -
                  opts[: 
     | 
| 
      
 15 
     | 
    
         
            +
                  opts[:clients] = plan.usecases.size if opts[:clients] < plan.usecases.size
         
     | 
| 
      
 16 
     | 
    
         
            +
                  opts[:clients] = 1000 if opts[:clients] > 1000
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  Stella.ld "OPTIONS: #{opts.inspect}"
         
     | 
| 
       19 
19 
     | 
    
         
             
                  Stella.li3 "Hosts: " << opts[:hosts].join(', ')
         
     | 
| 
       20 
20 
     | 
    
         
             
                  Stella.li2 plan.pretty
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                  packages = build_thread_package plan, opts
         
     | 
| 
       23 
     | 
    
         
            -
                  Stella.li $/, "Prepared #{packages.size} virtual  
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 23 
     | 
    
         
            +
                  Stella.li $/, "Prepared #{packages.size} virtual clients..."
         
     | 
| 
      
 24 
     | 
    
         
            +
                  Stella.lflush
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                  Stella.li $/, "Starting test...", $/
         
     | 
| 
       28 
     | 
    
         
            -
                   
     | 
| 
       29 
     | 
    
         
            -
                  sleep 0. 
     | 
| 
      
 28 
     | 
    
         
            +
                  Stella.lflush
         
     | 
| 
      
 29 
     | 
    
         
            +
                  sleep 0.3
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                  Thread.ify packages, :threads => opts[: 
     | 
| 
      
 31 
     | 
    
         
            +
                  Thread.ify packages, :threads => opts[:clients] do |package|
         
     | 
| 
       32 
32 
     | 
    
         
             
                    # TEMPFIX. The fill in build_thread_package is creating nil elements
         
     | 
| 
       33 
33 
     | 
    
         
             
                    next if package.nil? 
         
     | 
| 
       34 
34 
     | 
    
         
             
                    (1..opts[:repetitions]).to_a.each do |rep|
         
     | 
| 
       35 
35 
     | 
    
         
             
                      # We store client specific data in the usecase
         
     | 
| 
       36 
36 
     | 
    
         
             
                      # so we clone it here so each thread is unique.
         
     | 
| 
       37 
37 
     | 
    
         
             
                      Stella.rescue { package.client.execute package.usecase }
         
     | 
| 
       38 
     | 
    
         
            -
                      Drydock::Screen.flush
         
     | 
| 
       39 
38 
     | 
    
         
             
                    end
         
     | 
| 
       40 
39 
     | 
    
         
             
                  end
         
     | 
| 
       41 
40 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
                  Drydock::Screen.flush
         
     | 
| 
       43 
     | 
    
         
            -
                  
         
     | 
| 
       44 
41 
     | 
    
         
             
                  !plan.errors?
         
     | 
| 
       45 
42 
     | 
    
         
             
                end
         
     | 
| 
       46 
43 
     | 
    
         | 
| 
         @@ -55,21 +52,22 @@ module Stella::Engine 
     | 
|
| 
       55 
52 
     | 
    
         
             
                end
         
     | 
| 
       56 
53 
     | 
    
         | 
| 
       57 
54 
     | 
    
         
             
                def build_thread_package(plan, opts)
         
     | 
| 
       58 
     | 
    
         
            -
                  packages, pointer = Array.new(opts[: 
     | 
| 
      
 55 
     | 
    
         
            +
                  packages, pointer = Array.new(opts[:clients]), 0
         
     | 
| 
       59 
56 
     | 
    
         
             
                  plan.usecases.each_with_index do |usecase,i|
         
     | 
| 
       60 
57 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
                    count = case opts[: 
     | 
| 
      
 58 
     | 
    
         
            +
                    count = case opts[:clients]
         
     | 
| 
       62 
59 
     | 
    
         
             
                    when 0..9
         
     | 
| 
       63 
     | 
    
         
            -
                      if (opts[: 
     | 
| 
       64 
     | 
    
         
            -
                         
     | 
| 
      
 60 
     | 
    
         
            +
                      if (opts[:clients] % plan.usecases.size > 0) 
         
     | 
| 
      
 61 
     | 
    
         
            +
                        msg = "Client count does not evenly match usecase count"
         
     | 
| 
      
 62 
     | 
    
         
            +
                        raise Stella::Testplan::WackyRatio, msg
         
     | 
| 
       65 
63 
     | 
    
         
             
                      else
         
     | 
| 
       66 
     | 
    
         
            -
                        (opts[: 
     | 
| 
      
 64 
     | 
    
         
            +
                        (opts[:clients] / plan.usecases.size)
         
     | 
| 
       67 
65 
     | 
    
         
             
                      end
         
     | 
| 
       68 
66 
     | 
    
         
             
                    else
         
     | 
| 
       69 
     | 
    
         
            -
                      (opts[: 
     | 
| 
      
 67 
     | 
    
         
            +
                      (opts[:clients] * usecase.ratio).to_i
         
     | 
| 
       70 
68 
     | 
    
         
             
                    end
         
     | 
| 
       71 
69 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
                    Stella.ld "THREAD PACKAGE: #{usecase.desc} #{pointer}  
     | 
| 
      
 70 
     | 
    
         
            +
                    Stella.ld "THREAD PACKAGE: #{usecase.desc} (#{pointer} + #{count})"
         
     | 
| 
       73 
71 
     | 
    
         
             
                    # Fill the thread_package with the contents of the block
         
     | 
| 
       74 
72 
     | 
    
         
             
                    packages.fill(pointer, count) do |index|
         
     | 
| 
       75 
73 
     | 
    
         
             
                      Stella.li2 "Creating client ##{index+1} "
         
     | 
| 
         @@ -83,11 +81,15 @@ module Stella::Engine 
     | 
|
| 
       83 
81 
     | 
    
         
             
                  packages
         
     | 
| 
       84 
82 
     | 
    
         
             
                end
         
     | 
| 
       85 
83 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                def  
     | 
| 
      
 84 
     | 
    
         
            +
                def update_prepare_request(client_id, usecase, req, counter)
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
                
         
     | 
| 
      
 88 
     | 
    
         
            +
                def update_send_request(client_id, usecase, uri, req, params, counter)
         
     | 
| 
       87 
89 
     | 
    
         | 
| 
       88 
90 
     | 
    
         
             
                end
         
     | 
| 
       89 
91 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
                def update_receive_response(client_id, usecase,  
     | 
| 
      
 92 
     | 
    
         
            +
                def update_receive_response(client_id, usecase, uri, req, params, container)
         
     | 
| 
       91 
93 
     | 
    
         
             
                  desc = "#{usecase.desc} > #{req.desc}"
         
     | 
| 
       92 
94 
     | 
    
         
             
                  Stella.li2 '  Client%-3s %3d %-6s %-45s %s' % [client_id, container.status, req.http_method, desc, uri]
         
     | 
| 
       93 
95 
     | 
    
         
             
                end
         
     | 
| 
         @@ -98,9 +100,10 @@ module Stella::Engine 
     | 
|
| 
       98 
100 
     | 
    
         
             
                def update_error_execute_response_handler(client_id, ex, req, container)
         
     | 
| 
       99 
101 
     | 
    
         
             
                end
         
     | 
| 
       100 
102 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
                def update_request_error(client_id, usecase,  
     | 
| 
      
 103 
     | 
    
         
            +
                def update_request_error(client_id, usecase, uri, req, params, ex)
         
     | 
| 
       102 
104 
     | 
    
         
             
                  desc = "#{usecase.desc} > #{req.desc}"
         
     | 
| 
       103 
105 
     | 
    
         
             
                  Stella.le '  Client%-3s %-45s %s' % [client_id, desc, ex.message]
         
     | 
| 
      
 106 
     | 
    
         
            +
                  Stella.ld ex.backtrace
         
     | 
| 
       104 
107 
     | 
    
         
             
                end
         
     | 
| 
       105 
108 
     | 
    
         | 
| 
       106 
109 
     | 
    
         | 
    
        data/lib/stella/mixins.rb
    CHANGED
    
    | 
         @@ -1,2 +1,2 @@ 
     | 
|
| 
       1 
1 
     | 
    
         | 
| 
       2 
     | 
    
         
            -
            Stella::Utils.require_glob( 
     | 
| 
      
 2 
     | 
    
         
            +
            Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'mixins', '*.rb')
         
     | 
    
        data/lib/stella/stats.rb
    CHANGED
    
    | 
         @@ -36,15 +36,28 @@ class Stats 
     | 
|
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
              # Dump this Stats object with an optional additional message.
         
     | 
| 
       38 
38 
     | 
    
         
             
              def dump(msg = "", out=STDERR)
         
     | 
| 
       39 
     | 
    
         
            -
                out.puts "#{msg}: #{self. 
     | 
| 
      
 39 
     | 
    
         
            +
                out.puts "#{msg}: #{self.inspect}"
         
     | 
| 
       40 
40 
     | 
    
         
             
              end
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
              # Returns a common display (used by dump)
         
     | 
| 
       43 
     | 
    
         
            -
              def  
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 43 
     | 
    
         
            +
              def inspect
         
     | 
| 
      
 44 
     | 
    
         
            +
                v = [mean, @n, @sum, @sumsq, sd, @min, @max]
         
     | 
| 
      
 45 
     | 
    
         
            +
                t = %w"N=%0.4f SUM=%0.4f SUMSQ=%0.4f SD=%0.4f MIN=%0.4f MAX=%0.4f"
         
     | 
| 
      
 46 
     | 
    
         
            +
                "%0.4f: " << t % v
         
     | 
| 
       45 
47 
     | 
    
         
             
              end
         
     | 
| 
       46 
48 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 50 
     | 
    
         
            +
                mean.to_s
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
              
         
     | 
| 
      
 53 
     | 
    
         
            +
              def to_f
         
     | 
| 
      
 54 
     | 
    
         
            +
                mean.to_f
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
              
         
     | 
| 
      
 57 
     | 
    
         
            +
              def to_i
         
     | 
| 
      
 58 
     | 
    
         
            +
                mean.to_i
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
              
         
     | 
| 
       48 
61 
     | 
    
         
             
              # Calculates and returns the mean for the data passed so far.
         
     | 
| 
       49 
62 
     | 
    
         
             
              def mean
         
     | 
| 
       50 
63 
     | 
    
         
             
                @sum / @n
         
     | 
| 
         @@ -59,13 +59,13 @@ class Testplan 
     | 
|
| 
       59 
59 
     | 
    
         | 
| 
       60 
60 
     | 
    
         
             
                # Reads the contents of the file <tt>path</tt> (the current working
         
     | 
| 
       61 
61 
     | 
    
         
             
                # directory is assumed to be the same directory containing the test plan).
         
     | 
| 
       62 
     | 
    
         
            -
                def  
     | 
| 
      
 62 
     | 
    
         
            +
                def read(path)
         
     | 
| 
       63 
63 
     | 
    
         
             
                  path = File.join(@base_path, path) if @base_path
         
     | 
| 
       64 
64 
     | 
    
         
             
                  File.read(path)
         
     | 
| 
       65 
65 
     | 
    
         
             
                end
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
       67 
67 
     | 
    
         
             
                def list(path)
         
     | 
| 
       68 
     | 
    
         
            -
                   
     | 
| 
      
 68 
     | 
    
         
            +
                  read(path).split $/
         
     | 
| 
       69 
69 
     | 
    
         
             
                end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                def add_request(meth, *args, &blk)
         
     | 
    
        data/lib/stella/utils.rb
    CHANGED
    
    | 
         @@ -2,7 +2,6 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require 'socket'
         
     | 
| 
       3 
3 
     | 
    
         
             
            require 'open-uri'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'date'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
5 
     | 
    
         
             
            require 'timeout'
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
            module Stella
         
     | 
| 
         @@ -56,6 +55,22 @@ module Stella 
     | 
|
| 
       56 
55 
     | 
    
         
             
                  end
         
     | 
| 
       57 
56 
     | 
    
         
             
                end
         
     | 
| 
       58 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                # <tt>require</tt> a library from the vendor directory.
         
     | 
| 
      
 60 
     | 
    
         
            +
                # The vendor directory should be organized such
         
     | 
| 
      
 61 
     | 
    
         
            +
                # that +name+ and +version+ can be used to create
         
     | 
| 
      
 62 
     | 
    
         
            +
                # the path to the library. 
         
     | 
| 
      
 63 
     | 
    
         
            +
                #
         
     | 
| 
      
 64 
     | 
    
         
            +
                # e.g.
         
     | 
| 
      
 65 
     | 
    
         
            +
                # 
         
     | 
| 
      
 66 
     | 
    
         
            +
                #     vendor/httpclient-2.1.5.2/httpclient
         
     | 
| 
      
 67 
     | 
    
         
            +
                #
         
     | 
| 
      
 68 
     | 
    
         
            +
                def require_vendor(name, version)
         
     | 
| 
      
 69 
     | 
    
         
            +
                   $: << File.join(LIB_HOME, '..', 'vendor', "#{name}-#{version}")
         
     | 
| 
      
 70 
     | 
    
         
            +
                   require name
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
                
         
     | 
| 
      
 73 
     | 
    
         
            +
                
         
     | 
| 
       59 
74 
     | 
    
         
             
                # Checks whether something is listening to a socket. 
         
     | 
| 
       60 
75 
     | 
    
         
             
                # * +host+ A hostname
         
     | 
| 
       61 
76 
     | 
    
         
             
                # * +port+ The port to check
         
     | 
    
        data/lib/stella/version.rb
    CHANGED
    
    
    
        data/stella.gemspec
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            @spec = Gem::Specification.new do |s|
         
     | 
| 
       2 
2 
     | 
    
         
             
              s.name = "stella"
         
     | 
| 
       3 
3 
     | 
    
         
             
              s.rubyforge_project = 'stella'
         
     | 
| 
       4 
     | 
    
         
            -
              s.version = "0.7.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              s.version = "0.7.0.005"
         
     | 
| 
       5 
5 
     | 
    
         
             
              s.summary = "Stella: Your friend in performance testing."
         
     | 
| 
       6 
6 
     | 
    
         
             
              s.description = s.summary
         
     | 
| 
       7 
7 
     | 
    
         
             
              s.author = "Delano Mandelbaum"
         
     | 
| 
         @@ -29,9 +29,11 @@ 
     | 
|
| 
       29 
29 
     | 
    
         
             
              README.rdoc
         
     | 
| 
       30 
30 
     | 
    
         
             
              Rakefile
         
     | 
| 
       31 
31 
     | 
    
         
             
              bin/stella
         
     | 
| 
       32 
     | 
    
         
            -
              examples/ 
     | 
| 
       33 
     | 
    
         
            -
              examples/ 
     | 
| 
      
 32 
     | 
    
         
            +
              examples/essentials/logo.png
         
     | 
| 
      
 33 
     | 
    
         
            +
              examples/essentials/plan.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
              examples/essentials/search_terms.csv
         
     | 
| 
       34 
35 
     | 
    
         
             
              examples/example_webapp.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
              examples/example_webapp.ru
         
     | 
| 
       35 
37 
     | 
    
         
             
              examples/exceptions/plan.rb
         
     | 
| 
       36 
38 
     | 
    
         
             
              lib/stella.rb
         
     | 
| 
       37 
39 
     | 
    
         
             
              lib/stella/cli.rb
         
     | 
| 
         @@ -42,7 +44,6 @@ 
     | 
|
| 
       42 
44 
     | 
    
         
             
              lib/stella/data/http/body.rb
         
     | 
| 
       43 
45 
     | 
    
         
             
              lib/stella/data/http/request.rb
         
     | 
| 
       44 
46 
     | 
    
         
             
              lib/stella/data/http/response.rb
         
     | 
| 
       45 
     | 
    
         
            -
              lib/stella/dsl.rb
         
     | 
| 
       46 
47 
     | 
    
         
             
              lib/stella/engine.rb
         
     | 
| 
       47 
48 
     | 
    
         
             
              lib/stella/engine/functional.rb
         
     | 
| 
       48 
49 
     | 
    
         
             
              lib/stella/engine/load.rb
         
     | 
| 
         @@ -59,6 +60,18 @@ 
     | 
|
| 
       59 
60 
     | 
    
         
             
              lib/threadify.rb
         
     | 
| 
       60 
61 
     | 
    
         
             
              stella.gemspec
         
     | 
| 
       61 
62 
     | 
    
         
             
              support/useragents.txt
         
     | 
| 
      
 63 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient.rb
         
     | 
| 
      
 64 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/auth.rb
         
     | 
| 
      
 65 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/cacert.p7s
         
     | 
| 
      
 66 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/cacert_sha1.p7s
         
     | 
| 
      
 67 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/connection.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/cookie.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/http.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/session.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/ssl_config.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/stats.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/timeout.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
              vendor/httpclient-2.1.5.2/httpclient/util.rb
         
     | 
| 
       62 
75 
     | 
    
         
             
              )
         
     | 
| 
       63 
76 
     | 
    
         | 
| 
       64 
77 
     | 
    
         | 
| 
         @@ -0,0 +1,1025 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # HTTPClient - HTTP client library.
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright (C) 2000-2009  NAKAMURA, Hiroshi  <nahi@ruby-lang.org>.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
         
     | 
| 
      
 5 
     | 
    
         
            +
            # redistribute it and/or modify it under the same terms of Ruby's license;
         
     | 
| 
      
 6 
     | 
    
         
            +
            # either the dual license version in 2003, or any later version.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'stringio'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'digest/sha1'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # Extra library
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'httpclient/util'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'httpclient/ssl_config'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'httpclient/connection'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require 'httpclient/session'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'httpclient/http'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'httpclient/auth'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'httpclient/cookie'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require 'httpclient/stats'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            # The HTTPClient class provides several methods for accessing Web resources
         
     | 
| 
      
 26 
     | 
    
         
            +
            # via HTTP.
         
     | 
| 
      
 27 
     | 
    
         
            +
            #
         
     | 
| 
      
 28 
     | 
    
         
            +
            # HTTPClient instance is designed to be MT-safe.  You can call a HTTPClient
         
     | 
| 
      
 29 
     | 
    
         
            +
            # instance from several threads without synchronization after setting up an
         
     | 
| 
      
 30 
     | 
    
         
            +
            # instance.
         
     | 
| 
      
 31 
     | 
    
         
            +
            #
         
     | 
| 
      
 32 
     | 
    
         
            +
            #   clnt = HTTPClient.new
         
     | 
| 
      
 33 
     | 
    
         
            +
            #   clnt.set_cookie_store('/home/nahi/cookie.dat')
         
     | 
| 
      
 34 
     | 
    
         
            +
            #   urls.each do |url|
         
     | 
| 
      
 35 
     | 
    
         
            +
            #     Thread.new(url) do |u|
         
     | 
| 
      
 36 
     | 
    
         
            +
            #       p clnt.head(u).status
         
     | 
| 
      
 37 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 38 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 39 
     | 
    
         
            +
            #
         
     | 
| 
      
 40 
     | 
    
         
            +
            # == How to use
         
     | 
| 
      
 41 
     | 
    
         
            +
            #
         
     | 
| 
      
 42 
     | 
    
         
            +
            # At first, how to create your client.  See initialize for more detail.
         
     | 
| 
      
 43 
     | 
    
         
            +
            #
         
     | 
| 
      
 44 
     | 
    
         
            +
            # 1. Create simple client.
         
     | 
| 
      
 45 
     | 
    
         
            +
            #
         
     | 
| 
      
 46 
     | 
    
         
            +
            #     clnt = HTTPClient.new
         
     | 
| 
      
 47 
     | 
    
         
            +
            #
         
     | 
| 
      
 48 
     | 
    
         
            +
            # 2. Accessing resources through HTTP proxy.  You can use environment
         
     | 
| 
      
 49 
     | 
    
         
            +
            #    variable 'http_proxy' or 'HTTP_PROXY' instead.
         
     | 
| 
      
 50 
     | 
    
         
            +
            #
         
     | 
| 
      
 51 
     | 
    
         
            +
            #     clnt = HTTPClient.new('http://myproxy:8080')
         
     | 
| 
      
 52 
     | 
    
         
            +
            #
         
     | 
| 
      
 53 
     | 
    
         
            +
            # === How to retrieve web resources
         
     | 
| 
      
 54 
     | 
    
         
            +
            #
         
     | 
| 
      
 55 
     | 
    
         
            +
            # See get_content.
         
     | 
| 
      
 56 
     | 
    
         
            +
            #
         
     | 
| 
      
 57 
     | 
    
         
            +
            # 1. Get content of specified URL.  It returns a String of whole result.
         
     | 
| 
      
 58 
     | 
    
         
            +
            #
         
     | 
| 
      
 59 
     | 
    
         
            +
            #     puts clnt.get_content('http://dev.ctor.org/')
         
     | 
| 
      
 60 
     | 
    
         
            +
            #
         
     | 
| 
      
 61 
     | 
    
         
            +
            # 2. Get content as chunks of String.  It yields chunks of String.
         
     | 
| 
      
 62 
     | 
    
         
            +
            #
         
     | 
| 
      
 63 
     | 
    
         
            +
            #     clnt.get_content('http://dev.ctor.org/') do |chunk|
         
     | 
| 
      
 64 
     | 
    
         
            +
            #       puts chunk
         
     | 
| 
      
 65 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 66 
     | 
    
         
            +
            #
         
     | 
| 
      
 67 
     | 
    
         
            +
            # === Invoking other HTTP methods
         
     | 
| 
      
 68 
     | 
    
         
            +
            #
         
     | 
| 
      
 69 
     | 
    
         
            +
            # See head, get, post, put, delete, options, propfind, proppatch and trace.  
         
     | 
| 
      
 70 
     | 
    
         
            +
            # It returns a HTTP::Message instance as a response.
         
     | 
| 
      
 71 
     | 
    
         
            +
            #
         
     | 
| 
      
 72 
     | 
    
         
            +
            # 1. Do HEAD request.
         
     | 
| 
      
 73 
     | 
    
         
            +
            #
         
     | 
| 
      
 74 
     | 
    
         
            +
            #     res = clnt.head(uri)
         
     | 
| 
      
 75 
     | 
    
         
            +
            #     p res.header['Last-Modified'][0]
         
     | 
| 
      
 76 
     | 
    
         
            +
            #
         
     | 
| 
      
 77 
     | 
    
         
            +
            # 2. Do GET request with query.
         
     | 
| 
      
 78 
     | 
    
         
            +
            #
         
     | 
| 
      
 79 
     | 
    
         
            +
            #     query = { 'keyword' => 'ruby', 'lang' => 'en' }
         
     | 
| 
      
 80 
     | 
    
         
            +
            #     res = clnt.get(uri, query)
         
     | 
| 
      
 81 
     | 
    
         
            +
            #     p res.status
         
     | 
| 
      
 82 
     | 
    
         
            +
            #     p res.contenttype
         
     | 
| 
      
 83 
     | 
    
         
            +
            #     p res.header['X-Custom']
         
     | 
| 
      
 84 
     | 
    
         
            +
            #     puts res.content
         
     | 
| 
      
 85 
     | 
    
         
            +
            #
         
     | 
| 
      
 86 
     | 
    
         
            +
            # === How to POST
         
     | 
| 
      
 87 
     | 
    
         
            +
            #
         
     | 
| 
      
 88 
     | 
    
         
            +
            # See post.
         
     | 
| 
      
 89 
     | 
    
         
            +
            #
         
     | 
| 
      
 90 
     | 
    
         
            +
            # 1. Do POST a form data.
         
     | 
| 
      
 91 
     | 
    
         
            +
            #
         
     | 
| 
      
 92 
     | 
    
         
            +
            #     body = { 'keyword' => 'ruby', 'lang' => 'en' }
         
     | 
| 
      
 93 
     | 
    
         
            +
            #     res = clnt.post(uri, body)
         
     | 
| 
      
 94 
     | 
    
         
            +
            #
         
     | 
| 
      
 95 
     | 
    
         
            +
            # 2. Do multipart file upload with POST.  No need to set extra header by
         
     | 
| 
      
 96 
     | 
    
         
            +
            #    yourself from httpclient/2.1.4.
         
     | 
| 
      
 97 
     | 
    
         
            +
            #
         
     | 
| 
      
 98 
     | 
    
         
            +
            #     File.open('/tmp/post_data') do |file|
         
     | 
| 
      
 99 
     | 
    
         
            +
            #       body = { 'upload' => file, 'user' => 'nahi' }
         
     | 
| 
      
 100 
     | 
    
         
            +
            #       res = clnt.post(uri, body)
         
     | 
| 
      
 101 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 102 
     | 
    
         
            +
            #
         
     | 
| 
      
 103 
     | 
    
         
            +
            # === Accessing via SSL
         
     | 
| 
      
 104 
     | 
    
         
            +
            #
         
     | 
| 
      
 105 
     | 
    
         
            +
            # Ruby needs to be compiled with OpenSSL.
         
     | 
| 
      
 106 
     | 
    
         
            +
            #
         
     | 
| 
      
 107 
     | 
    
         
            +
            # 1. Get content of specified URL via SSL.
         
     | 
| 
      
 108 
     | 
    
         
            +
            #    Just pass an URL which starts with 'https://'.
         
     | 
| 
      
 109 
     | 
    
         
            +
            #
         
     | 
| 
      
 110 
     | 
    
         
            +
            #     https_url = 'https://www.rsa.com'
         
     | 
| 
      
 111 
     | 
    
         
            +
            #     clnt.get_content(https_url)
         
     | 
| 
      
 112 
     | 
    
         
            +
            #
         
     | 
| 
      
 113 
     | 
    
         
            +
            # 2. Getting peer certificate from response.
         
     | 
| 
      
 114 
     | 
    
         
            +
            #
         
     | 
| 
      
 115 
     | 
    
         
            +
            #     res = clnt.get(https_url)
         
     | 
| 
      
 116 
     | 
    
         
            +
            #     p res.peer_cert #=> returns OpenSSL::X509::Certificate
         
     | 
| 
      
 117 
     | 
    
         
            +
            #
         
     | 
| 
      
 118 
     | 
    
         
            +
            # 3. Configuring OpenSSL options.  See HTTPClient::SSLConfig for more details.
         
     | 
| 
      
 119 
     | 
    
         
            +
            #
         
     | 
| 
      
 120 
     | 
    
         
            +
            #     user_cert_file = 'cert.pem'
         
     | 
| 
      
 121 
     | 
    
         
            +
            #     user_key_file = 'privkey.pem'
         
     | 
| 
      
 122 
     | 
    
         
            +
            #     clnt.ssl_config.set_client_cert_file(user_cert_file, user_key_file)
         
     | 
| 
      
 123 
     | 
    
         
            +
            #     clnt.get_content(https_url)
         
     | 
| 
      
 124 
     | 
    
         
            +
            #
         
     | 
| 
      
 125 
     | 
    
         
            +
            # === Handling Cookies
         
     | 
| 
      
 126 
     | 
    
         
            +
            #
         
     | 
| 
      
 127 
     | 
    
         
            +
            # 1. Using volatile Cookies.  Nothing to do.  HTTPClient handles Cookies.
         
     | 
| 
      
 128 
     | 
    
         
            +
            #
         
     | 
| 
      
 129 
     | 
    
         
            +
            #     clnt = HTTPClient.new
         
     | 
| 
      
 130 
     | 
    
         
            +
            #     clnt.get_content(url1) # receives Cookies.
         
     | 
| 
      
 131 
     | 
    
         
            +
            #     clnt.get_content(url2) # sends Cookies if needed.
         
     | 
| 
      
 132 
     | 
    
         
            +
            #
         
     | 
| 
      
 133 
     | 
    
         
            +
            # 2. Saving non volatile Cookies to a specified file.  Need to set a file at
         
     | 
| 
      
 134 
     | 
    
         
            +
            #    first and invoke save method at last.
         
     | 
| 
      
 135 
     | 
    
         
            +
            #
         
     | 
| 
      
 136 
     | 
    
         
            +
            #     clnt = HTTPClient.new
         
     | 
| 
      
 137 
     | 
    
         
            +
            #     clnt.set_cookie_store('/home/nahi/cookie.dat')
         
     | 
| 
      
 138 
     | 
    
         
            +
            #     clnt.get_content(url)
         
     | 
| 
      
 139 
     | 
    
         
            +
            #     ...
         
     | 
| 
      
 140 
     | 
    
         
            +
            #     clnt.save_cookie_store
         
     | 
| 
      
 141 
     | 
    
         
            +
            #
         
     | 
| 
      
 142 
     | 
    
         
            +
            # 3. Disabling Cookies.
         
     | 
| 
      
 143 
     | 
    
         
            +
            #
         
     | 
| 
      
 144 
     | 
    
         
            +
            #     clnt = HTTPClient.new
         
     | 
| 
      
 145 
     | 
    
         
            +
            #     clnt.cookie_manager = nil
         
     | 
| 
      
 146 
     | 
    
         
            +
            #
         
     | 
| 
      
 147 
     | 
    
         
            +
            # === Configuring authentication credentials
         
     | 
| 
      
 148 
     | 
    
         
            +
            #
         
     | 
| 
      
 149 
     | 
    
         
            +
            # 1. Authentication with Web server.  Supports BasicAuth, DigestAuth, and
         
     | 
| 
      
 150 
     | 
    
         
            +
            #    Negotiate/NTLM (requires ruby/ntlm module).
         
     | 
| 
      
 151 
     | 
    
         
            +
            #
         
     | 
| 
      
 152 
     | 
    
         
            +
            #     clnt = HTTPClient.new
         
     | 
| 
      
 153 
     | 
    
         
            +
            #     domain = 'http://dev.ctor.org/http-access2/'
         
     | 
| 
      
 154 
     | 
    
         
            +
            #     user = 'user'
         
     | 
| 
      
 155 
     | 
    
         
            +
            #     password = 'user'
         
     | 
| 
      
 156 
     | 
    
         
            +
            #     clnt.set_auth(domain, user, password)
         
     | 
| 
      
 157 
     | 
    
         
            +
            #     p clnt.get_content('http://dev.ctor.org/http-access2/login').status
         
     | 
| 
      
 158 
     | 
    
         
            +
            #
         
     | 
| 
      
 159 
     | 
    
         
            +
            # 2. Authentication with Proxy server.  Supports BasicAuth and NTLM
         
     | 
| 
      
 160 
     | 
    
         
            +
            #    (requires win32/sspi)
         
     | 
| 
      
 161 
     | 
    
         
            +
            #
         
     | 
| 
      
 162 
     | 
    
         
            +
            #     clnt = HTTPClient.new(proxy)
         
     | 
| 
      
 163 
     | 
    
         
            +
            #     user = 'proxy'
         
     | 
| 
      
 164 
     | 
    
         
            +
            #     password = 'proxy'
         
     | 
| 
      
 165 
     | 
    
         
            +
            #     clnt.set_proxy_auth(user, password)
         
     | 
| 
      
 166 
     | 
    
         
            +
            #     p clnt.get_content(url)
         
     | 
| 
      
 167 
     | 
    
         
            +
            #
         
     | 
| 
      
 168 
     | 
    
         
            +
            # === Invoking HTTP methods with custom header
         
     | 
| 
      
 169 
     | 
    
         
            +
            #
         
     | 
| 
      
 170 
     | 
    
         
            +
            # Pass a Hash or an Array for extheader argument.
         
     | 
| 
      
 171 
     | 
    
         
            +
            #
         
     | 
| 
      
 172 
     | 
    
         
            +
            #     extheader = { 'Accept' => '*/*' }
         
     | 
| 
      
 173 
     | 
    
         
            +
            #     clnt.get_content(uri, query, extheader)
         
     | 
| 
      
 174 
     | 
    
         
            +
            #
         
     | 
| 
      
 175 
     | 
    
         
            +
            #     extheader = [['Accept', 'image/jpeg'], ['Accept', 'image/png']]
         
     | 
| 
      
 176 
     | 
    
         
            +
            #     clnt.get_content(uri, query, extheader)
         
     | 
| 
      
 177 
     | 
    
         
            +
            #
         
     | 
| 
      
 178 
     | 
    
         
            +
            # === Invoking HTTP methods asynchronously
         
     | 
| 
      
 179 
     | 
    
         
            +
            #
         
     | 
| 
      
 180 
     | 
    
         
            +
            # See head_async, get_async, post_async, put_async, delete_async,
         
     | 
| 
      
 181 
     | 
    
         
            +
            # options_async, propfind_async, proppatch_async, and trace_async.
         
     | 
| 
      
 182 
     | 
    
         
            +
            # It immediately returns a HTTPClient::Connection instance as a returning value.
         
     | 
| 
      
 183 
     | 
    
         
            +
            #
         
     | 
| 
      
 184 
     | 
    
         
            +
            #     connection = clnt.post_async(url, body)
         
     | 
| 
      
 185 
     | 
    
         
            +
            #     print 'posting.'
         
     | 
| 
      
 186 
     | 
    
         
            +
            #     while true
         
     | 
| 
      
 187 
     | 
    
         
            +
            #       break if connection.finished?
         
     | 
| 
      
 188 
     | 
    
         
            +
            #       print '.'
         
     | 
| 
      
 189 
     | 
    
         
            +
            #       sleep 1
         
     | 
| 
      
 190 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 191 
     | 
    
         
            +
            #     puts '.'
         
     | 
| 
      
 192 
     | 
    
         
            +
            #     res = connection.pop
         
     | 
| 
      
 193 
     | 
    
         
            +
            #     p res.status
         
     | 
| 
      
 194 
     | 
    
         
            +
            #     p res.content.read # res.content is an IO for the res of async method.
         
     | 
| 
      
 195 
     | 
    
         
            +
            #
         
     | 
| 
      
 196 
     | 
    
         
            +
            # === Shortcut methods
         
     | 
| 
      
 197 
     | 
    
         
            +
            #
         
     | 
| 
      
 198 
     | 
    
         
            +
            # You can invoke get_content, get, etc. without creating HTTPClient instance.
         
     | 
| 
      
 199 
     | 
    
         
            +
            #
         
     | 
| 
      
 200 
     | 
    
         
            +
            #   ruby -rhttpclient -e 'puts HTTPClient.get_content(ARGV.shift)' http://dev.ctor.org/
         
     | 
| 
      
 201 
     | 
    
         
            +
            #   ruby -rhttpclient -e 'p HTTPClient.head(ARGV.shift).header["last-modified"]' http://dev.ctor.org/
         
     | 
| 
      
 202 
     | 
    
         
            +
            #
         
     | 
| 
      
 203 
     | 
    
         
            +
            class HTTPClient
         
     | 
| 
      
 204 
     | 
    
         
            +
              VERSION = '2.1.5'
         
     | 
| 
      
 205 
     | 
    
         
            +
              RUBY_VERSION_STRING = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
         
     | 
| 
      
 206 
     | 
    
         
            +
              /: (\S+) (\S+)/ =~ %q$Id: httpclient.rb 280 2009-06-02 15:44:28Z nahi $
         
     | 
| 
      
 207 
     | 
    
         
            +
              LIB_NAME = "(#{$1}/#{$2}, #{RUBY_VERSION_STRING})"
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
              include Util
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
              # Raised for indicating running environment configuration error for example
         
     | 
| 
      
 212 
     | 
    
         
            +
              # accessing via SSL under the ruby which is not compiled with OpenSSL.
         
     | 
| 
      
 213 
     | 
    
         
            +
              class ConfigurationError < StandardError
         
     | 
| 
      
 214 
     | 
    
         
            +
              end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
              # Raised for indicating HTTP response error.
         
     | 
| 
      
 217 
     | 
    
         
            +
              class BadResponseError < RuntimeError
         
     | 
| 
      
 218 
     | 
    
         
            +
                # HTTP::Message:: a response
         
     | 
| 
      
 219 
     | 
    
         
            +
                attr_reader :res
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                def initialize(msg, res = nil) # :nodoc:
         
     | 
| 
      
 222 
     | 
    
         
            +
                  super(msg)
         
     | 
| 
      
 223 
     | 
    
         
            +
                  @res = res
         
     | 
| 
      
 224 
     | 
    
         
            +
                end
         
     | 
| 
      
 225 
     | 
    
         
            +
              end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
              # Raised for indicating a timeout error.
         
     | 
| 
      
 228 
     | 
    
         
            +
              class TimeoutError < RuntimeError
         
     | 
| 
      
 229 
     | 
    
         
            +
              end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              # Raised for indicating a connection timeout error.
         
     | 
| 
      
 232 
     | 
    
         
            +
              # You can configure connection timeout via HTTPClient#connect_timeout=.
         
     | 
| 
      
 233 
     | 
    
         
            +
              class ConnectTimeoutError < TimeoutError
         
     | 
| 
      
 234 
     | 
    
         
            +
              end
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
              # Raised for indicating a request sending timeout error.
         
     | 
| 
      
 237 
     | 
    
         
            +
              # You can configure request sending timeout via HTTPClient#send_timeout=.
         
     | 
| 
      
 238 
     | 
    
         
            +
              class SendTimeoutError < TimeoutError
         
     | 
| 
      
 239 
     | 
    
         
            +
              end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
              # Raised for indicating a response receiving timeout error.
         
     | 
| 
      
 242 
     | 
    
         
            +
              # You can configure response receiving timeout via
         
     | 
| 
      
 243 
     | 
    
         
            +
              # HTTPClient#receive_timeout=.
         
     | 
| 
      
 244 
     | 
    
         
            +
              class ReceiveTimeoutError < TimeoutError
         
     | 
| 
      
 245 
     | 
    
         
            +
              end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
              # Deprecated.  just for backward compatibility
         
     | 
| 
      
 248 
     | 
    
         
            +
              class Session
         
     | 
| 
      
 249 
     | 
    
         
            +
                BadResponse = ::HTTPClient::BadResponseError
         
     | 
| 
      
 250 
     | 
    
         
            +
              end
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 253 
     | 
    
         
            +
                %w(get_content post_content head get post put delete options propfind proppatch trace).each do |name|
         
     | 
| 
      
 254 
     | 
    
         
            +
                  eval <<-EOD
         
     | 
| 
      
 255 
     | 
    
         
            +
                    def #{name}(*arg, &block)
         
     | 
| 
      
 256 
     | 
    
         
            +
                      clnt = new
         
     | 
| 
      
 257 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 258 
     | 
    
         
            +
                        clnt.#{name}(*arg, &block)
         
     | 
| 
      
 259 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 260 
     | 
    
         
            +
                        clnt.reset_all
         
     | 
| 
      
 261 
     | 
    
         
            +
                      end
         
     | 
| 
      
 262 
     | 
    
         
            +
                    end
         
     | 
| 
      
 263 
     | 
    
         
            +
                  EOD
         
     | 
| 
      
 264 
     | 
    
         
            +
                end
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
              private
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                def attr_proxy(symbol, assignable = false)
         
     | 
| 
      
 269 
     | 
    
         
            +
                  name = symbol.to_s
         
     | 
| 
      
 270 
     | 
    
         
            +
                  define_method(name) {
         
     | 
| 
      
 271 
     | 
    
         
            +
                    @session_manager.__send__(name)
         
     | 
| 
      
 272 
     | 
    
         
            +
                  }
         
     | 
| 
      
 273 
     | 
    
         
            +
                  if assignable
         
     | 
| 
      
 274 
     | 
    
         
            +
                    aname = name + '='
         
     | 
| 
      
 275 
     | 
    
         
            +
                    define_method(aname) { |rhs|
         
     | 
| 
      
 276 
     | 
    
         
            +
                      reset_all
         
     | 
| 
      
 277 
     | 
    
         
            +
                      @session_manager.__send__(aname, rhs)
         
     | 
| 
      
 278 
     | 
    
         
            +
                    }
         
     | 
| 
      
 279 
     | 
    
         
            +
                  end
         
     | 
| 
      
 280 
     | 
    
         
            +
                end
         
     | 
| 
      
 281 
     | 
    
         
            +
              end
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
              # HTTPClient::SSLConfig:: SSL configurator.
         
     | 
| 
      
 284 
     | 
    
         
            +
              attr_reader :ssl_config
         
     | 
| 
      
 285 
     | 
    
         
            +
              # WebAgent::CookieManager:: Cookies configurator.
         
     | 
| 
      
 286 
     | 
    
         
            +
              attr_accessor :cookie_manager
         
     | 
| 
      
 287 
     | 
    
         
            +
              # An array of response HTTP message body String which is used for loop-back
         
     | 
| 
      
 288 
     | 
    
         
            +
              # test.  See test/* to see how to use it.  If you want to do loop-back test
         
     | 
| 
      
 289 
     | 
    
         
            +
              # of HTTP header, use test_loopback_http_response instead.
         
     | 
| 
      
 290 
     | 
    
         
            +
              attr_reader :test_loopback_response
         
     | 
| 
      
 291 
     | 
    
         
            +
              # An array of request filter which can trap HTTP request/response.
         
     | 
| 
      
 292 
     | 
    
         
            +
              # See HTTPClient::WWWAuth to see how to use it.
         
     | 
| 
      
 293 
     | 
    
         
            +
              attr_reader :request_filter
         
     | 
| 
      
 294 
     | 
    
         
            +
              # HTTPClient::ProxyAuth:: Proxy authentication handler.
         
     | 
| 
      
 295 
     | 
    
         
            +
              attr_reader :proxy_auth
         
     | 
| 
      
 296 
     | 
    
         
            +
              # HTTPClient::WWWAuth:: WWW authentication handler.
         
     | 
| 
      
 297 
     | 
    
         
            +
              attr_reader :www_auth
         
     | 
| 
      
 298 
     | 
    
         
            +
              # How many times get_content and post_content follows HTTP redirect.
         
     | 
| 
      
 299 
     | 
    
         
            +
              # 10 by default.
         
     | 
| 
      
 300 
     | 
    
         
            +
              attr_accessor :follow_redirect_count
         
     | 
| 
      
 301 
     | 
    
         
            +
              # A Timer object containing response times
         
     | 
| 
      
 302 
     | 
    
         
            +
              attr_reader :timer
         
     | 
| 
      
 303 
     | 
    
         
            +
              
         
     | 
| 
      
 304 
     | 
    
         
            +
              # Set HTTP version as a String:: 'HTTP/1.0' or 'HTTP/1.1'
         
     | 
| 
      
 305 
     | 
    
         
            +
              attr_proxy(:protocol_version, true)
         
     | 
| 
      
 306 
     | 
    
         
            +
              # Connect timeout in sec.
         
     | 
| 
      
 307 
     | 
    
         
            +
              attr_proxy(:connect_timeout, true)
         
     | 
| 
      
 308 
     | 
    
         
            +
              # Request sending timeout in sec.
         
     | 
| 
      
 309 
     | 
    
         
            +
              attr_proxy(:send_timeout, true)
         
     | 
| 
      
 310 
     | 
    
         
            +
              # Response receiving timeout in sec.
         
     | 
| 
      
 311 
     | 
    
         
            +
              attr_proxy(:receive_timeout, true)
         
     | 
| 
      
 312 
     | 
    
         
            +
              # Negotiation retry count for authentication.  5 by default.
         
     | 
| 
      
 313 
     | 
    
         
            +
              attr_proxy(:protocol_retry_count, true)
         
     | 
| 
      
 314 
     | 
    
         
            +
              # if your ruby is older than 2005-09-06, do not set socket_sync = false to
         
     | 
| 
      
 315 
     | 
    
         
            +
              # avoid an SSL socket blocking bug in openssl/buffering.rb.
         
     | 
| 
      
 316 
     | 
    
         
            +
              attr_proxy(:socket_sync, true)
         
     | 
| 
      
 317 
     | 
    
         
            +
              # User-Agent header in HTTP request.
         
     | 
| 
      
 318 
     | 
    
         
            +
              attr_proxy(:agent_name, true)
         
     | 
| 
      
 319 
     | 
    
         
            +
              # From header in HTTP request.
         
     | 
| 
      
 320 
     | 
    
         
            +
              attr_proxy(:from, true)
         
     | 
| 
      
 321 
     | 
    
         
            +
              # An array of response HTTP String (not a HTTP message body) which is used
         
     | 
| 
      
 322 
     | 
    
         
            +
              # for loopback test.  See test/* to see how to use it.
         
     | 
| 
      
 323 
     | 
    
         
            +
              attr_proxy(:test_loopback_http_response)
         
     | 
| 
      
 324 
     | 
    
         
            +
             
     | 
| 
      
 325 
     | 
    
         
            +
              # Default extheader for PROPFIND request.
         
     | 
| 
      
 326 
     | 
    
         
            +
              PROPFIND_DEFAULT_EXTHEADER = { 'Depth' => '0' }
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
              # Creates a HTTPClient instance which manages sessions, cookies, etc.
         
     | 
| 
      
 329 
     | 
    
         
            +
              #
         
     | 
| 
      
 330 
     | 
    
         
            +
              # HTTPClient.new takes 3 optional arguments for proxy url string,
         
     | 
| 
      
 331 
     | 
    
         
            +
              # User-Agent String and From header String.  User-Agent and From are embedded
         
     | 
| 
      
 332 
     | 
    
         
            +
              # in HTTP request Header if given.  No User-Agent and From header added
         
     | 
| 
      
 333 
     | 
    
         
            +
              # without setting it explicitly.
         
     | 
| 
      
 334 
     | 
    
         
            +
              #
         
     | 
| 
      
 335 
     | 
    
         
            +
              #   proxy = 'http://myproxy:8080'
         
     | 
| 
      
 336 
     | 
    
         
            +
              #   agent_name = 'MyAgent/0.1'
         
     | 
| 
      
 337 
     | 
    
         
            +
              #   from = 'from@example.com'
         
     | 
| 
      
 338 
     | 
    
         
            +
              #   HTTPClient.new(proxy, agent_name, from)
         
     | 
| 
      
 339 
     | 
    
         
            +
              #
         
     | 
| 
      
 340 
     | 
    
         
            +
              # You can use a keyword argument style Hash.  Keys are :proxy, :agent_name
         
     | 
| 
      
 341 
     | 
    
         
            +
              # and :from.
         
     | 
| 
      
 342 
     | 
    
         
            +
              #
         
     | 
| 
      
 343 
     | 
    
         
            +
              #   HTTPClient.new(:agent_name = 'MyAgent/0.1')
         
     | 
| 
      
 344 
     | 
    
         
            +
              def initialize(*args)
         
     | 
| 
      
 345 
     | 
    
         
            +
                proxy, agent_name, from = keyword_argument(args, :proxy, :agent_name, :from)
         
     | 
| 
      
 346 
     | 
    
         
            +
                @proxy = nil        # assigned later.
         
     | 
| 
      
 347 
     | 
    
         
            +
                @no_proxy = nil
         
     | 
| 
      
 348 
     | 
    
         
            +
                @www_auth = WWWAuth.new
         
     | 
| 
      
 349 
     | 
    
         
            +
                @proxy_auth = ProxyAuth.new
         
     | 
| 
      
 350 
     | 
    
         
            +
                @request_filter = [@proxy_auth, @www_auth]
         
     | 
| 
      
 351 
     | 
    
         
            +
                @debug_dev = nil
         
     | 
| 
      
 352 
     | 
    
         
            +
                @redirect_uri_callback = method(:default_redirect_uri_callback)
         
     | 
| 
      
 353 
     | 
    
         
            +
                @test_loopback_response = []
         
     | 
| 
      
 354 
     | 
    
         
            +
                @session_manager = SessionManager.new(self)
         
     | 
| 
      
 355 
     | 
    
         
            +
                @session_manager.agent_name = agent_name
         
     | 
| 
      
 356 
     | 
    
         
            +
                @session_manager.from = from
         
     | 
| 
      
 357 
     | 
    
         
            +
                @session_manager.ssl_config = @ssl_config = SSLConfig.new(self)
         
     | 
| 
      
 358 
     | 
    
         
            +
                @cookie_manager = WebAgent::CookieManager.new
         
     | 
| 
      
 359 
     | 
    
         
            +
                @follow_redirect_count = 10
         
     | 
| 
      
 360 
     | 
    
         
            +
                @timer = Timer.new
         
     | 
| 
      
 361 
     | 
    
         
            +
                load_environment
         
     | 
| 
      
 362 
     | 
    
         
            +
                self.proxy = proxy if proxy
         
     | 
| 
      
 363 
     | 
    
         
            +
              end
         
     | 
| 
      
 364 
     | 
    
         
            +
             
     | 
| 
      
 365 
     | 
    
         
            +
              # Returns debug device if exists.  See debug_dev=.
         
     | 
| 
      
 366 
     | 
    
         
            +
              def debug_dev
         
     | 
| 
      
 367 
     | 
    
         
            +
                @debug_dev
         
     | 
| 
      
 368 
     | 
    
         
            +
              end
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
              # Sets debug device.  Once debug device is set, all HTTP requests and
         
     | 
| 
      
 371 
     | 
    
         
            +
              # responses are dumped to given device.  dev must respond to << for dump.
         
     | 
| 
      
 372 
     | 
    
         
            +
              #
         
     | 
| 
      
 373 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 374 
     | 
    
         
            +
              def debug_dev=(dev)
         
     | 
| 
      
 375 
     | 
    
         
            +
                @debug_dev = dev
         
     | 
| 
      
 376 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 377 
     | 
    
         
            +
                @session_manager.debug_dev = dev
         
     | 
| 
      
 378 
     | 
    
         
            +
              end
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
              # Returns URI object of HTTP proxy if exists.
         
     | 
| 
      
 381 
     | 
    
         
            +
              def proxy
         
     | 
| 
      
 382 
     | 
    
         
            +
                @proxy
         
     | 
| 
      
 383 
     | 
    
         
            +
              end
         
     | 
| 
      
 384 
     | 
    
         
            +
             
     | 
| 
      
 385 
     | 
    
         
            +
              # Sets HTTP proxy used for HTTP connection.  Given proxy can be an URI,
         
     | 
| 
      
 386 
     | 
    
         
            +
              # a String or nil.  You can set user/password for proxy authentication like
         
     | 
| 
      
 387 
     | 
    
         
            +
              # HTTPClient#proxy = 'http://user:passwd@myproxy:8080'
         
     | 
| 
      
 388 
     | 
    
         
            +
              #
         
     | 
| 
      
 389 
     | 
    
         
            +
              # You can use environment variable 'http_proxy' or 'HTTP_PROXY' for it.
         
     | 
| 
      
 390 
     | 
    
         
            +
              # You need to use 'cgi_http_proxy' or 'CGI_HTTP_PROXY' instead if you run
         
     | 
| 
      
 391 
     | 
    
         
            +
              # HTTPClient from CGI environment from security reason. (HTTPClient checks
         
     | 
| 
      
 392 
     | 
    
         
            +
              # 'REQUEST_METHOD' environment variable whether it's CGI or not)
         
     | 
| 
      
 393 
     | 
    
         
            +
              #
         
     | 
| 
      
 394 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 395 
     | 
    
         
            +
              def proxy=(proxy)
         
     | 
| 
      
 396 
     | 
    
         
            +
                if proxy.nil?
         
     | 
| 
      
 397 
     | 
    
         
            +
                  @proxy = nil
         
     | 
| 
      
 398 
     | 
    
         
            +
                  @proxy_auth.reset_challenge
         
     | 
| 
      
 399 
     | 
    
         
            +
                else
         
     | 
| 
      
 400 
     | 
    
         
            +
                  @proxy = urify(proxy)
         
     | 
| 
      
 401 
     | 
    
         
            +
                  if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
         
     | 
| 
      
 402 
     | 
    
         
            +
                      @proxy.host == nil or @proxy.port == nil
         
     | 
| 
      
 403 
     | 
    
         
            +
                    raise ArgumentError.new("unsupported proxy #{proxy}")
         
     | 
| 
      
 404 
     | 
    
         
            +
                  end
         
     | 
| 
      
 405 
     | 
    
         
            +
                  @proxy_auth.reset_challenge
         
     | 
| 
      
 406 
     | 
    
         
            +
                  if @proxy.user || @proxy.password
         
     | 
| 
      
 407 
     | 
    
         
            +
                    @proxy_auth.set_auth(@proxy.user, @proxy.password)
         
     | 
| 
      
 408 
     | 
    
         
            +
                  end
         
     | 
| 
      
 409 
     | 
    
         
            +
                end
         
     | 
| 
      
 410 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 411 
     | 
    
         
            +
                @session_manager.proxy = @proxy
         
     | 
| 
      
 412 
     | 
    
         
            +
                @proxy
         
     | 
| 
      
 413 
     | 
    
         
            +
              end
         
     | 
| 
      
 414 
     | 
    
         
            +
             
     | 
| 
      
 415 
     | 
    
         
            +
              # Returns NO_PROXY setting String if given.
         
     | 
| 
      
 416 
     | 
    
         
            +
              def no_proxy
         
     | 
| 
      
 417 
     | 
    
         
            +
                @no_proxy
         
     | 
| 
      
 418 
     | 
    
         
            +
              end
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
              # Sets NO_PROXY setting String.  no_proxy must be a comma separated String.
         
     | 
| 
      
 421 
     | 
    
         
            +
              # Each entry must be 'host' or 'host:port' such as;
         
     | 
| 
      
 422 
     | 
    
         
            +
              # HTTPClient#no_proxy = 'example.com,example.co.jp:443'
         
     | 
| 
      
 423 
     | 
    
         
            +
              #
         
     | 
| 
      
 424 
     | 
    
         
            +
              # 'localhost' is treated as a no_proxy site regardless of explicitly listed.
         
     | 
| 
      
 425 
     | 
    
         
            +
              # HTTPClient checks given URI objects before accessing it.
         
     | 
| 
      
 426 
     | 
    
         
            +
              # 'host' is tail string match.  No IP-addr conversion.
         
     | 
| 
      
 427 
     | 
    
         
            +
              #
         
     | 
| 
      
 428 
     | 
    
         
            +
              # You can use environment variable 'no_proxy' or 'NO_PROXY' for it.
         
     | 
| 
      
 429 
     | 
    
         
            +
              #
         
     | 
| 
      
 430 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 431 
     | 
    
         
            +
              def no_proxy=(no_proxy)
         
     | 
| 
      
 432 
     | 
    
         
            +
                @no_proxy = no_proxy
         
     | 
| 
      
 433 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 434 
     | 
    
         
            +
              end
         
     | 
| 
      
 435 
     | 
    
         
            +
             
     | 
| 
      
 436 
     | 
    
         
            +
              # Sets credential for Web server authentication.
         
     | 
| 
      
 437 
     | 
    
         
            +
              # domain:: a String or an URI to specify where HTTPClient should use this
         
     | 
| 
      
 438 
     | 
    
         
            +
              #       credential.  If you set uri to nil, HTTPClient uses this credential
         
     | 
| 
      
 439 
     | 
    
         
            +
              #       wherever a server requires it.
         
     | 
| 
      
 440 
     | 
    
         
            +
              # user:: username String.
         
     | 
| 
      
 441 
     | 
    
         
            +
              # passwd:: password String.
         
     | 
| 
      
 442 
     | 
    
         
            +
              #
         
     | 
| 
      
 443 
     | 
    
         
            +
              # You can set multiple credentials for each uri.
         
     | 
| 
      
 444 
     | 
    
         
            +
              #
         
     | 
| 
      
 445 
     | 
    
         
            +
              #   clnt.set_auth('http://www.example.com/foo/', 'foo_user', 'passwd')
         
     | 
| 
      
 446 
     | 
    
         
            +
              #   clnt.set_auth('http://www.example.com/bar/', 'bar_user', 'passwd')
         
     | 
| 
      
 447 
     | 
    
         
            +
              #
         
     | 
| 
      
 448 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 449 
     | 
    
         
            +
              def set_auth(domain, user, passwd)
         
     | 
| 
      
 450 
     | 
    
         
            +
                uri = urify(domain)
         
     | 
| 
      
 451 
     | 
    
         
            +
                @www_auth.set_auth(uri, user, passwd)
         
     | 
| 
      
 452 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 453 
     | 
    
         
            +
              end
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
              # Deprecated.  Use set_auth instead.
         
     | 
| 
      
 456 
     | 
    
         
            +
              def set_basic_auth(domain, user, passwd)
         
     | 
| 
      
 457 
     | 
    
         
            +
                uri = urify(domain)
         
     | 
| 
      
 458 
     | 
    
         
            +
                @www_auth.basic_auth.set(uri, user, passwd)
         
     | 
| 
      
 459 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 460 
     | 
    
         
            +
              end
         
     | 
| 
      
 461 
     | 
    
         
            +
             
     | 
| 
      
 462 
     | 
    
         
            +
              # Sets credential for Proxy authentication.
         
     | 
| 
      
 463 
     | 
    
         
            +
              # user:: username String.
         
     | 
| 
      
 464 
     | 
    
         
            +
              # passwd:: password String.
         
     | 
| 
      
 465 
     | 
    
         
            +
              #
         
     | 
| 
      
 466 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 467 
     | 
    
         
            +
              def set_proxy_auth(user, passwd)
         
     | 
| 
      
 468 
     | 
    
         
            +
                @proxy_auth.set_auth(user, passwd)
         
     | 
| 
      
 469 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 470 
     | 
    
         
            +
              end
         
     | 
| 
      
 471 
     | 
    
         
            +
             
     | 
| 
      
 472 
     | 
    
         
            +
              # Sets the filename where non-volatile Cookies be saved by calling
         
     | 
| 
      
 473 
     | 
    
         
            +
              # save_cookie_store.
         
     | 
| 
      
 474 
     | 
    
         
            +
              # This method tries to load and managing Cookies from the specified file.
         
     | 
| 
      
 475 
     | 
    
         
            +
              #
         
     | 
| 
      
 476 
     | 
    
         
            +
              # Calling this method resets all existing sessions.
         
     | 
| 
      
 477 
     | 
    
         
            +
              def set_cookie_store(filename)
         
     | 
| 
      
 478 
     | 
    
         
            +
                @cookie_manager.cookies_file = filename
         
     | 
| 
      
 479 
     | 
    
         
            +
                @cookie_manager.load_cookies if filename
         
     | 
| 
      
 480 
     | 
    
         
            +
                reset_all
         
     | 
| 
      
 481 
     | 
    
         
            +
              end
         
     | 
| 
      
 482 
     | 
    
         
            +
             
     | 
| 
      
 483 
     | 
    
         
            +
              # Try to save Cookies to the file specified in set_cookie_store.  Unexpected
         
     | 
| 
      
 484 
     | 
    
         
            +
              # error will be raised if you don't call set_cookie_store first.
         
     | 
| 
      
 485 
     | 
    
         
            +
              # (interface mismatch between WebAgent::CookieManager implementation)
         
     | 
| 
      
 486 
     | 
    
         
            +
              def save_cookie_store
         
     | 
| 
      
 487 
     | 
    
         
            +
                @cookie_manager.save_cookies
         
     | 
| 
      
 488 
     | 
    
         
            +
              end
         
     | 
| 
      
 489 
     | 
    
         
            +
             
     | 
| 
      
 490 
     | 
    
         
            +
              # Sets callback proc when HTTP redirect status is returned for get_content
         
     | 
| 
      
 491 
     | 
    
         
            +
              # and post_content.  default_redirect_uri_callback is used by default.
         
     | 
| 
      
 492 
     | 
    
         
            +
              #
         
     | 
| 
      
 493 
     | 
    
         
            +
              # If you need strict implementation which does not allow relative URI
         
     | 
| 
      
 494 
     | 
    
         
            +
              # redirection, set strict_redirect_uri_callback instead.
         
     | 
| 
      
 495 
     | 
    
         
            +
              #
         
     | 
| 
      
 496 
     | 
    
         
            +
              #   clnt.redirect_uri_callback = clnt.method(:strict_redirect_uri_callback)
         
     | 
| 
      
 497 
     | 
    
         
            +
              #
         
     | 
| 
      
 498 
     | 
    
         
            +
              def redirect_uri_callback=(redirect_uri_callback)
         
     | 
| 
      
 499 
     | 
    
         
            +
                @redirect_uri_callback = redirect_uri_callback
         
     | 
| 
      
 500 
     | 
    
         
            +
              end
         
     | 
| 
      
 501 
     | 
    
         
            +
             
     | 
| 
      
 502 
     | 
    
         
            +
              # Retrieves a web resource.
         
     | 
| 
      
 503 
     | 
    
         
            +
              #
         
     | 
| 
      
 504 
     | 
    
         
            +
              # uri:: a String or an URI object which represents an URL of web resource.
         
     | 
| 
      
 505 
     | 
    
         
            +
              # query:: a Hash or an Array of query part of URL.
         
     | 
| 
      
 506 
     | 
    
         
            +
              #         e.g. { "a" => "b" } => 'http://host/part?a=b'.
         
     | 
| 
      
 507 
     | 
    
         
            +
              #         Give an array to pass multiple value like
         
     | 
| 
      
 508 
     | 
    
         
            +
              #         [["a", "b"], ["a", "c"]] => 'http://host/part?a=b&a=c'.
         
     | 
| 
      
 509 
     | 
    
         
            +
              # extheader:: a Hash or an Array of extra headers.  e.g.
         
     | 
| 
      
 510 
     | 
    
         
            +
              #             { 'Accept' => '*/*' } or
         
     | 
| 
      
 511 
     | 
    
         
            +
              #             [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
         
     | 
| 
      
 512 
     | 
    
         
            +
              # &block:: Give a block to get chunked message-body of response like
         
     | 
| 
      
 513 
     | 
    
         
            +
              #          get_content(uri) { |chunked_body| ... }.
         
     | 
| 
      
 514 
     | 
    
         
            +
              #          Size of each chunk may not be the same.
         
     | 
| 
      
 515 
     | 
    
         
            +
              #
         
     | 
| 
      
 516 
     | 
    
         
            +
              # get_content follows HTTP redirect status (see HTTP::Status.redirect?)
         
     | 
| 
      
 517 
     | 
    
         
            +
              # internally and try to retrieve content from redirected URL.  See
         
     | 
| 
      
 518 
     | 
    
         
            +
              # redirect_uri_callback= how HTTP redirection is handled.
         
     | 
| 
      
 519 
     | 
    
         
            +
              #
         
     | 
| 
      
 520 
     | 
    
         
            +
              # If you need to get full HTTP response including HTTP status and headers,
         
     | 
| 
      
 521 
     | 
    
         
            +
              # use get method.  get returns HTTP::Message as a response and you need to
         
     | 
| 
      
 522 
     | 
    
         
            +
              # follow HTTP redirect by yourself if you need.
         
     | 
| 
      
 523 
     | 
    
         
            +
              def get_content(uri, query = nil, extheader = {}, &block)
         
     | 
| 
      
 524 
     | 
    
         
            +
                follow_redirect(:get, uri, query, nil, extheader, &block).content
         
     | 
| 
      
 525 
     | 
    
         
            +
              end
         
     | 
| 
      
 526 
     | 
    
         
            +
             
     | 
| 
      
 527 
     | 
    
         
            +
              # Posts a content.
         
     | 
| 
      
 528 
     | 
    
         
            +
              #
         
     | 
| 
      
 529 
     | 
    
         
            +
              # uri:: a String or an URI object which represents an URL of web resource.
         
     | 
| 
      
 530 
     | 
    
         
            +
              # body:: a Hash or an Array of body part.
         
     | 
| 
      
 531 
     | 
    
         
            +
              #        e.g. { "a" => "b" } => 'a=b'.
         
     | 
| 
      
 532 
     | 
    
         
            +
              #        Give an array to pass multiple value like
         
     | 
| 
      
 533 
     | 
    
         
            +
              #        [["a", "b"], ["a", "c"]] => 'a=b&a=c'.
         
     | 
| 
      
 534 
     | 
    
         
            +
              #        When you pass a File as a value, it will be posted as a
         
     | 
| 
      
 535 
     | 
    
         
            +
              #        multipart/form-data.  e.g. { 'upload' => file }
         
     | 
| 
      
 536 
     | 
    
         
            +
              # extheader:: a Hash or an Array of extra headers.  e.g.
         
     | 
| 
      
 537 
     | 
    
         
            +
              #             { 'Accept' => '*/*' } or
         
     | 
| 
      
 538 
     | 
    
         
            +
              #             [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
         
     | 
| 
      
 539 
     | 
    
         
            +
              # &block:: Give a block to get chunked message-body of response like
         
     | 
| 
      
 540 
     | 
    
         
            +
              #          post_content(uri) { |chunked_body| ... }.
         
     | 
| 
      
 541 
     | 
    
         
            +
              #          Size of each chunk may not be the same.
         
     | 
| 
      
 542 
     | 
    
         
            +
              #
         
     | 
| 
      
 543 
     | 
    
         
            +
              # post_content follows HTTP redirect status (see HTTP::Status.redirect?)
         
     | 
| 
      
 544 
     | 
    
         
            +
              # internally and try to post the content to redirected URL.  See
         
     | 
| 
      
 545 
     | 
    
         
            +
              # redirect_uri_callback= how HTTP redirection is handled.
         
     | 
| 
      
 546 
     | 
    
         
            +
              #
         
     | 
| 
      
 547 
     | 
    
         
            +
              # If you need to get full HTTP response including HTTP status and headers,
         
     | 
| 
      
 548 
     | 
    
         
            +
              # use post method.
         
     | 
| 
      
 549 
     | 
    
         
            +
              def post_content(uri, body = nil, extheader = {}, &block)
         
     | 
| 
      
 550 
     | 
    
         
            +
                follow_redirect(:post, uri, nil, body, extheader, &block).content
         
     | 
| 
      
 551 
     | 
    
         
            +
              end
         
     | 
| 
      
 552 
     | 
    
         
            +
             
     | 
| 
      
 553 
     | 
    
         
            +
              # A method for redirect uri callback.  How to use:
         
     | 
| 
      
 554 
     | 
    
         
            +
              #   clnt.redirect_uri_callback = clnt.method(:strict_redirect_uri_callback)
         
     | 
| 
      
 555 
     | 
    
         
            +
              # This callback does not allow relative redirect such as
         
     | 
| 
      
 556 
     | 
    
         
            +
              #   Location: ../foo/
         
     | 
| 
      
 557 
     | 
    
         
            +
              # in HTTP header. (raises BadResponseError instead)
         
     | 
| 
      
 558 
     | 
    
         
            +
              def strict_redirect_uri_callback(uri, res)
         
     | 
| 
      
 559 
     | 
    
         
            +
                newuri = URI.parse(res.header['location'][0])
         
     | 
| 
      
 560 
     | 
    
         
            +
                if https?(uri) && !https?(newuri)
         
     | 
| 
      
 561 
     | 
    
         
            +
                  raise BadResponseError.new("redirecting to non-https resource")
         
     | 
| 
      
 562 
     | 
    
         
            +
                end
         
     | 
| 
      
 563 
     | 
    
         
            +
                unless newuri.is_a?(URI::HTTP)
         
     | 
| 
      
 564 
     | 
    
         
            +
                  raise BadResponseError.new("unexpected location: #{newuri}", res)
         
     | 
| 
      
 565 
     | 
    
         
            +
                end
         
     | 
| 
      
 566 
     | 
    
         
            +
                puts "redirect to: #{newuri}" if $DEBUG
         
     | 
| 
      
 567 
     | 
    
         
            +
                newuri
         
     | 
| 
      
 568 
     | 
    
         
            +
              end
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
              # A default method for redirect uri callback.  This method is used by
         
     | 
| 
      
 571 
     | 
    
         
            +
              # HTTPClient instance by default.
         
     | 
| 
      
 572 
     | 
    
         
            +
              # This callback allows relative redirect such as
         
     | 
| 
      
 573 
     | 
    
         
            +
              #   Location: ../foo/
         
     | 
| 
      
 574 
     | 
    
         
            +
              # in HTTP header.
         
     | 
| 
      
 575 
     | 
    
         
            +
              def default_redirect_uri_callback(uri, res)
         
     | 
| 
      
 576 
     | 
    
         
            +
                newuri = URI.parse(res.header['location'][0])
         
     | 
| 
      
 577 
     | 
    
         
            +
                if https?(uri) && !https?(newuri)
         
     | 
| 
      
 578 
     | 
    
         
            +
                  raise BadResponseError.new("redirecting to non-https resource")
         
     | 
| 
      
 579 
     | 
    
         
            +
                end
         
     | 
| 
      
 580 
     | 
    
         
            +
                unless newuri.is_a?(URI::HTTP)
         
     | 
| 
      
 581 
     | 
    
         
            +
                  newuri = uri + newuri
         
     | 
| 
      
 582 
     | 
    
         
            +
                  STDERR.puts("could be a relative URI in location header which is not recommended")
         
     | 
| 
      
 583 
     | 
    
         
            +
                  STDERR.puts("'The field value consists of a single absolute URI' in HTTP spec")
         
     | 
| 
      
 584 
     | 
    
         
            +
                end
         
     | 
| 
      
 585 
     | 
    
         
            +
                puts "redirect to: #{newuri}" if $DEBUG
         
     | 
| 
      
 586 
     | 
    
         
            +
                newuri
         
     | 
| 
      
 587 
     | 
    
         
            +
              end
         
     | 
| 
      
 588 
     | 
    
         
            +
             
     | 
| 
      
 589 
     | 
    
         
            +
              # Sends HEAD request to the specified URL.  See request for arguments.
         
     | 
| 
      
 590 
     | 
    
         
            +
              def head(uri, query = nil, extheader = {})
         
     | 
| 
      
 591 
     | 
    
         
            +
                request(:head, uri, query, nil, extheader)
         
     | 
| 
      
 592 
     | 
    
         
            +
              end
         
     | 
| 
      
 593 
     | 
    
         
            +
             
     | 
| 
      
 594 
     | 
    
         
            +
              # Sends GET request to the specified URL.  See request for arguments.
         
     | 
| 
      
 595 
     | 
    
         
            +
              def get(uri, query = nil, extheader = {}, &block)
         
     | 
| 
      
 596 
     | 
    
         
            +
                request(:get, uri, query, nil, extheader, &block)
         
     | 
| 
      
 597 
     | 
    
         
            +
              end
         
     | 
| 
      
 598 
     | 
    
         
            +
             
     | 
| 
      
 599 
     | 
    
         
            +
              # Sends POST request to the specified URL.  See request for arguments.
         
     | 
| 
      
 600 
     | 
    
         
            +
              def post(uri, body = '', extheader = {}, &block)
         
     | 
| 
      
 601 
     | 
    
         
            +
                request(:post, uri, nil, body, extheader, &block)
         
     | 
| 
      
 602 
     | 
    
         
            +
              end
         
     | 
| 
      
 603 
     | 
    
         
            +
             
     | 
| 
      
 604 
     | 
    
         
            +
              # Sends PUT request to the specified URL.  See request for arguments.
         
     | 
| 
      
 605 
     | 
    
         
            +
              def put(uri, body = '', extheader = {}, &block)
         
     | 
| 
      
 606 
     | 
    
         
            +
                request(:put, uri, nil, body, extheader, &block)
         
     | 
| 
      
 607 
     | 
    
         
            +
              end
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
              # Sends DELETE request to the specified URL.  See request for arguments.
         
     | 
| 
      
 610 
     | 
    
         
            +
              def delete(uri, extheader = {}, &block)
         
     | 
| 
      
 611 
     | 
    
         
            +
                request(:delete, uri, nil, nil, extheader, &block)
         
     | 
| 
      
 612 
     | 
    
         
            +
              end
         
     | 
| 
      
 613 
     | 
    
         
            +
             
     | 
| 
      
 614 
     | 
    
         
            +
              # Sends OPTIONS request to the specified URL.  See request for arguments.
         
     | 
| 
      
 615 
     | 
    
         
            +
              def options(uri, extheader = {}, &block)
         
     | 
| 
      
 616 
     | 
    
         
            +
                request(:options, uri, nil, nil, extheader, &block)
         
     | 
| 
      
 617 
     | 
    
         
            +
              end
         
     | 
| 
      
 618 
     | 
    
         
            +
             
     | 
| 
      
 619 
     | 
    
         
            +
              # Sends PROPFIND request to the specified URL.  See request for arguments.
         
     | 
| 
      
 620 
     | 
    
         
            +
              def propfind(uri, extheader = PROPFIND_DEFAULT_EXTHEADER, &block)
         
     | 
| 
      
 621 
     | 
    
         
            +
                request(:propfind, uri, nil, nil, extheader, &block)
         
     | 
| 
      
 622 
     | 
    
         
            +
              end
         
     | 
| 
      
 623 
     | 
    
         
            +
              
         
     | 
| 
      
 624 
     | 
    
         
            +
              # Sends PROPPATCH request to the specified URL.  See request for arguments.
         
     | 
| 
      
 625 
     | 
    
         
            +
              def proppatch(uri, body = nil, extheader = {}, &block)
         
     | 
| 
      
 626 
     | 
    
         
            +
                request(:proppatch, uri, nil, body, extheader, &block)
         
     | 
| 
      
 627 
     | 
    
         
            +
              end
         
     | 
| 
      
 628 
     | 
    
         
            +
              
         
     | 
| 
      
 629 
     | 
    
         
            +
              # Sends TRACE request to the specified URL.  See request for arguments.
         
     | 
| 
      
 630 
     | 
    
         
            +
              def trace(uri, query = nil, body = nil, extheader = {}, &block)
         
     | 
| 
      
 631 
     | 
    
         
            +
                request('TRACE', uri, query, body, extheader, &block)
         
     | 
| 
      
 632 
     | 
    
         
            +
              end
         
     | 
| 
      
 633 
     | 
    
         
            +
             
     | 
| 
      
 634 
     | 
    
         
            +
              # Sends a request to the specified URL.
         
     | 
| 
      
 635 
     | 
    
         
            +
              #
         
     | 
| 
      
 636 
     | 
    
         
            +
              # method:: HTTP method to be sent.  method.to_s.upcase is used.
         
     | 
| 
      
 637 
     | 
    
         
            +
              # uri:: a String or an URI object which represents an URL of web resource.
         
     | 
| 
      
 638 
     | 
    
         
            +
              # query:: a Hash or an Array of query part of URL.
         
     | 
| 
      
 639 
     | 
    
         
            +
              #         e.g. { "a" => "b" } => 'http://host/part?a=b'
         
     | 
| 
      
 640 
     | 
    
         
            +
              #         Give an array to pass multiple value like
         
     | 
| 
      
 641 
     | 
    
         
            +
              #         [["a", "b"], ["a", "c"]] => 'http://host/part?a=b&a=c'
         
     | 
| 
      
 642 
     | 
    
         
            +
              # body:: a Hash or an Array of body part.
         
     | 
| 
      
 643 
     | 
    
         
            +
              #        e.g. { "a" => "b" } => 'a=b'.
         
     | 
| 
      
 644 
     | 
    
         
            +
              #        Give an array to pass multiple value like
         
     | 
| 
      
 645 
     | 
    
         
            +
              #        [["a", "b"], ["a", "c"]] => 'a=b&a=c'.
         
     | 
| 
      
 646 
     | 
    
         
            +
              #        When the given method is 'POST' and the given body contains a file
         
     | 
| 
      
 647 
     | 
    
         
            +
              #        as a value, it will be posted as a multipart/form-data.
         
     | 
| 
      
 648 
     | 
    
         
            +
              #        e.g. { 'upload' => file }
         
     | 
| 
      
 649 
     | 
    
         
            +
              #        See HTTP::Message.file? for actual condition of 'a file'.
         
     | 
| 
      
 650 
     | 
    
         
            +
              # extheader:: a Hash or an Array of extra headers.  e.g.
         
     | 
| 
      
 651 
     | 
    
         
            +
              #             { 'Accept' => '*/*' } or
         
     | 
| 
      
 652 
     | 
    
         
            +
              #             [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
         
     | 
| 
      
 653 
     | 
    
         
            +
              # &block:: Give a block to get chunked message-body of response like
         
     | 
| 
      
 654 
     | 
    
         
            +
              #          get(uri) { |chunked_body| ... }.
         
     | 
| 
      
 655 
     | 
    
         
            +
              #          Size of each chunk may not be the same.
         
     | 
| 
      
 656 
     | 
    
         
            +
              #
         
     | 
| 
      
 657 
     | 
    
         
            +
              # You can also pass a String as a body.  HTTPClient just sends a String as
         
     | 
| 
      
 658 
     | 
    
         
            +
              # a HTTP request message body.
         
     | 
| 
      
 659 
     | 
    
         
            +
              #
         
     | 
| 
      
 660 
     | 
    
         
            +
              # When you pass an IO as a body, HTTPClient sends it as a HTTP request with
         
     | 
| 
      
 661 
     | 
    
         
            +
              # chunked encoding (Transfer-Encoding: chunked in HTTP header).  Bear in mind
         
     | 
| 
      
 662 
     | 
    
         
            +
              # that some server application does not support chunked request.  At least
         
     | 
| 
      
 663 
     | 
    
         
            +
              # cgi.rb does not support it.
         
     | 
| 
      
 664 
     | 
    
         
            +
              def request(method, uri, query = nil, body = nil, extheader = {}, &block)
         
     | 
| 
      
 665 
     | 
    
         
            +
                uri = urify(uri)
         
     | 
| 
      
 666 
     | 
    
         
            +
                if block
         
     | 
| 
      
 667 
     | 
    
         
            +
                  filtered_block = proc { |res, str|
         
     | 
| 
      
 668 
     | 
    
         
            +
                    block.call(str)
         
     | 
| 
      
 669 
     | 
    
         
            +
                  }
         
     | 
| 
      
 670 
     | 
    
         
            +
                end
         
     | 
| 
      
 671 
     | 
    
         
            +
                do_request(method, uri, query, body, extheader, &filtered_block)
         
     | 
| 
      
 672 
     | 
    
         
            +
              end
         
     | 
| 
      
 673 
     | 
    
         
            +
             
     | 
| 
      
 674 
     | 
    
         
            +
              # Sends HEAD request in async style.  See request_async for arguments.
         
     | 
| 
      
 675 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 676 
     | 
    
         
            +
              def head_async(uri, query = nil, extheader = {})
         
     | 
| 
      
 677 
     | 
    
         
            +
                request_async(:head, uri, query, nil, extheader)
         
     | 
| 
      
 678 
     | 
    
         
            +
              end
         
     | 
| 
      
 679 
     | 
    
         
            +
             
     | 
| 
      
 680 
     | 
    
         
            +
              # Sends GET request in async style.  See request_async for arguments.
         
     | 
| 
      
 681 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 682 
     | 
    
         
            +
              def get_async(uri, query = nil, extheader = {})
         
     | 
| 
      
 683 
     | 
    
         
            +
                request_async(:get, uri, query, nil, extheader)
         
     | 
| 
      
 684 
     | 
    
         
            +
              end
         
     | 
| 
      
 685 
     | 
    
         
            +
             
     | 
| 
      
 686 
     | 
    
         
            +
              # Sends POST request in async style.  See request_async for arguments.
         
     | 
| 
      
 687 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 688 
     | 
    
         
            +
              def post_async(uri, body = nil, extheader = {})
         
     | 
| 
      
 689 
     | 
    
         
            +
                request_async(:post, uri, nil, body, extheader)
         
     | 
| 
      
 690 
     | 
    
         
            +
              end
         
     | 
| 
      
 691 
     | 
    
         
            +
             
     | 
| 
      
 692 
     | 
    
         
            +
              # Sends PUT request in async style.  See request_async for arguments.
         
     | 
| 
      
 693 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 694 
     | 
    
         
            +
              def put_async(uri, body = nil, extheader = {})
         
     | 
| 
      
 695 
     | 
    
         
            +
                request_async(:put, uri, nil, body, extheader)
         
     | 
| 
      
 696 
     | 
    
         
            +
              end
         
     | 
| 
      
 697 
     | 
    
         
            +
             
     | 
| 
      
 698 
     | 
    
         
            +
              # Sends DELETE request in async style.  See request_async for arguments.
         
     | 
| 
      
 699 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 700 
     | 
    
         
            +
              def delete_async(uri, extheader = {})
         
     | 
| 
      
 701 
     | 
    
         
            +
                request_async(:delete, uri, nil, nil, extheader)
         
     | 
| 
      
 702 
     | 
    
         
            +
              end
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
              # Sends OPTIONS request in async style.  See request_async for arguments.
         
     | 
| 
      
 705 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 706 
     | 
    
         
            +
              def options_async(uri, extheader = {})
         
     | 
| 
      
 707 
     | 
    
         
            +
                request_async(:options, uri, nil, nil, extheader)
         
     | 
| 
      
 708 
     | 
    
         
            +
              end
         
     | 
| 
      
 709 
     | 
    
         
            +
             
     | 
| 
      
 710 
     | 
    
         
            +
              # Sends PROPFIND request in async style.  See request_async for arguments.
         
     | 
| 
      
 711 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 712 
     | 
    
         
            +
              def propfind_async(uri, extheader = PROPFIND_DEFAULT_EXTHEADER)
         
     | 
| 
      
 713 
     | 
    
         
            +
                request_async(:propfind, uri, nil, nil, extheader)
         
     | 
| 
      
 714 
     | 
    
         
            +
              end
         
     | 
| 
      
 715 
     | 
    
         
            +
              
         
     | 
| 
      
 716 
     | 
    
         
            +
              # Sends PROPPATCH request in async style.  See request_async for arguments.
         
     | 
| 
      
 717 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 718 
     | 
    
         
            +
              def proppatch_async(uri, body = nil, extheader = {})
         
     | 
| 
      
 719 
     | 
    
         
            +
                request_async(:proppatch, uri, nil, body, extheader)
         
     | 
| 
      
 720 
     | 
    
         
            +
              end
         
     | 
| 
      
 721 
     | 
    
         
            +
              
         
     | 
| 
      
 722 
     | 
    
         
            +
              # Sends TRACE request in async style.  See request_async for arguments.
         
     | 
| 
      
 723 
     | 
    
         
            +
              # It immediately returns a HTTPClient::Connection instance as a result.
         
     | 
| 
      
 724 
     | 
    
         
            +
              def trace_async(uri, query = nil, body = nil, extheader = {})
         
     | 
| 
      
 725 
     | 
    
         
            +
                request_async(:trace, uri, query, body, extheader)
         
     | 
| 
      
 726 
     | 
    
         
            +
              end
         
     | 
| 
      
 727 
     | 
    
         
            +
             
     | 
| 
      
 728 
     | 
    
         
            +
              # Sends a request in async style.  request method creates new Thread for
         
     | 
| 
      
 729 
     | 
    
         
            +
              # HTTP connection and returns a HTTPClient::Connection instance immediately.
         
     | 
| 
      
 730 
     | 
    
         
            +
              #
         
     | 
| 
      
 731 
     | 
    
         
            +
              # Arguments definition is the same as request.
         
     | 
| 
      
 732 
     | 
    
         
            +
              def request_async(method, uri, query = nil, body = nil, extheader = {})
         
     | 
| 
      
 733 
     | 
    
         
            +
                uri = urify(uri)
         
     | 
| 
      
 734 
     | 
    
         
            +
                do_request_async(method, uri, query, body, extheader)
         
     | 
| 
      
 735 
     | 
    
         
            +
              end
         
     | 
| 
      
 736 
     | 
    
         
            +
             
     | 
| 
      
 737 
     | 
    
         
            +
              # Resets internal session for the given URL.  Keep-alive connection for the
         
     | 
| 
      
 738 
     | 
    
         
            +
              # site (host-port pair) is disconnected if exists.
         
     | 
| 
      
 739 
     | 
    
         
            +
              def reset(uri)
         
     | 
| 
      
 740 
     | 
    
         
            +
                uri = urify(uri)
         
     | 
| 
      
 741 
     | 
    
         
            +
                @session_manager.reset(uri)
         
     | 
| 
      
 742 
     | 
    
         
            +
              end
         
     | 
| 
      
 743 
     | 
    
         
            +
             
     | 
| 
      
 744 
     | 
    
         
            +
              # Resets all of internal sessions.  Keep-alive connections are disconnected.
         
     | 
| 
      
 745 
     | 
    
         
            +
              def reset_all
         
     | 
| 
      
 746 
     | 
    
         
            +
                @session_manager.reset_all
         
     | 
| 
      
 747 
     | 
    
         
            +
              end
         
     | 
| 
      
 748 
     | 
    
         
            +
             
     | 
| 
      
 749 
     | 
    
         
            +
            private
         
     | 
| 
      
 750 
     | 
    
         
            +
             
     | 
| 
      
 751 
     | 
    
         
            +
              class RetryableResponse < StandardError # :nodoc:
         
     | 
| 
      
 752 
     | 
    
         
            +
              end
         
     | 
| 
      
 753 
     | 
    
         
            +
             
     | 
| 
      
 754 
     | 
    
         
            +
              class KeepAliveDisconnected < StandardError # :nodoc:
         
     | 
| 
      
 755 
     | 
    
         
            +
              end
         
     | 
| 
      
 756 
     | 
    
         
            +
             
     | 
| 
      
 757 
     | 
    
         
            +
              def do_request(method, uri, query, body, extheader, &block)
         
     | 
| 
      
 758 
     | 
    
         
            +
                conn = Connection.new
         
     | 
| 
      
 759 
     | 
    
         
            +
                res = nil
         
     | 
| 
      
 760 
     | 
    
         
            +
                if HTTP::Message.file?(body)
         
     | 
| 
      
 761 
     | 
    
         
            +
                  pos = body.pos rescue nil
         
     | 
| 
      
 762 
     | 
    
         
            +
                end
         
     | 
| 
      
 763 
     | 
    
         
            +
                retry_count = @session_manager.protocol_retry_count
         
     | 
| 
      
 764 
     | 
    
         
            +
                proxy = no_proxy?(uri) ? nil : @proxy
         
     | 
| 
      
 765 
     | 
    
         
            +
                while retry_count > 0
         
     | 
| 
      
 766 
     | 
    
         
            +
                  body.pos = pos if pos
         
     | 
| 
      
 767 
     | 
    
         
            +
                  req = create_request(method, uri, query, body, extheader)
         
     | 
| 
      
 768 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 769 
     | 
    
         
            +
                    protect_keep_alive_disconnected do
         
     | 
| 
      
 770 
     | 
    
         
            +
                      do_get_block(req, proxy, conn, &block)
         
     | 
| 
      
 771 
     | 
    
         
            +
                    end
         
     | 
| 
      
 772 
     | 
    
         
            +
                    res = conn.pop
         
     | 
| 
      
 773 
     | 
    
         
            +
                    break
         
     | 
| 
      
 774 
     | 
    
         
            +
                  rescue RetryableResponse
         
     | 
| 
      
 775 
     | 
    
         
            +
                    res = conn.pop
         
     | 
| 
      
 776 
     | 
    
         
            +
                    retry_count -= 1
         
     | 
| 
      
 777 
     | 
    
         
            +
                  end
         
     | 
| 
      
 778 
     | 
    
         
            +
                end
         
     | 
| 
      
 779 
     | 
    
         
            +
                res
         
     | 
| 
      
 780 
     | 
    
         
            +
              end
         
     | 
| 
      
 781 
     | 
    
         
            +
             
     | 
| 
      
 782 
     | 
    
         
            +
              def do_request_async(method, uri, query, body, extheader)
         
     | 
| 
      
 783 
     | 
    
         
            +
                conn = Connection.new
         
     | 
| 
      
 784 
     | 
    
         
            +
                t = Thread.new(conn) { |tconn|
         
     | 
| 
      
 785 
     | 
    
         
            +
                  if HTTP::Message.file?(body)
         
     | 
| 
      
 786 
     | 
    
         
            +
                    pos = body.pos rescue nil
         
     | 
| 
      
 787 
     | 
    
         
            +
                  end
         
     | 
| 
      
 788 
     | 
    
         
            +
                  retry_count = @session_manager.protocol_retry_count
         
     | 
| 
      
 789 
     | 
    
         
            +
                  proxy = no_proxy?(uri) ? nil : @proxy
         
     | 
| 
      
 790 
     | 
    
         
            +
                  while retry_count > 0
         
     | 
| 
      
 791 
     | 
    
         
            +
                    body.pos = pos if pos
         
     | 
| 
      
 792 
     | 
    
         
            +
                    req = create_request(method, uri, query, body, extheader)
         
     | 
| 
      
 793 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 794 
     | 
    
         
            +
                      protect_keep_alive_disconnected do
         
     | 
| 
      
 795 
     | 
    
         
            +
                        do_get_stream(req, proxy, tconn)
         
     | 
| 
      
 796 
     | 
    
         
            +
                      end
         
     | 
| 
      
 797 
     | 
    
         
            +
                      break
         
     | 
| 
      
 798 
     | 
    
         
            +
                    rescue RetryableResponse
         
     | 
| 
      
 799 
     | 
    
         
            +
                      retry_count -= 1
         
     | 
| 
      
 800 
     | 
    
         
            +
                    end
         
     | 
| 
      
 801 
     | 
    
         
            +
                  end
         
     | 
| 
      
 802 
     | 
    
         
            +
                }
         
     | 
| 
      
 803 
     | 
    
         
            +
                conn.async_thread = t
         
     | 
| 
      
 804 
     | 
    
         
            +
                conn
         
     | 
| 
      
 805 
     | 
    
         
            +
              end
         
     | 
| 
      
 806 
     | 
    
         
            +
             
     | 
| 
      
 807 
     | 
    
         
            +
              def load_environment
         
     | 
| 
      
 808 
     | 
    
         
            +
                # http_proxy
         
     | 
| 
      
 809 
     | 
    
         
            +
                if getenv('REQUEST_METHOD')
         
     | 
| 
      
 810 
     | 
    
         
            +
                  # HTTP_PROXY conflicts with the environment variable usage in CGI where
         
     | 
| 
      
 811 
     | 
    
         
            +
                  # HTTP_* is used for HTTP header information.  Unlike open-uri, we
         
     | 
| 
      
 812 
     | 
    
         
            +
                  # simply ignore http_proxy in CGI env and use cgi_http_proxy instead.
         
     | 
| 
      
 813 
     | 
    
         
            +
                  self.proxy = getenv('cgi_http_proxy')
         
     | 
| 
      
 814 
     | 
    
         
            +
                else
         
     | 
| 
      
 815 
     | 
    
         
            +
                  self.proxy = getenv('http_proxy')
         
     | 
| 
      
 816 
     | 
    
         
            +
                end
         
     | 
| 
      
 817 
     | 
    
         
            +
                # no_proxy
         
     | 
| 
      
 818 
     | 
    
         
            +
                self.no_proxy = getenv('no_proxy')
         
     | 
| 
      
 819 
     | 
    
         
            +
              end
         
     | 
| 
      
 820 
     | 
    
         
            +
             
     | 
| 
      
 821 
     | 
    
         
            +
              def getenv(name)
         
     | 
| 
      
 822 
     | 
    
         
            +
                ENV[name.downcase] || ENV[name.upcase]
         
     | 
| 
      
 823 
     | 
    
         
            +
              end
         
     | 
| 
      
 824 
     | 
    
         
            +
             
     | 
| 
      
 825 
     | 
    
         
            +
              def follow_redirect(method, uri, query, body, extheader, &block)
         
     | 
| 
      
 826 
     | 
    
         
            +
                uri = urify(uri)
         
     | 
| 
      
 827 
     | 
    
         
            +
                if block
         
     | 
| 
      
 828 
     | 
    
         
            +
                  filtered_block = proc { |r, str|
         
     | 
| 
      
 829 
     | 
    
         
            +
                    block.call(str) if HTTP::Status.successful?(r.status)
         
     | 
| 
      
 830 
     | 
    
         
            +
                  }
         
     | 
| 
      
 831 
     | 
    
         
            +
                end
         
     | 
| 
      
 832 
     | 
    
         
            +
                if HTTP::Message.file?(body)
         
     | 
| 
      
 833 
     | 
    
         
            +
                  pos = body.pos rescue nil
         
     | 
| 
      
 834 
     | 
    
         
            +
                end
         
     | 
| 
      
 835 
     | 
    
         
            +
                retry_number = 0
         
     | 
| 
      
 836 
     | 
    
         
            +
                while retry_number < @follow_redirect_count
         
     | 
| 
      
 837 
     | 
    
         
            +
                  body.pos = pos if pos
         
     | 
| 
      
 838 
     | 
    
         
            +
                  res = do_request(method, uri, query, body, extheader, &filtered_block)
         
     | 
| 
      
 839 
     | 
    
         
            +
                  if HTTP::Status.successful?(res.status)
         
     | 
| 
      
 840 
     | 
    
         
            +
                    return res
         
     | 
| 
      
 841 
     | 
    
         
            +
                  elsif HTTP::Status.redirect?(res.status)
         
     | 
| 
      
 842 
     | 
    
         
            +
                    uri = urify(@redirect_uri_callback.call(uri, res))
         
     | 
| 
      
 843 
     | 
    
         
            +
                    retry_number += 1
         
     | 
| 
      
 844 
     | 
    
         
            +
                  else
         
     | 
| 
      
 845 
     | 
    
         
            +
                    raise BadResponseError.new("unexpected response: #{res.header.inspect}", res)
         
     | 
| 
      
 846 
     | 
    
         
            +
                  end
         
     | 
| 
      
 847 
     | 
    
         
            +
                end
         
     | 
| 
      
 848 
     | 
    
         
            +
                raise BadResponseError.new("retry count exceeded", res)
         
     | 
| 
      
 849 
     | 
    
         
            +
              end
         
     | 
| 
      
 850 
     | 
    
         
            +
             
     | 
| 
      
 851 
     | 
    
         
            +
              def protect_keep_alive_disconnected
         
     | 
| 
      
 852 
     | 
    
         
            +
                begin
         
     | 
| 
      
 853 
     | 
    
         
            +
                  yield
         
     | 
| 
      
 854 
     | 
    
         
            +
                rescue KeepAliveDisconnected
         
     | 
| 
      
 855 
     | 
    
         
            +
                  yield
         
     | 
| 
      
 856 
     | 
    
         
            +
                end
         
     | 
| 
      
 857 
     | 
    
         
            +
              end
         
     | 
| 
      
 858 
     | 
    
         
            +
             
     | 
| 
      
 859 
     | 
    
         
            +
              def create_request(method, uri, query, body, extheader)
         
     | 
| 
      
 860 
     | 
    
         
            +
                method = method.to_s.upcase
         
     | 
| 
      
 861 
     | 
    
         
            +
                if extheader.is_a?(Hash)
         
     | 
| 
      
 862 
     | 
    
         
            +
                  extheader = extheader.to_a
         
     | 
| 
      
 863 
     | 
    
         
            +
                else
         
     | 
| 
      
 864 
     | 
    
         
            +
                  extheader = extheader.dup
         
     | 
| 
      
 865 
     | 
    
         
            +
                end
         
     | 
| 
      
 866 
     | 
    
         
            +
                boundary = nil
         
     | 
| 
      
 867 
     | 
    
         
            +
                if body
         
     | 
| 
      
 868 
     | 
    
         
            +
                  dummy, content_type = extheader.find { |key, value|
         
     | 
| 
      
 869 
     | 
    
         
            +
                    key.downcase == 'content-type'
         
     | 
| 
      
 870 
     | 
    
         
            +
                  }
         
     | 
| 
      
 871 
     | 
    
         
            +
                  if content_type
         
     | 
| 
      
 872 
     | 
    
         
            +
                    if /\Amultipart/ =~ content_type
         
     | 
| 
      
 873 
     | 
    
         
            +
                      if content_type =~ /boundary=(.+)\z/
         
     | 
| 
      
 874 
     | 
    
         
            +
                        boundary = $1
         
     | 
| 
      
 875 
     | 
    
         
            +
                      else
         
     | 
| 
      
 876 
     | 
    
         
            +
                        boundary = create_boundary
         
     | 
| 
      
 877 
     | 
    
         
            +
                        content_type = "#{content_type}; boundary=#{boundary}"
         
     | 
| 
      
 878 
     | 
    
         
            +
                        extheader = override_header(extheader, 'Content-Type', content_type)
         
     | 
| 
      
 879 
     | 
    
         
            +
                      end
         
     | 
| 
      
 880 
     | 
    
         
            +
                    end
         
     | 
| 
      
 881 
     | 
    
         
            +
                  elsif method == 'POST'
         
     | 
| 
      
 882 
     | 
    
         
            +
                    if file_in_form_data?(body)
         
     | 
| 
      
 883 
     | 
    
         
            +
                      boundary = create_boundary
         
     | 
| 
      
 884 
     | 
    
         
            +
                      content_type = "multipart/form-data; boundary=#{boundary}"
         
     | 
| 
      
 885 
     | 
    
         
            +
                    else
         
     | 
| 
      
 886 
     | 
    
         
            +
                      content_type = 'application/x-www-form-urlencoded'
         
     | 
| 
      
 887 
     | 
    
         
            +
                    end
         
     | 
| 
      
 888 
     | 
    
         
            +
                    extheader << ['Content-Type', content_type]
         
     | 
| 
      
 889 
     | 
    
         
            +
                  end
         
     | 
| 
      
 890 
     | 
    
         
            +
                end
         
     | 
| 
      
 891 
     | 
    
         
            +
                req = HTTP::Message.new_request(method, uri, query, body, boundary)
         
     | 
| 
      
 892 
     | 
    
         
            +
                extheader.each do |key, value|
         
     | 
| 
      
 893 
     | 
    
         
            +
                  req.header.add(key, value)
         
     | 
| 
      
 894 
     | 
    
         
            +
                end
         
     | 
| 
      
 895 
     | 
    
         
            +
                if @cookie_manager && cookie = @cookie_manager.find(uri)
         
     | 
| 
      
 896 
     | 
    
         
            +
                  req.header.add('Cookie', cookie)
         
     | 
| 
      
 897 
     | 
    
         
            +
                end
         
     | 
| 
      
 898 
     | 
    
         
            +
                req
         
     | 
| 
      
 899 
     | 
    
         
            +
              end
         
     | 
| 
      
 900 
     | 
    
         
            +
             
     | 
| 
      
 901 
     | 
    
         
            +
              def create_boundary
         
     | 
| 
      
 902 
     | 
    
         
            +
                Digest::SHA1.hexdigest(Time.now.to_s)
         
     | 
| 
      
 903 
     | 
    
         
            +
              end
         
     | 
| 
      
 904 
     | 
    
         
            +
             
     | 
| 
      
 905 
     | 
    
         
            +
              def file_in_form_data?(body)
         
     | 
| 
      
 906 
     | 
    
         
            +
                HTTP::Message.multiparam_query?(body) &&
         
     | 
| 
      
 907 
     | 
    
         
            +
                  body.any? { |k, v| HTTP::Message.file?(v) }
         
     | 
| 
      
 908 
     | 
    
         
            +
              end
         
     | 
| 
      
 909 
     | 
    
         
            +
             
     | 
| 
      
 910 
     | 
    
         
            +
              def override_header(extheader, key, value)
         
     | 
| 
      
 911 
     | 
    
         
            +
                result = []
         
     | 
| 
      
 912 
     | 
    
         
            +
                extheader.each do |k, v|
         
     | 
| 
      
 913 
     | 
    
         
            +
                  if k.downcase == key.downcase
         
     | 
| 
      
 914 
     | 
    
         
            +
                    result << [key, value]
         
     | 
| 
      
 915 
     | 
    
         
            +
                  else
         
     | 
| 
      
 916 
     | 
    
         
            +
                    result << [k, v]
         
     | 
| 
      
 917 
     | 
    
         
            +
                  end
         
     | 
| 
      
 918 
     | 
    
         
            +
                end
         
     | 
| 
      
 919 
     | 
    
         
            +
                result
         
     | 
| 
      
 920 
     | 
    
         
            +
              end
         
     | 
| 
      
 921 
     | 
    
         
            +
             
     | 
| 
      
 922 
     | 
    
         
            +
              NO_PROXY_HOSTS = ['localhost']
         
     | 
| 
      
 923 
     | 
    
         
            +
             
     | 
| 
      
 924 
     | 
    
         
            +
              def no_proxy?(uri)
         
     | 
| 
      
 925 
     | 
    
         
            +
                if !@proxy or NO_PROXY_HOSTS.include?(uri.host)
         
     | 
| 
      
 926 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 927 
     | 
    
         
            +
                end
         
     | 
| 
      
 928 
     | 
    
         
            +
                unless @no_proxy
         
     | 
| 
      
 929 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 930 
     | 
    
         
            +
                end
         
     | 
| 
      
 931 
     | 
    
         
            +
                @no_proxy.scan(/([^:,]+)(?::(\d+))?/) do |host, port|
         
     | 
| 
      
 932 
     | 
    
         
            +
                  if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host &&
         
     | 
| 
      
 933 
     | 
    
         
            +
                      (!port || uri.port == port.to_i)
         
     | 
| 
      
 934 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 935 
     | 
    
         
            +
                  end
         
     | 
| 
      
 936 
     | 
    
         
            +
                end
         
     | 
| 
      
 937 
     | 
    
         
            +
                false
         
     | 
| 
      
 938 
     | 
    
         
            +
              end
         
     | 
| 
      
 939 
     | 
    
         
            +
             
     | 
| 
      
 940 
     | 
    
         
            +
              def https?(uri)
         
     | 
| 
      
 941 
     | 
    
         
            +
                uri.scheme.downcase == 'https'
         
     | 
| 
      
 942 
     | 
    
         
            +
              end
         
     | 
| 
      
 943 
     | 
    
         
            +
             
     | 
| 
      
 944 
     | 
    
         
            +
              # !! CAUTION !!
         
     | 
| 
      
 945 
     | 
    
         
            +
              #   Method 'do_get*' runs under MT conditon. Be careful to change.
         
     | 
| 
      
 946 
     | 
    
         
            +
              def do_get_block(req, proxy, conn, &block)
         
     | 
| 
      
 947 
     | 
    
         
            +
                @request_filter.each do |filter|
         
     | 
| 
      
 948 
     | 
    
         
            +
                  filter.filter_request(req)
         
     | 
| 
      
 949 
     | 
    
         
            +
                end
         
     | 
| 
      
 950 
     | 
    
         
            +
                if str = @test_loopback_response.shift
         
     | 
| 
      
 951 
     | 
    
         
            +
                  dump_dummy_request_response(req.body.dump, str) if @debug_dev
         
     | 
| 
      
 952 
     | 
    
         
            +
                  conn.push(HTTP::Message.new_response(str))
         
     | 
| 
      
 953 
     | 
    
         
            +
                  return
         
     | 
| 
      
 954 
     | 
    
         
            +
                end
         
     | 
| 
      
 955 
     | 
    
         
            +
                content = block ? nil : ''
         
     | 
| 
      
 956 
     | 
    
         
            +
                res = HTTP::Message.new_response(content)
         
     | 
| 
      
 957 
     | 
    
         
            +
                @debug_dev << "= Request\n\n" if @debug_dev
         
     | 
| 
      
 958 
     | 
    
         
            +
                sess = @session_manager.query(req, proxy)
         
     | 
| 
      
 959 
     | 
    
         
            +
                res.peer_cert = sess.ssl_peer_cert
         
     | 
| 
      
 960 
     | 
    
         
            +
                @debug_dev << "\n\n= Response\n\n" if @debug_dev
         
     | 
| 
      
 961 
     | 
    
         
            +
                do_get_header(req, res, sess)
         
     | 
| 
      
 962 
     | 
    
         
            +
                conn.push(res)
         
     | 
| 
      
 963 
     | 
    
         
            +
                sess.get_body do |part|
         
     | 
| 
      
 964 
     | 
    
         
            +
                  if block
         
     | 
| 
      
 965 
     | 
    
         
            +
                    block.call(res, part)
         
     | 
| 
      
 966 
     | 
    
         
            +
                  else
         
     | 
| 
      
 967 
     | 
    
         
            +
                    content << part
         
     | 
| 
      
 968 
     | 
    
         
            +
                  end
         
     | 
| 
      
 969 
     | 
    
         
            +
                end
         
     | 
| 
      
 970 
     | 
    
         
            +
                @session_manager.keep(sess) unless sess.closed?
         
     | 
| 
      
 971 
     | 
    
         
            +
                commands = @request_filter.collect { |filter|
         
     | 
| 
      
 972 
     | 
    
         
            +
                  filter.filter_response(req, res)
         
     | 
| 
      
 973 
     | 
    
         
            +
                }
         
     | 
| 
      
 974 
     | 
    
         
            +
                if commands.find { |command| command == :retry }
         
     | 
| 
      
 975 
     | 
    
         
            +
                  raise RetryableResponse.new
         
     | 
| 
      
 976 
     | 
    
         
            +
                end
         
     | 
| 
      
 977 
     | 
    
         
            +
              end
         
     | 
| 
      
 978 
     | 
    
         
            +
             
     | 
| 
      
 979 
     | 
    
         
            +
              def do_get_stream(req, proxy, conn)
         
     | 
| 
      
 980 
     | 
    
         
            +
                @request_filter.each do |filter|
         
     | 
| 
      
 981 
     | 
    
         
            +
                  filter.filter_request(req)
         
     | 
| 
      
 982 
     | 
    
         
            +
                end
         
     | 
| 
      
 983 
     | 
    
         
            +
                if str = @test_loopback_response.shift
         
     | 
| 
      
 984 
     | 
    
         
            +
                  dump_dummy_request_response(req.body.dump, str) if @debug_dev
         
     | 
| 
      
 985 
     | 
    
         
            +
                  conn.push(HTTP::Message.new_response(StringIO.new(str)))
         
     | 
| 
      
 986 
     | 
    
         
            +
                  return
         
     | 
| 
      
 987 
     | 
    
         
            +
                end
         
     | 
| 
      
 988 
     | 
    
         
            +
                piper, pipew = IO.pipe
         
     | 
| 
      
 989 
     | 
    
         
            +
                res = HTTP::Message.new_response(piper)
         
     | 
| 
      
 990 
     | 
    
         
            +
                @debug_dev << "= Request\n\n" if @debug_dev
         
     | 
| 
      
 991 
     | 
    
         
            +
                sess = @session_manager.query(req, proxy)
         
     | 
| 
      
 992 
     | 
    
         
            +
                res.peer_cert = sess.ssl_peer_cert
         
     | 
| 
      
 993 
     | 
    
         
            +
                @debug_dev << "\n\n= Response\n\n" if @debug_dev
         
     | 
| 
      
 994 
     | 
    
         
            +
                do_get_header(req, res, sess)
         
     | 
| 
      
 995 
     | 
    
         
            +
                conn.push(res)
         
     | 
| 
      
 996 
     | 
    
         
            +
                sess.get_body do |part|
         
     | 
| 
      
 997 
     | 
    
         
            +
                  pipew.syswrite(part)
         
     | 
| 
      
 998 
     | 
    
         
            +
                end
         
     | 
| 
      
 999 
     | 
    
         
            +
                pipew.close
         
     | 
| 
      
 1000 
     | 
    
         
            +
                @session_manager.keep(sess) unless sess.closed?
         
     | 
| 
      
 1001 
     | 
    
         
            +
                commands = @request_filter.collect { |filter|
         
     | 
| 
      
 1002 
     | 
    
         
            +
                  filter.filter_response(req, res)
         
     | 
| 
      
 1003 
     | 
    
         
            +
                }
         
     | 
| 
      
 1004 
     | 
    
         
            +
                # ignore commands (not retryable in async mode)
         
     | 
| 
      
 1005 
     | 
    
         
            +
              end
         
     | 
| 
      
 1006 
     | 
    
         
            +
             
     | 
| 
      
 1007 
     | 
    
         
            +
              def do_get_header(req, res, sess)
         
     | 
| 
      
 1008 
     | 
    
         
            +
                res.version, res.status, res.reason, headers = sess.get_header
         
     | 
| 
      
 1009 
     | 
    
         
            +
                headers.each do |key, value|
         
     | 
| 
      
 1010 
     | 
    
         
            +
                  res.header.add(key, value)
         
     | 
| 
      
 1011 
     | 
    
         
            +
                end
         
     | 
| 
      
 1012 
     | 
    
         
            +
                if @cookie_manager
         
     | 
| 
      
 1013 
     | 
    
         
            +
                  res.header['set-cookie'].each do |cookie|
         
     | 
| 
      
 1014 
     | 
    
         
            +
                    @cookie_manager.parse(cookie, req.header.request_uri)
         
     | 
| 
      
 1015 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1016 
     | 
    
         
            +
                end
         
     | 
| 
      
 1017 
     | 
    
         
            +
              end
         
     | 
| 
      
 1018 
     | 
    
         
            +
             
     | 
| 
      
 1019 
     | 
    
         
            +
              def dump_dummy_request_response(req, res)
         
     | 
| 
      
 1020 
     | 
    
         
            +
                @debug_dev << "= Dummy Request\n\n"
         
     | 
| 
      
 1021 
     | 
    
         
            +
                @debug_dev << req
         
     | 
| 
      
 1022 
     | 
    
         
            +
                @debug_dev << "\n\n= Dummy Response\n\n"
         
     | 
| 
      
 1023 
     | 
    
         
            +
                @debug_dev << res
         
     | 
| 
      
 1024 
     | 
    
         
            +
              end
         
     | 
| 
      
 1025 
     | 
    
         
            +
            end
         
     |