curb 0.8.5 → 0.9.11

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/ext/extconf.rb CHANGED
@@ -59,6 +59,9 @@ def have_constant(name)
59
59
  end
60
60
  end
61
61
 
62
+ have_constant "curlopt_tcp_keepalive"
63
+ have_constant "curlopt_tcp_keepidle"
64
+ have_constant "curlopt_tcp_keepintvl"
62
65
  have_constant "curlinfo_appconnect_time"
63
66
  have_constant "curlinfo_redirect_time"
64
67
  have_constant "curlinfo_response_code"
@@ -66,6 +69,7 @@ have_constant "curlinfo_filetime"
66
69
  have_constant "curlinfo_redirect_count"
67
70
  have_constant "curlinfo_os_errno"
68
71
  have_constant "curlinfo_num_connects"
72
+ have_constant "curlinfo_cookielist"
69
73
  have_constant "curlinfo_ftp_entry_path"
70
74
  have_constant "curl_version_ssl"
71
75
  have_constant "curl_version_libz"
@@ -78,9 +82,12 @@ have_constant "curl_version_largefile"
78
82
  have_constant "curl_version_idn"
79
83
  have_constant "curl_version_sspi"
80
84
  have_constant "curl_version_conv"
85
+ have_constant "curl_version_http2"
81
86
  have_constant "curlproxy_http"
82
87
  have_constant "curlproxy_socks4"
88
+ have_constant "curlproxy_socks4a"
83
89
  have_constant "curlproxy_socks5"
90
+ have_constant "curlproxy_socks5_hostname"
84
91
  have_constant "curlauth_basic"
85
92
  have_constant "curlauth_digest"
86
93
  have_constant "curlauth_gssnegotiate"
@@ -99,6 +106,12 @@ have_constant "curle_send_fail_rewind"
99
106
  have_constant "curle_ssl_engine_initfailed"
100
107
  have_constant "curle_login_denied"
101
108
 
109
+ # older than 7.10.0
110
+ have_constant "curlopt_nosignal"
111
+
112
+ # older than 7.16.0
113
+ have_constant "curlmopt_pipelining"
114
+
102
115
  # older than 7.16.3
103
116
  have_constant "curlmopt_maxconnects"
104
117
 
@@ -143,6 +156,8 @@ have_func("curl_multi_timeout")
143
156
  have_func("curl_multi_fdset")
144
157
  have_func("curl_multi_perform")
145
158
 
159
+ have_constant "curlopt_haproxyprotocol"
160
+
146
161
  # constants
147
162
  have_constant "curlopt_interleavefunction"
148
163
  have_constant "curlopt_interleavedata"
@@ -207,6 +222,7 @@ have_constant "curlopt_httppost"
207
222
  have_constant "curlopt_referer"
208
223
  have_constant "curlopt_useragent"
209
224
  have_constant "curlopt_httpheader"
225
+ have_constant "curlopt_proxyheader"
210
226
  have_constant "curlopt_http200aliases"
211
227
  have_constant "curlopt_cookie"
212
228
  have_constant "curlopt_cookiefile"
@@ -319,6 +335,12 @@ have_constant "curl_sslversion_default"
319
335
  have_constant :CURL_SSLVERSION_TLSv1
320
336
  have_constant :CURL_SSLVERSION_SSLv2
321
337
  have_constant :CURL_SSLVERSION_SSLv3
338
+
339
+ # Added in 7.34.0
340
+ have_constant :CURL_SSLVERSION_TLSv1_0
341
+ have_constant :CURL_SSLVERSION_TLSv1_1
342
+ have_constant :CURL_SSLVERSION_TLSv1_2
343
+
322
344
  have_constant "curlopt_ssl_verifypeer"
323
345
  have_constant "curlopt_cainfo"
324
346
  have_constant "curlopt_issuercert"
@@ -352,11 +374,32 @@ have_constant "curle_not_built_in"
352
374
 
353
375
  have_constant "curle_obsolete" # removed in 7.24 ?
354
376
 
377
+ have_constant "curle_ftp_pret_failed"
378
+ have_constant "curle_rtsp_cseq_error"
379
+ have_constant "curle_rtsp_session_error"
380
+ have_constant "curle_ftp_bad_file_list"
381
+ have_constant "curle_chunk_failed"
382
+ have_constant "curle_no_connection_available"
383
+ have_constant "curle_ssl_pinnedpubkeynotmatch"
384
+ have_constant "curle_ssl_invalidcertstatus"
385
+ have_constant "curle_http2_stream"
386
+
355
387
  # gssapi/spnego delegation related constants
356
388
  have_constant "curlopt_gssapi_delegation"
357
389
  have_constant "curlgssapi_delegation_policy_flag"
358
390
  have_constant "curlgssapi_delegation_flag"
359
391
 
392
+ have_constant "CURLM_ADDED_ALREADY"
393
+
394
+ # added in 7.40.0
395
+ have_constant "curlopt_unix_socket_path"
396
+
397
+ # added in 7.42.0
398
+ have_constant "curlopt_path_as_is"
399
+
400
+ # added in 7.43.0
401
+ have_constant "curlopt_pipewait"
402
+
360
403
  if try_compile('int main() { return 0; }','-Wall')
361
404
  $CFLAGS << ' -Wall'
362
405
  end
@@ -372,23 +415,6 @@ def test_for(name, const, src)
372
415
  end
373
416
  end
374
417
  end
375
- test_for("Ruby 1.9 Hash", "RUBY19_HASH", %{
376
- #include <ruby.h>
377
- int main() {
378
- VALUE hash = rb_hash_new();
379
- if( RHASH(hash)->ntbl->num_entries ) {
380
- return 0;
381
- }
382
- return 1;
383
- }
384
- })
385
- test_for("Ruby 1.9 st.h", "RUBY19_ST_H", %{
386
- #include <ruby.h>
387
- #include <ruby/st.h>
388
- int main() {
389
- return 0;
390
- }
391
- })
392
418
 
393
419
  test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
394
420
  #include <curl/curl.h>
@@ -400,6 +426,9 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
400
426
  })
401
427
 
402
428
  have_func('rb_thread_blocking_region')
429
+ have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
430
+ have_header('ruby/io.h')
431
+ have_func('rb_io_stdio_file')
403
432
 
404
433
  create_header('curb_config.h')
405
434
  create_makefile('curb_core')
data/lib/curb.rb CHANGED
@@ -1 +1,2 @@
1
+ # frozen_string_literal: true
1
2
  require 'curl'
data/lib/curl/easy.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
3
  class Easy
3
4
 
@@ -6,31 +7,41 @@ module Curl
6
7
  alias body body_str
7
8
  alias head header_str
8
9
 
10
+ class Error < StandardError
11
+ attr_accessor :message, :code
12
+ def initialize(code, msg)
13
+ self.message = msg
14
+ self.code = code
15
+ end
16
+ end
17
+
9
18
  #
10
19
  # call-seq:
11
20
  # easy.status => String
12
21
  #
13
22
  def status
14
- parts = self.header_str.split(/\s/)
15
- status = []
16
- parts.shift
17
- while parts.size > 0 && parts.first != ''
18
- status << parts.shift
19
- end
20
- status.join(' ')
23
+ # Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP (Opt:)Reason-Phrase CRLF'
24
+ statuses = self.header_str.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map{ |match| match[1] }
25
+ statuses.last.strip if statuses.length > 0
21
26
  end
22
27
 
23
28
  #
24
29
  # call-seq:
25
30
  # easy.set :sym|Fixnum, value
26
- #
31
+ #
27
32
  # set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
28
33
  #
29
34
  def set(opt,val)
30
35
  if opt.is_a?(Symbol)
31
- setopt(sym2curl(opt), val)
36
+ option = sym2curl(opt)
32
37
  else
33
- setopt(opt.to_i, val)
38
+ option = opt.to_i
39
+ end
40
+
41
+ begin
42
+ setopt(option, val)
43
+ rescue TypeError
44
+ raise TypeError, "Curb doesn't support setting #{opt} [##{option}] option"
34
45
  end
35
46
  end
36
47
 
@@ -56,10 +67,16 @@ module Curl
56
67
  self.multi = Curl::Multi.new if self.multi.nil?
57
68
  self.multi.add self
58
69
  ret = self.multi.perform
70
+ self.multi.remove self
71
+
72
+ if Curl::Multi.autoclose
73
+ self.multi.close
74
+ self.multi = nil
75
+ end
59
76
 
60
77
  if self.last_result != 0 && self.on_failure.nil?
61
- error = Curl::Easy.error(self.last_result)
62
- raise error.first
78
+ error = Curl::Easy.error(self.last_result)
79
+ raise error.first.new(self.head)
63
80
  end
64
81
 
65
82
  ret
@@ -83,54 +100,55 @@ module Curl
83
100
  # easy.perform
84
101
  #
85
102
  def delete=(onoff)
86
- set :customrequest, onoff ? 'delete' : nil
103
+ set :customrequest, onoff ? 'DELETE' : nil
87
104
  onoff
88
105
  end
89
- #
106
+ #
90
107
  # call-seq:
91
- #
108
+ #
92
109
  # easy = Curl::Easy.new("url")
110
+ # easy.version = Curl::HTTP_2_0
93
111
  # easy.version = Curl::HTTP_1_1
94
112
  # easy.version = Curl::HTTP_1_0
95
113
  # easy.version = Curl::HTTP_NONE
96
- #
114
+ #
97
115
  def version=(http_version)
98
116
  set :http_version, http_version
99
117
  end
100
118
 
101
- #
119
+ #
102
120
  # call-seq:
103
121
  # easy.url = "http://some.url/" => "http://some.url/"
104
- #
122
+ #
105
123
  # Set the URL for subsequent calls to +perform+. It is acceptable
106
124
  # (and even recommended) to reuse Curl::Easy instances by reassigning
107
125
  # the URL between calls to +perform+.
108
- #
126
+ #
109
127
  def url=(u)
110
128
  set :url, u
111
129
  end
112
130
 
113
- #
131
+ #
114
132
  # call-seq:
115
133
  # easy.proxy_url = string => string
116
- #
134
+ #
117
135
  # Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
118
136
  # The URL should specify the the host name or dotted IP address. To specify
119
137
  # port number in this string, append :[port] to the end of the host name.
120
138
  # The proxy string may be prefixed with [protocol]:// since any such prefix
121
139
  # will be ignored. The proxy's port number may optionally be specified with
122
140
  # the separate option proxy_port .
123
- #
141
+ #
124
142
  # When you tell the library to use an HTTP proxy, libcurl will transparently
125
143
  # convert operations to HTTP even if you specify an FTP URL etc. This may have
126
144
  # an impact on what other features of the library you can use, such as
127
145
  # FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
128
146
  # tunneling is activated with proxy_tunnel = true.
129
- #
147
+ #
130
148
  # libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
131
149
  # *all_proxy* etc, if any of those is set. The proxy_url option does however
132
150
  # override any possibly set environment variables.
133
- #
151
+ #
134
152
  # Starting with libcurl 7.14.1, the proxy host string given in environment
135
153
  # variables can be specified the exact same way as the proxy can be set with
136
154
  # proxy_url, including protocol prefix (http://) and embedded user + password.
@@ -145,89 +163,89 @@ module Curl
145
163
  self.ssl_verify_host_integer=value
146
164
  end
147
165
 
148
- #
166
+ #
149
167
  # call-seq:
150
168
  # easy.ssl_verify_host? => boolean
151
- #
169
+ #
152
170
  # Deprecated: call easy.ssl_verify_host instead
153
171
  # can be one of [0,1,2]
154
- #
172
+ #
155
173
  # Determine whether this Curl instance will verify that the server cert
156
174
  # is for the server it is known as.
157
- #
175
+ #
158
176
  def ssl_verify_host?
159
177
  ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
160
178
  end
161
179
 
162
- #
180
+ #
163
181
  # call-seq:
164
182
  # easy.interface = string => string
165
- #
183
+ #
166
184
  # Set the interface name to use as the outgoing network interface.
167
185
  # The name can be an interface name, an IP address or a host name.
168
- #
186
+ #
169
187
  def interface=(value)
170
188
  set :interface, value
171
189
  end
172
190
 
173
- #
191
+ #
174
192
  # call-seq:
175
193
  # easy.userpwd = string => string
176
- #
194
+ #
177
195
  # Set the username/password string to use for subsequent calls to +perform+.
178
196
  # The supplied string should have the form "username:password"
179
- #
197
+ #
180
198
  def userpwd=(value)
181
199
  set :userpwd, value
182
200
  end
183
201
 
184
- #
202
+ #
185
203
  # call-seq:
186
204
  # easy.proxypwd = string => string
187
- #
205
+ #
188
206
  # Set the username/password string to use for proxy connection during
189
207
  # subsequent calls to +perform+. The supplied string should have the
190
208
  # form "username:password"
191
- #
209
+ #
192
210
  def proxypwd=(value)
193
211
  set :proxyuserpwd, value
194
212
  end
195
213
 
196
- #
214
+ #
197
215
  # call-seq:
198
216
  # easy.cookies = "name1=content1; name2=content2;" => string
199
- #
217
+ #
200
218
  # Set cookies to be sent by this Curl::Easy instance. The format of the string should
201
219
  # be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
202
220
  # Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
203
- #
221
+ #
204
222
  def cookies=(value)
205
223
  set :cookie, value
206
224
  end
207
225
 
208
- #
226
+ #
209
227
  # call-seq:
210
228
  # easy.cookiefile = string => string
211
- #
229
+ #
212
230
  # Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
213
- #
231
+ #
214
232
  # *Note* that you must set enable_cookies true to enable the cookie
215
233
  # engine, or this option will be ignored.
216
- #
234
+ #
217
235
  def cookiefile=(value)
218
236
  set :cookiefile, value
219
237
  end
220
238
 
221
- #
239
+ #
222
240
  # call-seq:
223
241
  # easy.cookiejar = string => string
224
- #
242
+ #
225
243
  # Set a cookiejar file to use for this Curl::Easy instance.
226
244
  # Cookies from the response will be written into this file.
227
- #
245
+ #
228
246
  # *Note* that you must set enable_cookies true to enable the cookie
229
247
  # engine, or this option will be ignored.
230
- #
248
+ #
231
249
  def cookiejar=(value)
232
250
  set :cookiejar, value
233
251
  end
@@ -405,35 +423,35 @@ module Curl
405
423
  c.http_delete
406
424
  c
407
425
  end
408
-
426
+
409
427
  # call-seq:
410
428
  # Curl::Easy.download(url, filename = url.split(/\?/).first.split(/\//).last) { |curl| ... }
411
- #
429
+ #
412
430
  # Stream the specified url (via perform) and save the data directly to the
413
- # supplied filename (defaults to the last component of the URL path, which will
431
+ # supplied filename (defaults to the last component of the URL path, which will
414
432
  # usually be the filename most simple urls).
415
- #
433
+ #
416
434
  # If a block is supplied, it will be passed the curl instance prior to the
417
435
  # perform call.
418
- #
436
+ #
419
437
  # *Note* that the semantics of the on_body handler are subtly changed when using
420
- # download, to account for the automatic routing of data to the specified file: The
438
+ # download, to account for the automatic routing of data to the specified file: The
421
439
  # data string is passed to the handler *before* it is written
422
- # to the file, allowing the handler to perform mutative operations where
440
+ # to the file, allowing the handler to perform mutative operations where
423
441
  # necessary. As usual, the transfer will be aborted if the on_body handler
424
- # returns a size that differs from the data chunk size - in this case, the
442
+ # returns a size that differs from the data chunk size - in this case, the
425
443
  # offending chunk will *not* be written to the file, the file will be closed,
426
444
  # and a Curl::Err::AbortedByCallbackError will be raised.
427
445
  def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
428
446
  curl = Curl::Easy.new(url, &blk)
429
-
447
+
430
448
  output = if filename.is_a? IO
431
449
  filename.binmode if filename.respond_to?(:binmode)
432
450
  filename
433
451
  else
434
452
  File.open(filename, 'wb')
435
453
  end
436
-
454
+
437
455
  begin
438
456
  old_on_body = curl.on_body do |data|
439
457
  result = old_on_body ? old_on_body.call(data) : data.length
@@ -444,7 +462,7 @@ module Curl
444
462
  ensure
445
463
  output.close rescue IOError
446
464
  end
447
-
465
+
448
466
  return curl
449
467
  end
450
468
  end
data/lib/curl/multi.rb CHANGED
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
-
3
3
  class Multi
4
4
  class << self
5
5
  # call-seq:
6
- # Curl::Multi.get('url1','url2','url3','url4','url5', :follow_location => true) do|easy|
6
+ # Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
7
7
  # easy
8
8
  # end
9
- #
9
+ #
10
10
  # Blocking call to fetch multiple url's in parallel.
11
11
  def get(urls, easy_options={}, multi_options={}, &blk)
12
12
  url_confs = []
@@ -22,13 +22,13 @@ module Curl
22
22
  # {:url => 'url2', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
23
23
  # {:url => 'url3', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}}],
24
24
  # { :follow_location => true, :multipart_form_post => true },
25
- # {:pipeline => true }) do|easy|
25
+ # {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
26
26
  # easy_handle_on_request_complete
27
27
  # end
28
- #
28
+ #
29
29
  # Blocking call to POST multiple form's in parallel.
30
- #
31
- # urls_with_config: is a hash of url's pointing to the postfields to send
30
+ #
31
+ # urls_with_config: is a hash of url's pointing to the postfields to send
32
32
  # easy_options: are a set of common options to set on all easy handles
33
33
  # multi_options: options to set on the Curl::Multi handle
34
34
  #
@@ -46,13 +46,13 @@ module Curl
46
46
  # {:url => 'url2', :put_data => IO.read('filepath')},
47
47
  # {:url => 'url3', :put_data => "maybe another string or socket?"],
48
48
  # {:follow_location => true},
49
- # {:pipeline => true }) do|easy|
49
+ # {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
50
50
  # easy_handle_on_request_complete
51
51
  # end
52
- #
52
+ #
53
53
  # Blocking call to POST multiple form's in parallel.
54
- #
55
- # urls_with_config: is a hash of url's pointing to the postfields to send
54
+ #
55
+ # urls_with_config: is a hash of url's pointing to the postfields to send
56
56
  # easy_options: are a set of common options to set on all easy handles
57
57
  # multi_options: options to set on the Curl::Multi handle
58
58
  #
@@ -74,12 +74,12 @@ module Curl
74
74
  # :follow_location => true, :max_redirects => 3 },
75
75
  # { :url => 'url3', :method => :put, :put_data => File.open('file.txt','rb') },
76
76
  # { :url => 'url4', :method => :head }
77
- # ], {:pipeline => true})
77
+ # ], {:pipeline => Curl::CURLPIPE_HTTP1})
78
78
  #
79
79
  # Blocking call to issue multiple HTTP requests with varying verb's.
80
80
  #
81
81
  # urls_with_config: is a hash of url's pointing to the easy handle options as well as the special option :method, that can by one of [:get, :post, :put, :delete, :head], when no verb is provided e.g. :method => nil -> GET is used
82
- # multi_options: options for the multi handle
82
+ # multi_options: options for the multi handle
83
83
  # blk: a callback, that yeilds when a handle is completed
84
84
  #
85
85
  def http(urls_with_config, multi_options={}, &blk)
@@ -92,7 +92,7 @@ module Curl
92
92
 
93
93
  # configure the multi handle
94
94
  multi_options.each { |k,v| m.send("#{k}=", v) }
95
- callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
95
+ callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_redirect,:on_body,:on_header]
96
96
 
97
97
  add_free_handle = proc do|conf, easy|
98
98
  c = conf.dup # avoid being destructive to input
@@ -128,23 +128,23 @@ module Curl
128
128
 
129
129
  # headers is a special key
130
130
  headers.each {|k,v| easy.headers[k] = v } if headers
131
-
131
+
132
132
  #
133
133
  # use the remaining options as specific configuration to the easy handle
134
134
  # bad options should raise an undefined method error
135
135
  #
136
136
  c.each { |k,v| easy.send("#{k}=",v) }
137
137
 
138
- easy.on_complete {|curl,code|
138
+ easy.on_complete {|curl|
139
139
  free_handles << curl
140
- blk.call(curl,code,method) if blk
140
+ blk.call(curl,curl.response_code,method) if blk
141
141
  }
142
142
  m.add(easy)
143
143
  end
144
144
 
145
145
  max_connects.times do
146
146
  conf = urls_with_config.pop
147
- add_free_handle.call conf, nil
147
+ add_free_handle.call(conf, nil) if conf
148
148
  break if urls_with_config.empty?
149
149
  end
150
150
 
@@ -153,7 +153,7 @@ module Curl
153
153
  if urls_with_config.size > 0 && free_handles.size > 0
154
154
  easy = free_handles.pop
155
155
  conf = urls_with_config.pop
156
- add_free_handle.call conf, easy
156
+ add_free_handle.call(conf, easy) if conf
157
157
  end
158
158
  end
159
159
 
@@ -168,6 +168,7 @@ module Curl
168
168
  end
169
169
  free_handles = nil
170
170
  end
171
+
171
172
  end
172
173
 
173
174
  # call-seq:
@@ -175,7 +176,7 @@ module Curl
175
176
  # Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
176
177
  #
177
178
  # will create 2 new files file1.txt and file2.txt
178
- #
179
+ #
179
180
  # 2 files will be opened, and remain open until the call completes
180
181
  #
181
182
  # when using the :post or :put method, urls should be a hash, including the individual post fields per post
@@ -242,7 +243,45 @@ module Curl
242
243
  }
243
244
  raise errors unless errors.empty?
244
245
  end
246
+ end
245
247
 
248
+ def cancel!
249
+ requests.each do |_,easy|
250
+ remove(easy)
251
+ end
246
252
  end
253
+
254
+ def idle?
255
+ requests.empty?
256
+ end
257
+
258
+ def requests
259
+ @requests ||= {}
260
+ end
261
+
262
+ def add(easy)
263
+ return self if requests[easy.object_id]
264
+ requests[easy.object_id] = easy
265
+ _add(easy)
266
+ self
267
+ end
268
+
269
+ def remove(easy)
270
+ return self if !requests[easy.object_id]
271
+ requests.delete(easy.object_id)
272
+ _remove(easy)
273
+ self
274
+ end
275
+
276
+ def close
277
+ requests.values.each {|easy|
278
+ _remove(easy)
279
+ }
280
+ @requests = {}
281
+ _close
282
+ self
283
+ end
284
+
285
+
247
286
  end
248
287
  end
data/lib/curl.rb CHANGED
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  require 'curb_core'
2
3
  require 'curl/easy'
3
4
  require 'curl/multi'
4
5
  require 'uri'
6
+ require 'cgi'
5
7
 
6
8
  # expose shortcut methods
7
9
  module Curl
8
-
10
+
9
11
  def self.http(verb, url, post_body=nil, put_data=nil, &block)
10
12
  handle = Thread.current[:curb_curl] ||= Curl::Easy.new
11
13
  handle.reset
@@ -46,18 +48,21 @@ module Curl
46
48
  end
47
49
 
48
50
  def self.urlalize(url, params={})
49
- query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
50
- if url.match(/\?/)
51
- "#{url}&#{query_str}"
52
- elsif query_str.size > 0
53
- "#{url}?#{query_str}"
54
- else
55
- url
56
- end
51
+ uri = URI(url)
52
+ # early return if we didn't specify any extra params
53
+ return uri.to_s if (params || {}).empty?
54
+
55
+ params_query = URI.encode_www_form(params || {})
56
+ uri.query = [uri.query.to_s, params_query].reject(&:empty?).join('&')
57
+ uri.to_s
57
58
  end
58
59
 
59
60
  def self.postalize(params={})
60
61
  params.respond_to?(:map) ? URI.encode_www_form(params) : (params.respond_to?(:to_s) ? params.to_s : params)
61
62
  end
62
63
 
64
+ def self.reset
65
+ Thread.current[:curb_curl] = Curl::Easy.new
66
+ end
67
+
63
68
  end