curb 0.8.4 → 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,12 +59,17 @@ 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"
65
+ have_constant "curlinfo_appconnect_time"
62
66
  have_constant "curlinfo_redirect_time"
63
67
  have_constant "curlinfo_response_code"
64
68
  have_constant "curlinfo_filetime"
65
69
  have_constant "curlinfo_redirect_count"
66
70
  have_constant "curlinfo_os_errno"
67
71
  have_constant "curlinfo_num_connects"
72
+ have_constant "curlinfo_cookielist"
68
73
  have_constant "curlinfo_ftp_entry_path"
69
74
  have_constant "curl_version_ssl"
70
75
  have_constant "curl_version_libz"
@@ -77,9 +82,12 @@ have_constant "curl_version_largefile"
77
82
  have_constant "curl_version_idn"
78
83
  have_constant "curl_version_sspi"
79
84
  have_constant "curl_version_conv"
85
+ have_constant "curl_version_http2"
80
86
  have_constant "curlproxy_http"
81
87
  have_constant "curlproxy_socks4"
88
+ have_constant "curlproxy_socks4a"
82
89
  have_constant "curlproxy_socks5"
90
+ have_constant "curlproxy_socks5_hostname"
83
91
  have_constant "curlauth_basic"
84
92
  have_constant "curlauth_digest"
85
93
  have_constant "curlauth_gssnegotiate"
@@ -98,6 +106,12 @@ have_constant "curle_send_fail_rewind"
98
106
  have_constant "curle_ssl_engine_initfailed"
99
107
  have_constant "curle_login_denied"
100
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
+
101
115
  # older than 7.16.3
102
116
  have_constant "curlmopt_maxconnects"
103
117
 
@@ -142,6 +156,8 @@ have_func("curl_multi_timeout")
142
156
  have_func("curl_multi_fdset")
143
157
  have_func("curl_multi_perform")
144
158
 
159
+ have_constant "curlopt_haproxyprotocol"
160
+
145
161
  # constants
146
162
  have_constant "curlopt_interleavefunction"
147
163
  have_constant "curlopt_interleavedata"
@@ -206,6 +222,7 @@ have_constant "curlopt_httppost"
206
222
  have_constant "curlopt_referer"
207
223
  have_constant "curlopt_useragent"
208
224
  have_constant "curlopt_httpheader"
225
+ have_constant "curlopt_proxyheader"
209
226
  have_constant "curlopt_http200aliases"
210
227
  have_constant "curlopt_cookie"
211
228
  have_constant "curlopt_cookiefile"
@@ -318,6 +335,12 @@ have_constant "curl_sslversion_default"
318
335
  have_constant :CURL_SSLVERSION_TLSv1
319
336
  have_constant :CURL_SSLVERSION_SSLv2
320
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
+
321
344
  have_constant "curlopt_ssl_verifypeer"
322
345
  have_constant "curlopt_cainfo"
323
346
  have_constant "curlopt_issuercert"
@@ -351,6 +374,32 @@ have_constant "curle_not_built_in"
351
374
 
352
375
  have_constant "curle_obsolete" # removed in 7.24 ?
353
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
+
387
+ # gssapi/spnego delegation related constants
388
+ have_constant "curlopt_gssapi_delegation"
389
+ have_constant "curlgssapi_delegation_policy_flag"
390
+ have_constant "curlgssapi_delegation_flag"
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
+
354
403
  if try_compile('int main() { return 0; }','-Wall')
355
404
  $CFLAGS << ' -Wall'
356
405
  end
@@ -366,23 +415,6 @@ def test_for(name, const, src)
366
415
  end
367
416
  end
368
417
  end
369
- test_for("Ruby 1.9 Hash", "RUBY19_HASH", %{
370
- #include <ruby.h>
371
- int main() {
372
- VALUE hash = rb_hash_new();
373
- if( RHASH(hash)->ntbl->num_entries ) {
374
- return 0;
375
- }
376
- return 1;
377
- }
378
- })
379
- test_for("Ruby 1.9 st.h", "RUBY19_ST_H", %{
380
- #include <ruby.h>
381
- #include <ruby/st.h>
382
- int main() {
383
- return 0;
384
- }
385
- })
386
418
 
387
419
  test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
388
420
  #include <curl/curl.h>
@@ -394,6 +426,9 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
394
426
  })
395
427
 
396
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')
397
432
 
398
433
  create_header('curb_config.h')
399
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,34 +1,47 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
3
  class Easy
3
4
 
4
5
  alias post http_post
5
6
  alias put http_put
7
+ alias body body_str
8
+ alias head header_str
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
6
17
 
7
18
  #
8
19
  # call-seq:
9
20
  # easy.status => String
10
21
  #
11
22
  def status
12
- parts = self.header_str.split(/\s/)
13
- status = []
14
- parts.shift
15
- while parts.size > 0 && parts.first != ''
16
- status << parts.shift
17
- end
18
- 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
19
26
  end
20
27
 
21
28
  #
22
29
  # call-seq:
23
30
  # easy.set :sym|Fixnum, value
24
- #
31
+ #
25
32
  # set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
26
33
  #
27
34
  def set(opt,val)
28
35
  if opt.is_a?(Symbol)
29
- setopt(sym2curl(opt), val)
36
+ option = sym2curl(opt)
30
37
  else
31
- 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"
32
45
  end
33
46
  end
34
47
 
@@ -54,10 +67,16 @@ module Curl
54
67
  self.multi = Curl::Multi.new if self.multi.nil?
55
68
  self.multi.add self
56
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
57
76
 
58
77
  if self.last_result != 0 && self.on_failure.nil?
59
- error = Curl::Easy.error(self.last_result)
60
- raise error.first
78
+ error = Curl::Easy.error(self.last_result)
79
+ raise error.first.new(self.head)
61
80
  end
62
81
 
63
82
  ret
@@ -81,54 +100,55 @@ module Curl
81
100
  # easy.perform
82
101
  #
83
102
  def delete=(onoff)
84
- set :customrequest, onoff ? 'delete' : nil
103
+ set :customrequest, onoff ? 'DELETE' : nil
85
104
  onoff
86
105
  end
87
- #
106
+ #
88
107
  # call-seq:
89
- #
108
+ #
90
109
  # easy = Curl::Easy.new("url")
110
+ # easy.version = Curl::HTTP_2_0
91
111
  # easy.version = Curl::HTTP_1_1
92
112
  # easy.version = Curl::HTTP_1_0
93
113
  # easy.version = Curl::HTTP_NONE
94
- #
114
+ #
95
115
  def version=(http_version)
96
116
  set :http_version, http_version
97
117
  end
98
118
 
99
- #
119
+ #
100
120
  # call-seq:
101
121
  # easy.url = "http://some.url/" => "http://some.url/"
102
- #
122
+ #
103
123
  # Set the URL for subsequent calls to +perform+. It is acceptable
104
124
  # (and even recommended) to reuse Curl::Easy instances by reassigning
105
125
  # the URL between calls to +perform+.
106
- #
126
+ #
107
127
  def url=(u)
108
128
  set :url, u
109
129
  end
110
130
 
111
- #
131
+ #
112
132
  # call-seq:
113
133
  # easy.proxy_url = string => string
114
- #
134
+ #
115
135
  # Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
116
136
  # The URL should specify the the host name or dotted IP address. To specify
117
137
  # port number in this string, append :[port] to the end of the host name.
118
138
  # The proxy string may be prefixed with [protocol]:// since any such prefix
119
139
  # will be ignored. The proxy's port number may optionally be specified with
120
140
  # the separate option proxy_port .
121
- #
141
+ #
122
142
  # When you tell the library to use an HTTP proxy, libcurl will transparently
123
143
  # convert operations to HTTP even if you specify an FTP URL etc. This may have
124
144
  # an impact on what other features of the library you can use, such as
125
145
  # FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
126
146
  # tunneling is activated with proxy_tunnel = true.
127
- #
147
+ #
128
148
  # libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
129
149
  # *all_proxy* etc, if any of those is set. The proxy_url option does however
130
150
  # override any possibly set environment variables.
131
- #
151
+ #
132
152
  # Starting with libcurl 7.14.1, the proxy host string given in environment
133
153
  # variables can be specified the exact same way as the proxy can be set with
134
154
  # proxy_url, including protocol prefix (http://) and embedded user + password.
@@ -143,89 +163,89 @@ module Curl
143
163
  self.ssl_verify_host_integer=value
144
164
  end
145
165
 
146
- #
166
+ #
147
167
  # call-seq:
148
168
  # easy.ssl_verify_host? => boolean
149
- #
169
+ #
150
170
  # Deprecated: call easy.ssl_verify_host instead
151
171
  # can be one of [0,1,2]
152
- #
172
+ #
153
173
  # Determine whether this Curl instance will verify that the server cert
154
174
  # is for the server it is known as.
155
- #
175
+ #
156
176
  def ssl_verify_host?
157
177
  ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
158
178
  end
159
179
 
160
- #
180
+ #
161
181
  # call-seq:
162
182
  # easy.interface = string => string
163
- #
183
+ #
164
184
  # Set the interface name to use as the outgoing network interface.
165
185
  # The name can be an interface name, an IP address or a host name.
166
- #
186
+ #
167
187
  def interface=(value)
168
188
  set :interface, value
169
189
  end
170
190
 
171
- #
191
+ #
172
192
  # call-seq:
173
193
  # easy.userpwd = string => string
174
- #
194
+ #
175
195
  # Set the username/password string to use for subsequent calls to +perform+.
176
196
  # The supplied string should have the form "username:password"
177
- #
197
+ #
178
198
  def userpwd=(value)
179
199
  set :userpwd, value
180
200
  end
181
201
 
182
- #
202
+ #
183
203
  # call-seq:
184
204
  # easy.proxypwd = string => string
185
- #
205
+ #
186
206
  # Set the username/password string to use for proxy connection during
187
207
  # subsequent calls to +perform+. The supplied string should have the
188
208
  # form "username:password"
189
- #
209
+ #
190
210
  def proxypwd=(value)
191
211
  set :proxyuserpwd, value
192
212
  end
193
213
 
194
- #
214
+ #
195
215
  # call-seq:
196
216
  # easy.cookies = "name1=content1; name2=content2;" => string
197
- #
217
+ #
198
218
  # Set cookies to be sent by this Curl::Easy instance. The format of the string should
199
219
  # be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
200
220
  # Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
201
- #
221
+ #
202
222
  def cookies=(value)
203
223
  set :cookie, value
204
224
  end
205
225
 
206
- #
226
+ #
207
227
  # call-seq:
208
228
  # easy.cookiefile = string => string
209
- #
229
+ #
210
230
  # Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
211
- #
231
+ #
212
232
  # *Note* that you must set enable_cookies true to enable the cookie
213
233
  # engine, or this option will be ignored.
214
- #
234
+ #
215
235
  def cookiefile=(value)
216
236
  set :cookiefile, value
217
237
  end
218
238
 
219
- #
239
+ #
220
240
  # call-seq:
221
241
  # easy.cookiejar = string => string
222
- #
242
+ #
223
243
  # Set a cookiejar file to use for this Curl::Easy instance.
224
244
  # Cookies from the response will be written into this file.
225
- #
245
+ #
226
246
  # *Note* that you must set enable_cookies true to enable the cookie
227
247
  # engine, or this option will be ignored.
228
- #
248
+ #
229
249
  def cookiejar=(value)
230
250
  set :cookiejar, value
231
251
  end
@@ -403,35 +423,35 @@ module Curl
403
423
  c.http_delete
404
424
  c
405
425
  end
406
-
426
+
407
427
  # call-seq:
408
428
  # Curl::Easy.download(url, filename = url.split(/\?/).first.split(/\//).last) { |curl| ... }
409
- #
429
+ #
410
430
  # Stream the specified url (via perform) and save the data directly to the
411
- # 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
412
432
  # usually be the filename most simple urls).
413
- #
433
+ #
414
434
  # If a block is supplied, it will be passed the curl instance prior to the
415
435
  # perform call.
416
- #
436
+ #
417
437
  # *Note* that the semantics of the on_body handler are subtly changed when using
418
- # 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
419
439
  # data string is passed to the handler *before* it is written
420
- # to the file, allowing the handler to perform mutative operations where
440
+ # to the file, allowing the handler to perform mutative operations where
421
441
  # necessary. As usual, the transfer will be aborted if the on_body handler
422
- # 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
423
443
  # offending chunk will *not* be written to the file, the file will be closed,
424
444
  # and a Curl::Err::AbortedByCallbackError will be raised.
425
445
  def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
426
446
  curl = Curl::Easy.new(url, &blk)
427
-
447
+
428
448
  output = if filename.is_a? IO
429
449
  filename.binmode if filename.respond_to?(:binmode)
430
450
  filename
431
451
  else
432
452
  File.open(filename, 'wb')
433
453
  end
434
-
454
+
435
455
  begin
436
456
  old_on_body = curl.on_body do |data|
437
457
  result = old_on_body ? old_on_body.call(data) : data.length
@@ -442,7 +462,7 @@ module Curl
442
462
  ensure
443
463
  output.close rescue IOError
444
464
  end
445
-
465
+
446
466
  return curl
447
467
  end
448
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,13 +1,16 @@
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
13
+ handle.reset
11
14
  handle.url = url
12
15
  handle.post_body = post_body if post_body
13
16
  handle.put_data = put_data if put_data
@@ -45,18 +48,21 @@ module Curl
45
48
  end
46
49
 
47
50
  def self.urlalize(url, params={})
48
- query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
49
- if url.match(/\?/)
50
- "#{url}&#{query_str}"
51
- elsif query_str.size > 0
52
- "#{url}?#{query_str}"
53
- else
54
- url
55
- 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
56
58
  end
57
59
 
58
60
  def self.postalize(params={})
59
61
  params.respond_to?(:map) ? URI.encode_www_form(params) : (params.respond_to?(:to_s) ? params.to_s : params)
60
62
  end
61
63
 
64
+ def self.reset
65
+ Thread.current[:curb_curl] = Curl::Easy.new
66
+ end
67
+
62
68
  end