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.
@@ -0,0 +1,230 @@
1
+ # Curb - Libcurl bindings for Ruby
2
+
3
+ * [rubyforge rdoc](http://curb.rubyforge.org/)
4
+ * [rubyforge project](http://rubyforge.org/projects/curb)
5
+ * [github project](http://github.com/taf2/curb/tree/master)
6
+
7
+ Curb (probably CUrl-RuBy or something) provides Ruby-language bindings for the
8
+ libcurl(3), a fully-featured client-side URL transfer library.
9
+ cURL and libcurl live at [http://curl.haxx.se/](http://curl.haxx.se/) .
10
+
11
+ Curb is a work-in-progress, and currently only supports libcurl's 'easy' and 'multi' modes.
12
+
13
+ ## License
14
+
15
+ Curb is copyright (c)2006 Ross Bamford, and released under the terms of the
16
+ Ruby license. See the LICENSE file for the gory details.
17
+
18
+ ## You will need
19
+
20
+ * A working Ruby installation (1.8+, tested with 1.8.6, 1.8.7, 1.9.1, and 1.9.2)
21
+ * A working (lib)curl installation, with development stuff (7.5+, tested with 7.19.x)
22
+ * A sane build environment (e.g. gcc, make)
23
+
24
+ ## Installation...
25
+
26
+ ... will usually be as simple as:
27
+
28
+ $ gem install curb
29
+
30
+ Or, if you downloaded the archive:
31
+
32
+ $ rake install
33
+
34
+ If you have a weird setup, you might need extconf options. In this case, pass
35
+ them like so:
36
+
37
+ $ rake install EXTCONF_OPTS='--with-curl-dir=/path/to/libcurl --prefix=/what/ever'
38
+
39
+ Curb is tested only on GNU/Linux x86 and Mac OSX - YMMV on other platforms.
40
+ If you do use another platform and experience problems, or if you can
41
+ expand on the above instructions, please report the issue at http://github.com/taf2/curb/issues
42
+
43
+ On Ubuntu, the dependencies can be satisfied by installing the following packages:
44
+
45
+ $ sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev
46
+
47
+ Curb has fairly extensive RDoc comments in the source. You can build the
48
+ documentation with:
49
+
50
+ $ rake doc
51
+
52
+ ## Usage & examples
53
+
54
+ Curb provides two classes:
55
+
56
+ * `Curl::Easy` - simple API, for day-to-day tasks.
57
+ * `Curl::Multi` - more advanced API, for operating on multiple URLs simultaneously.
58
+
59
+ ### Super simple API (less typing)
60
+
61
+ ```ruby
62
+ http = Curl.get("http://www.google.com/")
63
+ puts http.body_str
64
+
65
+ http = Curl.post("http://www.google.com/", {:foo => "bar"})
66
+ puts http.body_str
67
+
68
+ http = Curl.get("http://www.google.com/") do|http|
69
+ http.headers['Cookie'] = 'foo=1;bar=2'
70
+ end
71
+ puts http.body_str
72
+ ```
73
+
74
+ ### Simple fetch via HTTP:
75
+
76
+ ```ruby
77
+ c = Curl::Easy.perform("http://www.google.co.uk")
78
+ puts c.body_str
79
+ ```
80
+
81
+ Same thing, more manual:
82
+
83
+ ```ruby
84
+ c = Curl::Easy.new("http://www.google.co.uk")
85
+ c.perform
86
+ puts c.body_str
87
+ ```
88
+
89
+ ### Additional config:
90
+
91
+ ```ruby
92
+ Curl::Easy.perform("http://www.google.co.uk") do |curl|
93
+ curl.headers["User-Agent"] = "myapp-0.0"
94
+ curl.verbose = true
95
+ end
96
+ ```
97
+
98
+ Same thing, more manual:
99
+
100
+ ```ruby
101
+ c = Curl::Easy.new("http://www.google.co.uk") do |curl|
102
+ curl.headers["User-Agent"] = "myapp-0.0"
103
+ curl.verbose = true
104
+ end
105
+
106
+ c.perform
107
+ ```
108
+
109
+ ### HTTP basic authentication:
110
+
111
+ ```ruby
112
+ c = Curl::Easy.new("http://github.com/")
113
+ c.http_auth_types = :basic
114
+ c.username = 'foo'
115
+ c.password = 'bar'
116
+ c.perform
117
+ ```
118
+
119
+ ### HTTP "insecure" SSL connections (like curl -k, --insecure) to avoid Curl::Err::SSLCACertificateError:
120
+
121
+ ```ruby
122
+ c = Curl::Easy.new("http://github.com/")
123
+ c.ssl_verify_peer = false
124
+ c.perform
125
+ ```
126
+
127
+ ### Supplying custom handlers:
128
+
129
+ ```ruby
130
+ c = Curl::Easy.new("http://www.google.co.uk")
131
+
132
+ c.on_body { |data| print(data) }
133
+ c.on_header { |data| print(data) }
134
+
135
+ c.perform
136
+ ```
137
+
138
+ ### Reusing Curls:
139
+
140
+ ```ruby
141
+ c = Curl::Easy.new
142
+
143
+ ["http://www.google.co.uk", "http://www.ruby-lang.org/"].map do |url|
144
+ c.url = url
145
+ c.perform
146
+ c.body_str
147
+ end
148
+ ```
149
+
150
+ ### HTTP POST form:
151
+
152
+ ```ruby
153
+ c = Curl::Easy.http_post("http://my.rails.box/thing/create",
154
+ Curl::PostField.content('thing[name]', 'box'),
155
+ Curl::PostField.content('thing[type]', 'storage'))
156
+ ```
157
+
158
+ ### HTTP POST file upload:
159
+
160
+ ```ruby
161
+ c = Curl::Easy.new("http://my.rails.box/files/upload")
162
+ c.multipart_form_post = true
163
+ c.http_post(Curl::PostField.file('thing[file]', 'myfile.rb'))
164
+ ```
165
+
166
+ ### Multi Interface (Basic HTTP GET):
167
+
168
+ ```ruby
169
+ # make multiple GET requests
170
+ easy_options = {:follow_location => true}
171
+ multi_options = {:pipeline => true}
172
+
173
+ Curl::Multi.get('url1','url2','url3','url4','url5', easy_options, multi_options) do|easy|
174
+ # do something interesting with the easy response
175
+ puts easy.last_effective_url
176
+ end
177
+ ```
178
+
179
+ ### Multi Interface (Basic HTTP POST):
180
+
181
+ ```ruby
182
+ # make multiple POST requests
183
+ easy_options = {:follow_location => true, :multipart_form_post => true}
184
+ multi_options = {:pipeline => true}
185
+
186
+ url_fields = [
187
+ { :url => 'url1', :post_fields => {'f1' => 'v1'} },
188
+ { :url => 'url2', :post_fields => {'f1' => 'v1'} },
189
+ { :url => 'url3', :post_fields => {'f1' => 'v1'} }
190
+ ]
191
+
192
+ Curl::Multi.post(url_fields, easy_options, multi_options) do|easy|
193
+ # do something interesting with the easy response
194
+ puts easy.last_effective_url
195
+ end
196
+ ```
197
+
198
+ ### Multi Interface (Advanced):
199
+
200
+ ```ruby
201
+ responses = {}
202
+ requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
203
+ m = Curl::Multi.new
204
+ # add a few easy handles
205
+ requests.each do |url|
206
+ responses[url] = ""
207
+ c = Curl::Easy.new(url) do|curl|
208
+ curl.follow_location = true
209
+ curl.on_body{|data| responses[url] << data; data.size }
210
+ curl.on_success {|easy| puts "success, add more easy handles" }
211
+ end
212
+ m.add(c)
213
+ end
214
+
215
+ m.perform do
216
+ puts "idling... can do some work here"
217
+ end
218
+
219
+ requests.each do|url|
220
+ puts responses[url]
221
+ end
222
+ ```
223
+
224
+ ### Easy Callbacks
225
+
226
+ * `on_success` is called when the response code is 2xx
227
+ * `on_redirect` is called when the response code is 3xx
228
+ * `on_missing` is called when the response code is 4xx
229
+ * `on_failure` is called when the response code is 5xx
230
+ * `on_complete` is called in all cases.
data/ext/curb.c CHANGED
@@ -304,6 +304,13 @@ void Init_curb_core() {
304
304
  rb_define_const(mCurl, "CURLPROXY_SOCKS4", INT2FIX(-2));
305
305
  #endif
306
306
 
307
+ /* When passed to Curl::Easy#proxy_type , indicates that the proxy is a SOCKS4A proxy. (libcurl >= 7.18.0) */
308
+ #ifdef HAVE_CURLPROXY_SOCKS4A
309
+ rb_define_const(mCurl, "CURLPROXY_SOCKS4A", INT2FIX(CURLPROXY_SOCKS4A));
310
+ #else
311
+ rb_define_const(mCurl, "CURLPROXY_SOCKS4A", INT2FIX(-2));
312
+ #endif
313
+
307
314
  /* When passed to Curl::Easy#proxy_type , indicates that the proxy is a SOCKS5 proxy. (libcurl >= 7.10) */
308
315
  #ifdef HAVE_CURLPROXY_SOCKS5
309
316
  rb_define_const(mCurl, "CURLPROXY_SOCKS5", INT2FIX(CURLPROXY_SOCKS5));
data/ext/curb.h CHANGED
@@ -20,11 +20,11 @@
20
20
  #include "curb_macros.h"
21
21
 
22
22
  // These should be managed from the Rake 'release' task.
23
- #define CURB_VERSION "0.8.5"
24
- #define CURB_VER_NUM 805
23
+ #define CURB_VERSION "0.8.6"
24
+ #define CURB_VER_NUM 806
25
25
  #define CURB_VER_MAJ 0
26
26
  #define CURB_VER_MIN 8
27
- #define CURB_VER_MIC 5
27
+ #define CURB_VER_MIC 6
28
28
  #define CURB_VER_PATCH 0
29
29
 
30
30
 
@@ -37,12 +37,8 @@
37
37
  #define RSTRING_PTR(x) RSTRING(x)->ptr
38
38
  #endif
39
39
 
40
- #ifndef RHASH_LEN
41
- #ifdef HAVE_RUBY19_HASH
42
- #define RHASH_LEN(hash) RHASH(hash)->ntbl->num_entries
43
- #else
44
- #define RHASH_LEN(hash) RHASH(hash)->tbl->num_entries
45
- #endif
40
+ #ifndef RHASH_SIZE
41
+ #define RHASH_SIZE(hash) RHASH(hash)->tbl->num_entries
46
42
  #endif
47
43
 
48
44
  extern VALUE mCurl;
@@ -96,6 +96,25 @@ static size_t read_data_handler(void *ptr,
96
96
  }
97
97
  }
98
98
 
99
+ int seek_data_handler(ruby_curl_easy *rbce,
100
+ curl_off_t offset,
101
+ int origin) {
102
+
103
+ VALUE upload = rb_easy_get("upload");
104
+ VALUE stream = ruby_curl_upload_stream_get(upload);
105
+
106
+ if (rb_respond_to(stream, rb_intern("seek"))) {
107
+ rb_funcall(stream, rb_intern("seek"), 2, SEEK_SET, offset);
108
+ } else {
109
+ ruby_curl_upload *rbcu;
110
+ Data_Get_Struct(upload, ruby_curl_upload, rbcu);
111
+ // This OK because curl only uses SEEK_SET as per the documentation
112
+ rbcu->offset = offset;
113
+ }
114
+
115
+ return 0;
116
+ }
117
+
99
118
  static size_t proc_data_handler(char *stream,
100
119
  size_t size,
101
120
  size_t nmemb,
@@ -772,7 +791,9 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
772
791
  curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
773
792
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
774
793
  curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
794
+ curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
775
795
  curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
796
+ curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
776
797
 
777
798
  /*
778
799
  * we need to set specific headers for the PUT to work... so
@@ -1637,9 +1658,10 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
1637
1658
  */
1638
1659
  static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
1639
1660
  ruby_curl_easy *rbce;
1661
+ unsigned short rm;
1640
1662
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1641
1663
 
1642
- unsigned short rm = rbce->resolve_mode;
1664
+ rm = rbce->resolve_mode;
1643
1665
 
1644
1666
  switch(rm) {
1645
1667
  case CURL_IPRESOLVE_V4:
@@ -1668,9 +1690,10 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
1668
1690
  return Qnil;
1669
1691
  } else {
1670
1692
  ruby_curl_easy *rbce;
1693
+ ID resolve_mode_id;
1671
1694
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1672
1695
 
1673
- ID resolve_mode_id = rb_to_id(resolve_mode);
1696
+ resolve_mode_id = rb_to_id(resolve_mode);
1674
1697
 
1675
1698
  if (resolve_mode_id == rb_intern("auto")) {
1676
1699
  rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
@@ -1850,10 +1873,10 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1850
1873
  */
1851
1874
  static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
1852
1875
  struct curl_slist **list;
1853
- Data_Get_Struct(wrap, struct curl_slist *, list);
1854
-
1855
1876
  VALUE header_str = Qnil;
1856
1877
 
1878
+ Data_Get_Struct(wrap, struct curl_slist *, list);
1879
+
1857
1880
  //rb_p(header);
1858
1881
 
1859
1882
  if (rb_type(header) == T_ARRAY) {
@@ -1882,9 +1905,10 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
1882
1905
  */
1883
1906
  static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
1884
1907
  struct curl_slist **list;
1908
+ VALUE ftp_command_string;
1885
1909
  Data_Get_Struct(wrap, struct curl_slist *, list);
1886
1910
 
1887
- VALUE ftp_command_string = rb_obj_as_string(ftp_command);
1911
+ ftp_command_string = rb_obj_as_string(ftp_command);
1888
1912
  *list = curl_slist_append(*list, StringValuePtr(ftp_command));
1889
1913
 
1890
1914
  return ftp_command_string;
@@ -3129,6 +3153,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3129
3153
  VALUE cookiejar = val;
3130
3154
  CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
3131
3155
  } break;
3156
+ case CURLOPT_TCP_NODELAY: {
3157
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, FIX2LONG(val));
3158
+ } break;
3132
3159
  case CURLOPT_RESUME_FROM: {
3133
3160
  curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, FIX2LONG(val));
3134
3161
  } break;
@@ -3141,7 +3168,7 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3141
3168
  } break;
3142
3169
  #endif
3143
3170
  default:
3144
- break;
3171
+ rb_raise(rb_eTypeError, "Curb unsupported option");
3145
3172
  }
3146
3173
 
3147
3174
  return val;
@@ -3247,7 +3274,7 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3247
3274
 
3248
3275
  /*
3249
3276
  * call-seq:
3250
- * Curl::Easy.error(code) => String
3277
+ * Curl::Easy.error(code) => [ErrCode, String]
3251
3278
  *
3252
3279
  * translate an internal libcurl error to ruby error class
3253
3280
  */
@@ -32,13 +32,13 @@ VALUE eCurlErrNotBuiltIn;
32
32
  VALUE eCurlErrProxyResolution;
33
33
  VALUE eCurlErrHostResolution;
34
34
  VALUE eCurlErrConnectFailed;
35
- VALUE eCurlErrFTPWierdReply;
35
+ VALUE eCurlErrFTPWeirdReply;
36
36
  VALUE eCurlErrFTPAccessDenied;
37
37
  VALUE eCurlErrFTPBadPassword;
38
- VALUE eCurlErrFTPWierdPassReply;
39
- VALUE eCurlErrFTPWierdUserReply;
40
- VALUE eCurlErrFTPWierdPasvReply;
41
- VALUE eCurlErrFTPWierd227Format;
38
+ VALUE eCurlErrFTPWeirdPassReply;
39
+ VALUE eCurlErrFTPWeirdUserReply;
40
+ VALUE eCurlErrFTPWeirdPasvReply;
41
+ VALUE eCurlErrFTPWeird227Format;
42
42
  VALUE eCurlErrFTPCantGetHost;
43
43
  VALUE eCurlErrFTPCantReconnect;
44
44
  VALUE eCurlErrFTPCouldntSetBinary;
@@ -118,6 +118,9 @@ VALUE mCurlErrBadEasyHandle;
118
118
  VALUE mCurlErrOutOfMemory;
119
119
  VALUE mCurlErrInternalError;
120
120
  VALUE mCurlErrBadSocket;
121
+ #if HAVE_CURLM_ADDED_ALREADY
122
+ VALUE mCurlErrAddedAlready;
123
+ #endif
121
124
  VALUE mCurlErrUnknownOption;
122
125
 
123
126
  /* binding errors */
@@ -161,7 +164,7 @@ VALUE rb_curl_easy_error(CURLcode code) {
161
164
  exclz = eCurlErrConnectFailed;
162
165
  break;
163
166
  case CURLE_FTP_WEIRD_SERVER_REPLY: /* 8 */
164
- exclz = eCurlErrFTPWierdReply;
167
+ exclz = eCurlErrFTPWeirdReply;
165
168
  break;
166
169
  case CURLE_FTP_ACCESS_DENIED: /* 9 denied due to lack of access. */
167
170
  exclz = eCurlErrFTPAccessDenied;
@@ -170,16 +173,16 @@ VALUE rb_curl_easy_error(CURLcode code) {
170
173
  exclz = eCurlErrFTPBadPassword;
171
174
  break;
172
175
  case CURLE_FTP_WEIRD_PASS_REPLY: /* 11 */
173
- exclz = eCurlErrFTPWierdPassReply;
176
+ exclz = eCurlErrFTPWeirdPassReply;
174
177
  break;
175
178
  case CURLE_FTP_WEIRD_USER_REPLY: /* 12 */
176
- exclz = eCurlErrFTPWierdUserReply;
179
+ exclz = eCurlErrFTPWeirdUserReply;
177
180
  break;
178
181
  case CURLE_FTP_WEIRD_PASV_REPLY: /* 13 */
179
- exclz = eCurlErrFTPWierdPasvReply;
182
+ exclz = eCurlErrFTPWeirdPasvReply;
180
183
  break;
181
184
  case CURLE_FTP_WEIRD_227_FORMAT: /* 14 */
182
- exclz = eCurlErrFTPWierd227Format;
185
+ exclz = eCurlErrFTPWeird227Format;
183
186
  break;
184
187
  case CURLE_FTP_CANT_GET_HOST: /* 15 */
185
188
  exclz = eCurlErrFTPCantGetHost;
@@ -492,6 +495,11 @@ VALUE rb_curl_multi_error(CURLMcode code) {
492
495
  case CURLM_UNKNOWN_OPTION: /* 6 */
493
496
  exclz = mCurlErrUnknownOption;
494
497
  break;
498
+ #endif
499
+ #if HAVE_CURLM_ADDED_ALREADY
500
+ case CURLM_ADDED_ALREADY: /* 7 */
501
+ exclz = mCurlErrAddedAlready;
502
+ break;
495
503
  #endif
496
504
  default:
497
505
  exclz = eCurlErrError;
@@ -535,13 +543,13 @@ void init_curb_errors() {
535
543
  eCurlErrHostResolution = rb_define_class_under(mCurlErr, "HostResolutionError", eCurlErrError);
536
544
  eCurlErrConnectFailed = rb_define_class_under(mCurlErr, "ConnectionFailedError", eCurlErrError);
537
545
 
538
- eCurlErrFTPWierdReply = rb_define_class_under(mCurlErr, "WierdReplyError", eCurlErrFTPError);
546
+ eCurlErrFTPWeirdReply = rb_define_class_under(mCurlErr, "WeirdReplyError", eCurlErrFTPError);
539
547
  eCurlErrFTPAccessDenied = rb_define_class_under(mCurlErr, "AccessDeniedError", eCurlErrFTPError);
540
- eCurlErrFTPBadPassword = rb_define_class_under(mCurlErr, "BadBasswordError", eCurlErrFTPError);
541
- eCurlErrFTPWierdPassReply = rb_define_class_under(mCurlErr, "WierdPassReplyError", eCurlErrFTPError);
542
- eCurlErrFTPWierdUserReply = rb_define_class_under(mCurlErr, "WierdUserReplyError", eCurlErrFTPError);
543
- eCurlErrFTPWierdPasvReply = rb_define_class_under(mCurlErr, "WierdPasvReplyError", eCurlErrFTPError);
544
- eCurlErrFTPWierd227Format = rb_define_class_under(mCurlErr, "Wierd227FormatError", eCurlErrFTPError);
548
+ eCurlErrFTPBadPassword = rb_define_class_under(mCurlErr, "BadPasswordError", eCurlErrFTPError);
549
+ eCurlErrFTPWeirdPassReply = rb_define_class_under(mCurlErr, "WeirdPassReplyError", eCurlErrFTPError);
550
+ eCurlErrFTPWeirdUserReply = rb_define_class_under(mCurlErr, "WeirdUserReplyError", eCurlErrFTPError);
551
+ eCurlErrFTPWeirdPasvReply = rb_define_class_under(mCurlErr, "WeirdPasvReplyError", eCurlErrFTPError);
552
+ eCurlErrFTPWeird227Format = rb_define_class_under(mCurlErr, "Weird227FormatError", eCurlErrFTPError);
545
553
  eCurlErrFTPCantGetHost = rb_define_class_under(mCurlErr, "CantGetHostError", eCurlErrFTPError);
546
554
  eCurlErrFTPCantReconnect = rb_define_class_under(mCurlErr, "CantReconnectError", eCurlErrFTPError);
547
555
  eCurlErrFTPCouldntSetBinary = rb_define_class_under(mCurlErr, "CouldntSetBinaryError", eCurlErrFTPError);
@@ -625,6 +633,9 @@ void init_curb_errors() {
625
633
  mCurlErrOutOfMemory = rb_define_class_under(mCurlErr, "MultiOutOfMemory", eCurlErrError);
626
634
  mCurlErrInternalError = rb_define_class_under(mCurlErr, "MultiInternalError", eCurlErrError);
627
635
  mCurlErrBadSocket = rb_define_class_under(mCurlErr, "MultiBadSocket", eCurlErrError);
636
+ #if HAVE_CURLM_ADDED_ALREADY
637
+ mCurlErrAddedAlready = rb_define_class_under(mCurlErr, "MultiAddedAlready", eCurlErrError);
638
+ #endif
628
639
  mCurlErrUnknownOption = rb_define_class_under(mCurlErr, "MultiUnknownOption", eCurlErrError);
629
640
 
630
641
  eCurlErrLDAPInvalidURL = rb_define_class_under(mCurlErr, "InvalidLDAPURLError", eCurlErrLDAPError);