curb 0.8.5 → 0.8.6
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/README.markdown +230 -0
- data/ext/curb.c +7 -0
- data/ext/curb.h +5 -9
- data/ext/curb_easy.c +34 -7
- data/ext/curb_errors.c +27 -16
- data/ext/curb_errors.h +8 -5
- data/ext/curb_multi.c +16 -10
- data/ext/extconf.rb +4 -17
- data/lib/curl.rb +2 -1
- data/lib/curl/easy.rb +69 -59
- data/tests/bug_crash_on_progress.rb +41 -1
- data/tests/bug_issue102.rb +17 -0
- data/tests/helper.rb +6 -1
- data/tests/tc_curl_download.rb +1 -1
- data/tests/tc_curl_easy.rb +11 -4
- data/tests/tc_curl_multi.rb +1 -1
- metadata +7 -5
- data/README +0 -194
data/ext/curb_errors.h
CHANGED
@@ -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
|
33
|
+
extern VALUE eCurlErrFTPWeirdReply;
|
34
34
|
extern VALUE eCurlErrFTPAccessDenied;
|
35
35
|
extern VALUE eCurlErrFTPBadPassword;
|
36
|
-
extern VALUE
|
37
|
-
extern VALUE
|
38
|
-
extern VALUE
|
39
|
-
extern VALUE
|
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;
|
data/ext/curb_multi.c
CHANGED
@@ -4,13 +4,17 @@
|
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
#include "curb_config.h"
|
7
|
-
#
|
8
|
-
|
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 &&
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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);
|
data/ext/extconf.rb
CHANGED
@@ -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')
|
data/lib/curl.rb
CHANGED
@@ -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)}=#{
|
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
|
data/lib/curl/easy.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
35
|
+
option = sym2curl(opt)
|
32
36
|
else
|
33
|
-
|
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 ? '
|
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
|