File: easy.rb

package info (click to toggle)
ruby-curb 0.8.6-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 604 kB
  • ctags: 880
  • sloc: ansic: 4,242; ruby: 2,768; makefile: 3
file content (480 lines) | stat: -rw-r--r-- 14,605 bytes parent folder | download
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
module Curl
  class Easy

    alias post http_post
    alias put http_put
    alias body body_str
    alias head header_str

    class Error < Exception
      attr_accessor :message, :code
      def initialize(code, msg)
        self.message = msg
        self.code = code
      end
    end

    #
    # call-seq:
    #   easy.status  => String
    #
    def status
      # Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF'
      statuses = self.header_str.scan(/HTTP\/\d\.\d\s(\d+\s.+)\r\n/).map{ |match|  match[0] }
      statuses.last.strip
    end

    #
    # call-seq:
    #   easy.set :sym|Fixnum, value
    #
    # set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
    #
    def set(opt,val)
      if opt.is_a?(Symbol)
        option = sym2curl(opt)
      else
        option = opt.to_i
      end

      begin
        setopt(option, val)
      rescue TypeError
        raise TypeError, "Curb doesn't support setting #{opt} [##{option}] option"
      end
    end

    #
    # call-seq:
    #   easy.sym2curl :symbol => Fixnum
    #
    #  translates ruby symbols to libcurl options
    #
    def sym2curl(opt)
      Curl.const_get("CURLOPT_#{opt.to_s.upcase}")
    end

    #
    # call-seq:
    #   easy.perform                                     => true
    #
    # Transfer the currently configured URL using the options set for this
    # Curl::Easy instance. If this is an HTTP URL, it will be transferred via
    # the configured HTTP Verb.
    #
    def perform
      self.multi = Curl::Multi.new if self.multi.nil?
      self.multi.add self
      ret = self.multi.perform

      if self.last_result != 0 && self.on_failure.nil?
        error = Curl::Easy.error(self.last_result)
        raise error.first.new(error.last)
      end

      ret
    end

    #
    # call-seq:
    #
    # easy = Curl::Easy.new
    # easy.nosignal = true
    #
    def nosignal=(onoff)
      set :nosignal, !!onoff
    end

    #
    # call-seq:
    #   easy = Curl::Easy.new("url") do|c|
    #    c.delete = true
    #   end
    #   easy.perform
    #
    def delete=(onoff)
      set :customrequest, onoff ? 'DELETE' : nil
      onoff
    end
    #
    # call-seq:
    #
    #  easy = Curl::Easy.new("url")
    #  easy.version = Curl::HTTP_1_1
    #  easy.version = Curl::HTTP_1_0
    #  easy.version = Curl::HTTP_NONE
    #
    def version=(http_version)
      set :http_version, http_version
    end

    #
    # call-seq:
    #   easy.url = "http://some.url/"                    => "http://some.url/"
    #
    # Set the URL for subsequent calls to +perform+. It is acceptable
    # (and even recommended) to reuse Curl::Easy instances by reassigning
    # the URL between calls to +perform+.
    #
    def url=(u)
      set :url, u
    end

    #
    # call-seq:
    #   easy.proxy_url = string                          => string
    #
    # Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
    # The URL should specify the the host name or dotted IP address. To specify
    # port number in this string, append :[port] to the end of the host name.
    # The proxy string may be prefixed with [protocol]:// since any such prefix
    # will be ignored. The proxy's port number may optionally be specified with
    # the separate option proxy_port .
    #
    # When you tell the library to use an HTTP proxy, libcurl will transparently
    # convert operations to HTTP even if you specify an FTP URL etc. This may have
    # an impact on what other features of the library you can use, such as
    # FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
    # tunneling is activated with proxy_tunnel = true.
    #
    # libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
    # *all_proxy* etc, if any of those is set. The proxy_url option does however
    # override any possibly set environment variables.
    #
    # Starting with libcurl 7.14.1, the proxy host string given in environment
    # variables can be specified the exact same way as the proxy can be set with
    # proxy_url, including protocol prefix (http://) and embedded user + password.
    #
    def proxy_url=(url)
      set :proxy, url
    end

    def ssl_verify_host=(value)
      value = 1 if value.class == TrueClass
      value = 0 if value.class == FalseClass
      self.ssl_verify_host_integer=value
    end

    #
    # call-seq:
    #   easy.ssl_verify_host?                            => boolean
    #
    # Deprecated: call easy.ssl_verify_host instead
    # can be one of [0,1,2]
    #
    # Determine whether this Curl instance will verify that the server cert
    # is for the server it is known as.
    #
    def ssl_verify_host?
      ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
    end

    #
    # call-seq:
    #   easy.interface = string                          => string
    #
    # Set the interface name to use as the outgoing network interface.
    # The name can be an interface name, an IP address or a host name.
    #
    def interface=(value)
      set :interface, value
    end

    #
    # call-seq:
    #   easy.userpwd = string                            => string
    #
    # Set the username/password string to use for subsequent calls to +perform+.
    # The supplied string should have the form "username:password"
    #
    def userpwd=(value)
      set :userpwd, value
    end

    #
    # call-seq:
    #   easy.proxypwd = string                           => string
    #
    # Set the username/password string to use for proxy connection during
    # subsequent calls to +perform+. The supplied string should have the
    # form "username:password"
    #
    def proxypwd=(value)
      set :proxyuserpwd, value
    end

    #
    # call-seq:
    #   easy.cookies = "name1=content1; name2=content2;" => string
    #
    # Set cookies to be sent by this Curl::Easy instance. The format of the string should
    # be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
    # Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
    #
    def cookies=(value)
      set :cookie, value
    end

    #
    # call-seq:
    #   easy.cookiefile = string                         => string
    #
    # Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
    #
    # *Note* that you must set enable_cookies true to enable the cookie
    # engine, or this option will be ignored.
    #
    def cookiefile=(value)
      set :cookiefile, value
    end

    #
    # call-seq:
    #   easy.cookiejar = string                          => string
    #
    # Set a cookiejar file to use for this Curl::Easy instance.
    # Cookies from the response will be written into this file.
    #
    # *Note* that you must set enable_cookies true to enable the cookie
    # engine, or this option will be ignored.
    #
    def cookiejar=(value)
      set :cookiejar, value
    end

    #
    # call-seq:
    #  easy = Curl::Easy.new("url") do|c|
    #   c.head = true
    #  end
    #  easy.perform
    #
    def head=(onoff)
      set :nobody, onoff
    end

    #
    # call-seq:
    #   easy.follow_location = boolean                   => boolean
    #
    # Configure whether this Curl instance will follow Location: headers
    # in HTTP responses. Redirects will only be followed to the extent
    # specified by +max_redirects+.
    #
    def follow_location=(onoff)
      set :followlocation, onoff
    end

    #
    # call-seq:
    #   easy.http_head                                   => true
    #
    # Request headers from the currently configured URL using the HEAD
    # method and current options set for this Curl::Easy instance. This
    # method always returns true, or raises an exception (defined under
    # Curl::Err) on error.
    #
    def http_head
      set :nobody, true
      ret = self.perform
      set :nobody, false
      ret
    end

    #
    # call-seq:
    #   easy.http_get                                    => true
    #
    # GET the currently configured URL using the current options set for
    # this Curl::Easy instance. This method always returns true, or raises
    # an exception (defined under Curl::Err) on error.
    #
    def http_get
      set :httpget, true
      http :GET
    end
    alias get http_get

    #
    # call-seq:
    #   easy.http_delete
    #
    # DELETE the currently configured URL using the current options set for
    # this Curl::Easy instance. This method always returns true, or raises
    # an exception (defined under Curl::Err) on error.
    #
    def http_delete
      self.http :DELETE
    end
    alias delete http_delete

    class << self

      #
      # call-seq:
      #   Curl::Easy.perform(url) { |easy| ... }           => #&lt;Curl::Easy...&gt;
      #
      # Convenience method that creates a new Curl::Easy instance with
      # the specified URL and calls the general +perform+ method, before returning
      # the new instance. For HTTP URLs, this is equivalent to calling +http_get+.
      #
      # If a block is supplied, the new instance will be yielded just prior to
      # the +http_get+ call.
      #
      def perform(*args)
        c = Curl::Easy.new(*args)
        yield c if block_given?
        c.perform
        c
      end

      #
      # call-seq:
      #   Curl::Easy.http_get(url) { |easy| ... }          => #&lt;Curl::Easy...&gt;
      #
      # Convenience method that creates a new Curl::Easy instance with
      # the specified URL and calls +http_get+, before returning the new instance.
      #
      # If a block is supplied, the new instance will be yielded just prior to
      # the +http_get+ call.
      #
      def http_get(*args)
        c = Curl::Easy.new(*args)
        yield c if block_given?
        c.http_get
        c
      end

      #
      # call-seq:
      #   Curl::Easy.http_head(url) { |easy| ... }         => #&lt;Curl::Easy...&gt;
      #
      # Convenience method that creates a new Curl::Easy instance with
      # the specified URL and calls +http_head+, before returning the new instance.
      #
      # If a block is supplied, the new instance will be yielded just prior to
      # the +http_head+ call.
      #
      def http_head(*args)
        c = Curl::Easy.new(*args)
        yield c if block_given?
        c.http_head
        c
      end

      #
      # call-seq:
      #   Curl::Easy.http_put(url, data) {|c| ... }
      #
      # see easy.http_put
      #
      def http_put(url, data)
        c = Curl::Easy.new url
        yield c if block_given?
        c.http_put data
        c
      end

      #
      # call-seq:
      #   Curl::Easy.http_post(url, "some=urlencoded%20form%20data&and=so%20on") => true
      #   Curl::Easy.http_post(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
      #   Curl::Easy.http_post(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
      #   Curl::Easy.http_post(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
      #
      # POST the specified formdata to the currently configured URL using
      # the current options set for this Curl::Easy instance. This method
      # always returns true, or raises an exception (defined under
      # Curl::Err) on error.
      #
      # If you wish to use multipart form encoding, you'll need to supply a block
      # in order to set multipart_form_post true. See #http_post for more
      # information.
      #
      def http_post(*args)
        url = args.shift
        c = Curl::Easy.new url
        yield c if block_given?
        c.http_post(*args)
        c
      end

      #
      # call-seq:
      #   Curl::Easy.http_delete(url) { |easy| ... }       => #&lt;Curl::Easy...&gt;
      #
      # Convenience method that creates a new Curl::Easy instance with
      # the specified URL and calls +http_delete+, before returning the new instance.
      #
      # If a block is supplied, the new instance will be yielded just prior to
      # the +http_delete+ call.
      #
      def http_delete(*args)
        c = Curl::Easy.new(*args)
        yield c if block_given?
        c.http_delete
        c
      end

      # call-seq:
      #   Curl::Easy.download(url, filename = url.split(/\?/).first.split(/\//).last) { |curl| ... }
      #
      # Stream the specified url (via perform) and save the data directly to the
      # supplied filename (defaults to the last component of the URL path, which will
      # usually be the filename most simple urls).
      #
      # If a block is supplied, it will be passed the curl instance prior to the
      # perform call.
      #
      # *Note* that the semantics of the on_body handler are subtly changed when using
      # download, to account for the automatic routing of data to the specified file: The
      # data string is passed to the handler *before* it is written
      # to the file, allowing the handler to perform mutative operations where
      # necessary. As usual, the transfer will be aborted if the on_body handler
      # returns a size that differs from the data chunk size - in this case, the
      # offending chunk will *not* be written to the file, the file will be closed,
      # and a Curl::Err::AbortedByCallbackError will be raised.
      def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
        curl = Curl::Easy.new(url, &blk)

        output = if filename.is_a? IO
          filename.binmode if filename.respond_to?(:binmode)
          filename
        else
          File.open(filename, 'wb')
        end

        begin
          old_on_body = curl.on_body do |data|
            result = old_on_body ?  old_on_body.call(data) : data.length
            output << data if result == data.length
            result
          end
          curl.perform
        ensure
          output.close rescue IOError
        end

        return curl
      end
    end

    # Allow the incoming cert string to be file:password
    # but be careful to not use a colon from a windows file path
    # as the split point. Mimic what curl's main does
    if respond_to?(:cert=)
    alias_method :native_cert=, :cert=
    def cert=(cert_file)
      pos = cert_file.rindex(':')
      if pos && pos > 1
        self.native_cert= cert_file[0..pos-1]
        self.certpassword= cert_file[pos+1..-1]
      else
        self.native_cert= cert_file
      end
      self.cert
    end
    end

  end
end