curb 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);