File: util.rb

package info (click to toggle)
ruby-httpclient 2.8.3%2Bgit20211122.4658227-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,908 kB
  • sloc: ruby: 9,963; makefile: 10; sh: 2
file content (222 lines) | stat: -rw-r--r-- 5,874 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# HTTPClient - HTTP client library.
# Copyright (C) 2000-2015  NAKAMURA, Hiroshi  <nahi@ruby-lang.org>.
#
# This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
# redistribute it and/or modify it under the same terms of Ruby's license;
# either the dual license version in 2003, or any later version.


unless ''.respond_to?(:bytesize)
  class String
    alias bytesize size
  end
end

if RUBY_VERSION < "1.9.3"
  require 'uri'
  module URI
    class Generic
      def hostname
        v = self.host
        /\A\[(.*)\]\z/ =~ v ? $1 : v
      end
    end
  end
end

# With recent JRuby 1.7 + jruby-openssl, X509CRL#extentions_to_text causes
# StringIndexOOBException when we try to dump SSL Server Certificate.
# when one of extensions has "" as value.
if defined?(JRUBY_VERSION)
  require 'openssl'
  require 'java'
  module OpenSSL
    module X509
      class Certificate
        java_import 'java.security.cert.Certificate'
        java_import 'java.security.cert.CertificateFactory'
        java_import 'java.io.ByteArrayInputStream'
        def to_text
          cf = CertificateFactory.getInstance('X.509')
          cf.generateCertificate(ByteArrayInputStream.new(self.to_der.to_java_bytes)).toString
        end
      end
    end
  end
end


class HTTPClient


  # A module for common function.
  module Util

    # URI abstraction; Addressable::URI or URI
    require 'uri'
    begin
      require 'addressable/uri'
      # Older versions doesn't have #default_port
      unless Addressable::URI.instance_methods.include?(:default_port) # 1.9 only
        raise LoadError
      end
      class AddressableURI < Addressable::URI
        # Overwrites the original definition just for one line...
        def authority
          self.host && @authority ||= (begin
            authority = ""
            if self.userinfo != nil
              authority << "#{self.userinfo}@"
            end
            authority << self.host
            if self.port != self.default_port # ...HERE! Compares with default_port because self.port is not nil in this wrapper.
              authority << ":#{self.port}"
            end
            authority
          end)
        end

        # HTTPClient expects urify("http://foo/").port to be not nil but 80 like URI.
        def port
          super || default_port
        end

        # Captured from uri/generic.rb
        def hostname
          v = self.host
          /\A\[(.*)\]\z/ =~ v ? $1 : v
        end
      end
      AddressableEnabled = true
    rescue LoadError
      AddressableEnabled = false
    end

    # Keyword argument helper.
    # args:: given arguments.
    # *field:: a list of arguments to be extracted.
    #
    # You can extract 3 arguments (a, b, c) with:
    #
    #   include Util
    #   def my_method(*args)
    #     a, b, c = keyword_argument(args, :a, :b, :c)
    #     ...
    #   end
    #   my_method(1, 2, 3)
    #   my_method(:b => 2, :a = 1)
    #
    # instead of;
    #
    #   def my_method(a, b, c)
    #     ...
    #   end
    #
    def keyword_argument(args, *field)
      if args.size == 1 and Hash === args[0]
        h = args[0]
        if field.any? { |f| h.key?(f) }
          return h.values_at(*field)
        end
      end
      args
    end

    # Keyword argument to hash helper.
    # args:: given arguments.
    # *field:: a list of arguments to be extracted.
    #
    # Returns hash which has defined keys. When a Hash given, returns it
    # including undefined keys. When an Array given, returns a Hash which only
    # includes defined keys.
    def argument_to_hash(args, *field)
      return nil if args.empty?
      if args.size == 1 and Hash === args[0]
        h = args[0]
        if field.any? { |f| h.key?(f) }
          return h
        end
      end
      h = {}
      field.each_with_index do |e, idx|
        h[e] = args[idx]
      end
      h
    end

    # Gets an URI instance.
    def urify(uri)
      if uri.nil?
        nil
      elsif uri.is_a?(URI)
        uri
      elsif AddressableEnabled
        AddressableURI.parse(uri.to_s)
      else
        URI.parse(uri.to_s)
      end
    end
    module_function :urify

    # Returns true if the given 2 URIs have a part_of relationship.
    # * the same scheme
    # * the same host String (no host resolution or IP-addr conversion)
    # * the same port number
    # * target URI's path starts with base URI's path.
    def uri_part_of(uri, part)
      ((uri.scheme == part.scheme) and
       (uri.host == part.host) and
       (uri.port == part.port) and
       uri.path.upcase.index(part.path.upcase) == 0)
    end
    module_function :uri_part_of

    # Returns parent directory URI of the given URI.
    def uri_dirname(uri)
      uri = uri.clone
      uri.path = uri.path.sub(/\/[^\/]*\z/, '/')
      uri
    end
    module_function :uri_dirname

    # Finds a value of a Hash.
    def hash_find_value(hash, &block)
      v = hash.find(&block)
      v ? v[1] : nil
    end
    module_function :hash_find_value

    # Try to require a feature and returns true/false if loaded
    #
    # It returns 'true' for the second require in contrast of the standard
    # require returns false if the feature is already loaded.
    def try_require(feature)
      require feature
      true
    rescue LoadError
      false
    end
    module_function :try_require

    # show one warning message only once by caching message
    #
    # it cached all messages in memory so be careful not to show many kinds of warning message.
    @@__warned = {}
    def warning(message)
      return if @@__warned.key?(message)
      warn(message)
      @@__warned[message] = true
    end

    # Checks if the given URI is https.
    def https?(uri)
      uri.scheme && uri.scheme.downcase == 'https'
    end

    def http?(uri)
      uri.scheme && uri.scheme.downcase == 'http'
    end
  end


end