curb 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,13 +30,13 @@ extern VALUE eCurlErrMalformedURLUser;
30
30
  extern VALUE eCurlErrProxyResolution;
31
31
  extern VALUE eCurlErrHostResolution;
32
32
  extern VALUE eCurlErrConnectFailed;
33
- extern VALUE eCurlErrFTPWierdReply;
33
+ extern VALUE eCurlErrFTPWeirdReply;
34
34
  extern VALUE eCurlErrFTPAccessDenied;
35
35
  extern VALUE eCurlErrFTPBadPassword;
36
- extern VALUE eCurlErrFTPWierdPassReply;
37
- extern VALUE eCurlErrFTPWierdUserReply;
38
- extern VALUE eCurlErrFTPWierdPasvReply;
39
- extern VALUE eCurlErrFTPWierd227Format;
36
+ extern VALUE eCurlErrFTPWeirdPassReply;
37
+ extern VALUE eCurlErrFTPWeirdUserReply;
38
+ extern VALUE eCurlErrFTPWeirdPasvReply;
39
+ extern VALUE eCurlErrFTPWeird227Format;
40
40
  extern VALUE eCurlErrFTPCantGetHost;
41
41
  extern VALUE eCurlErrFTPCantReconnect;
42
42
  extern VALUE eCurlErrFTPCouldntSetBinary;
@@ -116,6 +116,9 @@ extern VALUE mCurlErrOutOfMemory;
116
116
  extern VALUE mCurlErrInternalError;
117
117
  extern VALUE mCurlErrBadSocket;
118
118
  extern VALUE mCurlErrUnknownOption;
119
+ #if HAVE_CURLM_ADDED_ALREADY
120
+ extern VALUE mCurlErrAddedAlready;
121
+ #endif
119
122
 
120
123
  /* binding errors */
121
124
  extern VALUE eCurlErrInvalidPostField;
@@ -4,13 +4,17 @@
4
4
  *
5
5
  */
6
6
  #include "curb_config.h"
7
- #ifdef HAVE_RUBY19_ST_H
8
- #include <ruby.h>
7
+ #include <ruby.h>
8
+ #ifdef HAVE_RUBY_ST_H
9
9
  #include <ruby/st.h>
10
10
  #else
11
- #include <ruby.h>
12
11
  #include <st.h>
13
12
  #endif
13
+
14
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
15
+ #include <ruby/thread.h>
16
+ #endif
17
+
14
18
  #include "curb_easy.h"
15
19
  #include "curb_errors.h"
16
20
  #include "curb_postfield.h"
@@ -64,7 +68,7 @@ rb_hash_clear_i(VALUE key, VALUE value, VALUE dummy) {
64
68
 
65
69
  static void curl_multi_free(ruby_curl_multi *rbcm) {
66
70
 
67
- if (rbcm && !rbcm->requests == Qnil && rb_type(rbcm->requests) == T_HASH && RHASH_LEN(rbcm->requests) > 0) {
71
+ if (rbcm && !rbcm->requests == Qnil && rb_type(rbcm->requests) == T_HASH && RHASH_SIZE(rbcm->requests) > 0) {
68
72
 
69
73
  rb_hash_foreach( rbcm->requests, (int (*)())curl_multi_flush_easy, (VALUE)rbcm );
70
74
 
@@ -262,12 +266,9 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
262
266
  */
263
267
  VALUE ruby_curl_multi_remove(VALUE self, VALUE easy) {
264
268
  ruby_curl_multi *rbcm;
265
- ruby_curl_easy *rbce;
266
269
 
267
270
  Data_Get_Struct(self, ruby_curl_multi, rbcm);
268
271
 
269
- Data_Get_Struct(easy, ruby_curl_easy, rbce);
270
-
271
272
  rb_curl_multi_remove(rbcm,easy);
272
273
 
273
274
  return self;
@@ -471,7 +472,7 @@ void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
471
472
  }
472
473
  #endif
473
474
 
474
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
475
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
475
476
  struct _select_set {
476
477
  int maxfd;
477
478
  fd_set *fdread, *fdwrite, *fdexcep;
@@ -511,7 +512,7 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
511
512
  long timeout_milliseconds;
512
513
  struct timeval tv = {0, 0};
513
514
  VALUE block = Qnil;
514
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
515
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
515
516
  struct _select_set fdset_args;
516
517
  #endif
517
518
 
@@ -570,17 +571,22 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
570
571
  create_crt_fd(&fdexcep, &crt_fdexcep);
571
572
  #endif
572
573
 
573
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
574
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
574
575
  fdset_args.maxfd = maxfd+1;
575
576
  fdset_args.fdread = &fdread;
576
577
  fdset_args.fdwrite = &fdwrite;
577
578
  fdset_args.fdexcep = &fdexcep;
578
579
  fdset_args.tv = &tv;
580
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
581
+ rc = (int)(VALUE) rb_thread_call_without_gvl((void *(*)(void *))curb_select, &fdset_args, RUBY_UBF_IO, 0);
582
+ #elif HAVE_RB_THREAD_BLOCKING_REGION
579
583
  rc = rb_thread_blocking_region(curb_select, &fdset_args, RUBY_UBF_IO, 0);
580
584
  #else
581
585
  rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
582
586
  #endif
583
587
 
588
+ #endif
589
+
584
590
  #ifdef _WIN32
585
591
  cleanup_crt_fd(&fdread, &crt_fdread);
586
592
  cleanup_crt_fd(&fdwrite, &crt_fdwrite);
@@ -80,6 +80,7 @@ have_constant "curl_version_sspi"
80
80
  have_constant "curl_version_conv"
81
81
  have_constant "curlproxy_http"
82
82
  have_constant "curlproxy_socks4"
83
+ have_constant "curlproxy_socks4a"
83
84
  have_constant "curlproxy_socks5"
84
85
  have_constant "curlauth_basic"
85
86
  have_constant "curlauth_digest"
@@ -357,6 +358,8 @@ have_constant "curlopt_gssapi_delegation"
357
358
  have_constant "curlgssapi_delegation_policy_flag"
358
359
  have_constant "curlgssapi_delegation_flag"
359
360
 
361
+ have_constant "CURLM_ADDED_ALREADY"
362
+
360
363
  if try_compile('int main() { return 0; }','-Wall')
361
364
  $CFLAGS << ' -Wall'
362
365
  end
@@ -372,23 +375,6 @@ def test_for(name, const, src)
372
375
  end
373
376
  end
374
377
  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
378
 
393
379
  test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
394
380
  #include <curl/curl.h>
@@ -400,6 +386,7 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
400
386
  })
401
387
 
402
388
  have_func('rb_thread_blocking_region')
389
+ have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
403
390
 
404
391
  create_header('curb_config.h')
405
392
  create_makefile('curb_core')
@@ -2,6 +2,7 @@ require 'curb_core'
2
2
  require 'curl/easy'
3
3
  require 'curl/multi'
4
4
  require 'uri'
5
+ require 'cgi'
5
6
 
6
7
  # expose shortcut methods
7
8
  module Curl
@@ -46,7 +47,7 @@ module Curl
46
47
  end
47
48
 
48
49
  def self.urlalize(url, params={})
49
- query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
50
+ query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
50
51
  if url.match(/\?/)
51
52
  "#{url}&#{query_str}"
52
53
  elsif query_str.size > 0
@@ -6,31 +6,41 @@ module Curl
6
6
  alias body body_str
7
7
  alias head header_str
8
8
 
9
+ class Error < Exception
10
+ attr_accessor :message, :code
11
+ def initialize(code, msg)
12
+ self.message = msg
13
+ self.code = code
14
+ end
15
+ end
16
+
9
17
  #
10
18
  # call-seq:
11
19
  # easy.status => String
12
20
  #
13
21
  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(' ')
22
+ # Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF'
23
+ statuses = self.header_str.scan(/HTTP\/\d\.\d\s(\d+\s.+)\r\n/).map{ |match| match[0] }
24
+ statuses.last.strip
21
25
  end
22
26
 
23
27
  #
24
28
  # call-seq:
25
29
  # easy.set :sym|Fixnum, value
26
- #
30
+ #
27
31
  # set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
28
32
  #
29
33
  def set(opt,val)
30
34
  if opt.is_a?(Symbol)
31
- setopt(sym2curl(opt), val)
35
+ option = sym2curl(opt)
32
36
  else
33
- setopt(opt.to_i, val)
37
+ option = opt.to_i
38
+ end
39
+
40
+ begin
41
+ setopt(option, val)
42
+ rescue TypeError
43
+ raise TypeError, "Curb doesn't support setting #{opt} [##{option}] option"
34
44
  end
35
45
  end
36
46
 
@@ -58,8 +68,8 @@ module Curl
58
68
  ret = self.multi.perform
59
69
 
60
70
  if self.last_result != 0 && self.on_failure.nil?
61
- error = Curl::Easy.error(self.last_result)
62
- raise error.first
71
+ error = Curl::Easy.error(self.last_result)
72
+ raise error.first.new(error.last)
63
73
  end
64
74
 
65
75
  ret
@@ -83,54 +93,54 @@ module Curl
83
93
  # easy.perform
84
94
  #
85
95
  def delete=(onoff)
86
- set :customrequest, onoff ? 'delete' : nil
96
+ set :customrequest, onoff ? 'DELETE' : nil
87
97
  onoff
88
98
  end
89
- #
99
+ #
90
100
  # call-seq:
91
- #
101
+ #
92
102
  # easy = Curl::Easy.new("url")
93
103
  # easy.version = Curl::HTTP_1_1
94
104
  # easy.version = Curl::HTTP_1_0
95
105
  # easy.version = Curl::HTTP_NONE
96
- #
106
+ #
97
107
  def version=(http_version)
98
108
  set :http_version, http_version
99
109
  end
100
110
 
101
- #
111
+ #
102
112
  # call-seq:
103
113
  # easy.url = "http://some.url/" => "http://some.url/"
104
- #
114
+ #
105
115
  # Set the URL for subsequent calls to +perform+. It is acceptable
106
116
  # (and even recommended) to reuse Curl::Easy instances by reassigning
107
117
  # the URL between calls to +perform+.
108
- #
118
+ #
109
119
  def url=(u)
110
120
  set :url, u
111
121
  end
112
122
 
113
- #
123
+ #
114
124
  # call-seq:
115
125
  # easy.proxy_url = string => string
116
- #
126
+ #
117
127
  # Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
118
128
  # The URL should specify the the host name or dotted IP address. To specify
119
129
  # port number in this string, append :[port] to the end of the host name.
120
130
  # The proxy string may be prefixed with [protocol]:// since any such prefix
121
131
  # will be ignored. The proxy's port number may optionally be specified with
122
132
  # the separate option proxy_port .
123
- #
133
+ #
124
134
  # When you tell the library to use an HTTP proxy, libcurl will transparently
125
135
  # convert operations to HTTP even if you specify an FTP URL etc. This may have
126
136
  # an impact on what other features of the library you can use, such as
127
137
  # FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
128
138
  # tunneling is activated with proxy_tunnel = true.
129
- #
139
+ #
130
140
  # libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
131
141
  # *all_proxy* etc, if any of those is set. The proxy_url option does however
132
142
  # override any possibly set environment variables.
133
- #
143
+ #
134
144
  # Starting with libcurl 7.14.1, the proxy host string given in environment
135
145
  # variables can be specified the exact same way as the proxy can be set with
136
146
  # proxy_url, including protocol prefix (http://) and embedded user + password.
@@ -145,89 +155,89 @@ module Curl
145
155
  self.ssl_verify_host_integer=value
146
156
  end
147
157
 
148
- #
158
+ #
149
159
  # call-seq:
150
160
  # easy.ssl_verify_host? => boolean
151
- #
161
+ #
152
162
  # Deprecated: call easy.ssl_verify_host instead
153
163
  # can be one of [0,1,2]
154
- #
164
+ #
155
165
  # Determine whether this Curl instance will verify that the server cert
156
166
  # is for the server it is known as.
157
- #
167
+ #
158
168
  def ssl_verify_host?
159
169
  ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
160
170
  end
161
171
 
162
- #
172
+ #
163
173
  # call-seq:
164
174
  # easy.interface = string => string
165
- #
175
+ #
166
176
  # Set the interface name to use as the outgoing network interface.
167
177
  # The name can be an interface name, an IP address or a host name.
168
- #
178
+ #
169
179
  def interface=(value)
170
180
  set :interface, value
171
181
  end
172
182
 
173
- #
183
+ #
174
184
  # call-seq:
175
185
  # easy.userpwd = string => string
176
- #
186
+ #
177
187
  # Set the username/password string to use for subsequent calls to +perform+.
178
188
  # The supplied string should have the form "username:password"
179
- #
189
+ #
180
190
  def userpwd=(value)
181
191
  set :userpwd, value
182
192
  end
183
193
 
184
- #
194
+ #
185
195
  # call-seq:
186
196
  # easy.proxypwd = string => string
187
- #
197
+ #
188
198
  # Set the username/password string to use for proxy connection during
189
199
  # subsequent calls to +perform+. The supplied string should have the
190
200
  # form "username:password"
191
- #
201
+ #
192
202
  def proxypwd=(value)
193
203
  set :proxyuserpwd, value
194
204
  end
195
205
 
196
- #
206
+ #
197
207
  # call-seq:
198
208
  # easy.cookies = "name1=content1; name2=content2;" => string
199
- #
209
+ #
200
210
  # Set cookies to be sent by this Curl::Easy instance. The format of the string should
201
211
  # be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
202
212
  # Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
203
- #
213
+ #
204
214
  def cookies=(value)
205
215
  set :cookie, value
206
216
  end
207
217
 
208
- #
218
+ #
209
219
  # call-seq:
210
220
  # easy.cookiefile = string => string
211
- #
221
+ #
212
222
  # Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
213
- #
223
+ #
214
224
  # *Note* that you must set enable_cookies true to enable the cookie
215
225
  # engine, or this option will be ignored.
216
- #
226
+ #
217
227
  def cookiefile=(value)
218
228
  set :cookiefile, value
219
229
  end
220
230
 
221
- #
231
+ #
222
232
  # call-seq:
223
233
  # easy.cookiejar = string => string
224
- #
234
+ #
225
235
  # Set a cookiejar file to use for this Curl::Easy instance.
226
236
  # Cookies from the response will be written into this file.
227
- #
237
+ #
228
238
  # *Note* that you must set enable_cookies true to enable the cookie
229
239
  # engine, or this option will be ignored.
230
- #
240
+ #
231
241
  def cookiejar=(value)
232
242
  set :cookiejar, value
233
243
  end
@@ -405,35 +415,35 @@ module Curl
405
415
  c.http_delete
406
416
  c
407
417
  end
408
-
418
+
409
419
  # call-seq:
410
420
  # Curl::Easy.download(url, filename = url.split(/\?/).first.split(/\//).last) { |curl| ... }
411
- #
421
+ #
412
422
  # 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
423
+ # supplied filename (defaults to the last component of the URL path, which will
414
424
  # usually be the filename most simple urls).
415
- #
425
+ #
416
426
  # If a block is supplied, it will be passed the curl instance prior to the
417
427
  # perform call.
418
- #
428
+ #
419
429
  # *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
430
+ # download, to account for the automatic routing of data to the specified file: The
421
431
  # data string is passed to the handler *before* it is written
422
- # to the file, allowing the handler to perform mutative operations where
432
+ # to the file, allowing the handler to perform mutative operations where
423
433
  # 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
434
+ # returns a size that differs from the data chunk size - in this case, the
425
435
  # offending chunk will *not* be written to the file, the file will be closed,
426
436
  # and a Curl::Err::AbortedByCallbackError will be raised.
427
437
  def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
428
438
  curl = Curl::Easy.new(url, &blk)
429
-
439
+
430
440
  output = if filename.is_a? IO
431
441
  filename.binmode if filename.respond_to?(:binmode)
432
442
  filename
433
443
  else
434
444
  File.open(filename, 'wb')
435
445
  end
436
-
446
+
437
447
  begin
438
448
  old_on_body = curl.on_body do |data|
439
449
  result = old_on_body ? old_on_body.call(data) : data.length
@@ -444,7 +454,7 @@ module Curl
444
454
  ensure
445
455
  output.close rescue IOError
446
456
  end
447
-
457
+
448
458
  return curl
449
459
  end
450
460
  end