arachni-typhoeus 0.2.0

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.
Files changed (55) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.markdown +43 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +30 -0
  5. data/README.textile +6 -0
  6. data/Rakefile +40 -0
  7. data/VERSION +1 -0
  8. data/benchmarks/profile.rb +25 -0
  9. data/benchmarks/vs_nethttp.rb +35 -0
  10. data/examples/twitter.rb +21 -0
  11. data/ext/typhoeus/.gitignore +7 -0
  12. data/ext/typhoeus/extconf.rb +65 -0
  13. data/ext/typhoeus/native.c +11 -0
  14. data/ext/typhoeus/native.h +21 -0
  15. data/ext/typhoeus/typhoeus_easy.c +220 -0
  16. data/ext/typhoeus/typhoeus_easy.h +19 -0
  17. data/ext/typhoeus/typhoeus_multi.c +211 -0
  18. data/ext/typhoeus/typhoeus_multi.h +16 -0
  19. data/lib/typhoeus.rb +58 -0
  20. data/lib/typhoeus/.gitignore +1 -0
  21. data/lib/typhoeus/easy.rb +366 -0
  22. data/lib/typhoeus/filter.rb +28 -0
  23. data/lib/typhoeus/hydra.rb +245 -0
  24. data/lib/typhoeus/hydra/callbacks.rb +24 -0
  25. data/lib/typhoeus/hydra/connect_options.rb +61 -0
  26. data/lib/typhoeus/hydra/stubbing.rb +52 -0
  27. data/lib/typhoeus/hydra_mock.rb +131 -0
  28. data/lib/typhoeus/multi.rb +37 -0
  29. data/lib/typhoeus/normalized_header_hash.rb +58 -0
  30. data/lib/typhoeus/remote.rb +306 -0
  31. data/lib/typhoeus/remote_method.rb +108 -0
  32. data/lib/typhoeus/remote_proxy_object.rb +50 -0
  33. data/lib/typhoeus/request.rb +210 -0
  34. data/lib/typhoeus/response.rb +91 -0
  35. data/lib/typhoeus/service.rb +20 -0
  36. data/lib/typhoeus/utils.rb +24 -0
  37. data/profilers/valgrind.rb +24 -0
  38. data/spec/fixtures/result_set.xml +60 -0
  39. data/spec/servers/app.rb +84 -0
  40. data/spec/spec.opts +2 -0
  41. data/spec/spec_helper.rb +11 -0
  42. data/spec/typhoeus/easy_spec.rb +284 -0
  43. data/spec/typhoeus/filter_spec.rb +35 -0
  44. data/spec/typhoeus/hydra_mock_spec.rb +300 -0
  45. data/spec/typhoeus/hydra_spec.rb +526 -0
  46. data/spec/typhoeus/multi_spec.rb +74 -0
  47. data/spec/typhoeus/normalized_header_hash_spec.rb +41 -0
  48. data/spec/typhoeus/remote_method_spec.rb +141 -0
  49. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  50. data/spec/typhoeus/remote_spec.rb +695 -0
  51. data/spec/typhoeus/request_spec.rb +276 -0
  52. data/spec/typhoeus/response_spec.rb +151 -0
  53. data/spec/typhoeus/utils_spec.rb +22 -0
  54. data/typhoeus.gemspec +123 -0
  55. metadata +196 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .*.sw?
2
+ *.gem
3
+ .bundle
@@ -0,0 +1,43 @@
1
+ Current Master
2
+ --------------
3
+ * Added extended proxy support [Zapotek, GH-46]
4
+ * eliminated compile time warnings by using proper type declarations [skaes, GH-54]
5
+ * fixed broken calls to rb_raise [skaes, GH-54]
6
+ * prevent leaking of curl easy handles when exceptions are raised (either from typhoeus itself or user callbacks) [skaes, GH-54]
7
+ * fixed Easy#timed_out? using curl return codes [skaes, GH-54]
8
+ * provide curl return codes and corresponding curl error messages on classes Easy and Request [skaes, GH-54]
9
+ * allow VCR to whitelist hosts in Typhoeus stubbing/mocking [myronmarston, GH-57]
10
+ * added timed_out? documentation, method to Response [dbalatero, GH-34]
11
+ * added abort to Hydra to prematurely stop a hydra.run [Zapotek]
12
+
13
+ 0.2.0
14
+ ------
15
+ * Fix warning in Request#headers from attr_accessor
16
+ * Params with array values were not parsing into the format that rack expects
17
+ [GH-39, smartocci]
18
+ * Removed Rack as a dependency [GH-45]
19
+ * Added integration hooks for VCR!
20
+
21
+ 0.1.31
22
+ ------
23
+ * Fixed bug in setting compression encoding [morhekil]
24
+ * Exposed authentication control methods through Request interface [morhekil]
25
+
26
+ 0.1.30
27
+ -----------
28
+ * Exposed CURLOPT_CONNECTTIMEOUT_MS to Requests [balexis]
29
+
30
+ 0.1.29
31
+ ------
32
+ * Fixed a memory corruption with using CURLOPT_POSTFIELDS [gravis,
33
+ 32531d0821aecc4]
34
+
35
+ 0.1.28
36
+ ----------------
37
+ * Added SSL cert options for Typhoeus::Easy [GH-25, gravis]
38
+ * Ported SSL cert options to Typhoeus::Request interface [gravis]
39
+ * Added support for any HTTP method (purge for Varnish) [ryana]
40
+
41
+ 0.1.27
42
+ ------
43
+ * Added rack as dependency, added dev dependencies to Rakefile [GH-21]
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ group :test do
4
+ gem 'rspec', '1.3.1'
5
+ gem 'jeweler'
6
+ gem 'json'
7
+ gem 'sinatra'
8
+ gem 'diff-lcs'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ gemcutter (0.6.1)
6
+ git (1.2.5)
7
+ jeweler (1.4.0)
8
+ gemcutter (>= 0.1.0)
9
+ git (>= 1.2.5)
10
+ rubyforge (>= 2.0.0)
11
+ json (1.4.6)
12
+ json_pure (1.4.6)
13
+ rack (1.2.1)
14
+ rspec (1.3.1)
15
+ rubyforge (2.0.4)
16
+ json_pure (>= 1.1.7)
17
+ sinatra (1.1.0)
18
+ rack (~> 1.1)
19
+ tilt (~> 1.1)
20
+ tilt (1.1)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ diff-lcs
27
+ jeweler
28
+ json
29
+ rspec (= 1.3.1)
30
+ sinatra
data/README.textile ADDED
@@ -0,0 +1,6 @@
1
+ h1. Info
2
+
3
+ This branch holds the Arachni sanctioned version of Typhoeus.
4
+ Typhoeus 0.2.1 doesn't agree with Arachni on some matters so the gem built using this branch remedies the situation.
5
+
6
+ Original Typhoeus repo @ https://github.com/dbalatero/typhoeus
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require "spec"
4
+ require "spec/rake/spectask"
5
+ require 'lib/typhoeus'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gemspec|
10
+ gemspec.name = "arachni-typhoeus"
11
+ gemspec.summary = "Typhoeus gem tailored for Arachni."
12
+ gemspec.description = "Original @ https://github.com/dbalatero/typhoeus."
13
+ gemspec.email = "tasos.laskos@gmail.com"
14
+ gemspec.homepage = "https://github.com/Zapotek/typhoeus/tree/arachni-typhoeus"
15
+ gemspec.authors = ["Paul Dix", "Tasos Laskos"]
16
+ gemspec.add_development_dependency "rspec"
17
+ gemspec.add_development_dependency "jeweler"
18
+ gemspec.add_development_dependency "diff-lcs"
19
+ gemspec.add_development_dependency "sinatra"
20
+ gemspec.add_development_dependency "json"
21
+ end
22
+
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler not available. Install it with: gem install jeweler"
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new do |t|
29
+ t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
30
+ t.spec_files = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ task :install do
34
+ rm_rf "*.gem"
35
+ puts `gem build typhoeus.gemspec`
36
+ puts `sudo gem install typhoeus-#{Typhoeus::VERSION}.gem`
37
+ end
38
+
39
+ desc "Run all the tests"
40
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../lib/typhoeus.rb'
2
+ require 'rubygems'
3
+ require 'ruby-prof'
4
+
5
+ calls = 20
6
+ @klass = Class.new do
7
+ include Typhoeus
8
+ end
9
+
10
+ Typhoeus.init_easy_objects
11
+
12
+ RubyProf.start
13
+
14
+ responses = []
15
+ calls.times do |i|
16
+ responses << @klass.get("http://127.0.0.1:3000/#{i}")
17
+ end
18
+
19
+ responses.each {|r| }#raise unless r.response_body == "whatever"}
20
+
21
+ result = RubyProf.stop
22
+
23
+ # Print a flat profile to text
24
+ printer = RubyProf::FlatPrinter.new(result)
25
+ printer.print(STDOUT, 0)
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require File.dirname(__FILE__) + '/../lib/typhoeus.rb'
3
+ require 'open-uri'
4
+ require 'benchmark'
5
+ include Benchmark
6
+
7
+
8
+ calls = 20
9
+ @klass = Class.new do
10
+ include Typhoeus
11
+ end
12
+
13
+ Typhoeus.init_easy_object_pool
14
+
15
+ benchmark do |t|
16
+ t.report("net::http") do
17
+ responses = []
18
+
19
+ calls.times do |i|
20
+ responses << open("http://127.0.0.1:3000/#{i}").read
21
+ end
22
+
23
+ responses.each {|r| raise unless r == "whatever"}
24
+ end
25
+
26
+ t.report("typhoeus") do
27
+ responses = []
28
+
29
+ calls.times do |i|
30
+ responses << @klass.get("http://127.0.0.1:3000/#{i}")
31
+ end
32
+
33
+ responses.each {|r| raise unless r.body == "whatever"}
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require File.dirname(__FILE__) + '/../lib/typhoeus.rb'
3
+ require 'json'
4
+
5
+ class Twitter
6
+ include Typhoeus
7
+ remote_defaults :on_success => lambda {|response| JSON.parse(response.body)},
8
+ :on_failure => lambda {|response| puts "error code: #{response.code}"},
9
+ :base_uri => "http://search.twitter.com"
10
+
11
+ define_remote_method :search, :path => '/search.json'
12
+ define_remote_method :trends, :path => '/trends/:time_frame.json'
13
+ end
14
+
15
+ tweets = Twitter.search(:params => {:q => "railsconf"})
16
+ trends = Twitter.trends(:time_frame => :current)
17
+
18
+ # and then the calls don't actually happen until the first time you
19
+ # call a method on one of the objects returned from the remote_method
20
+
21
+ puts tweets.keys # it's a hash from parsed JSON
@@ -0,0 +1,7 @@
1
+ conftest.dSYM/*
2
+ conftest.dSYM
3
+ mkmf.log
4
+ *.o
5
+ native.bundle
6
+ Makefile
7
+ *.bundle
@@ -0,0 +1,65 @@
1
+ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
+
3
+ # :stopdoc:
4
+
5
+ require 'mkmf'
6
+
7
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
8
+ specified_curl = ARGV[0] =~ /^--with-curl/ ? ARGV[0].split("=")[1] : nil
9
+ LIBDIR = specified_curl ? "#{specified_curl}/lib": Config::CONFIG['libdir']
10
+ INCLUDEDIR = specified_curl ? "#{specified_curl}/include" : Config::CONFIG['includedir']
11
+
12
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'macruby'
13
+ $LIBRUBYARG_STATIC.gsub!(/-static/, '')
14
+ end
15
+
16
+ $CFLAGS << " #{ENV["CFLAGS"]}"
17
+ if Config::CONFIG['target_os'] == 'mingw32'
18
+ $CFLAGS << " -DXP_WIN -DXP_WIN32 -DUSE_INCLUDED_VASPRINTF"
19
+ elsif Config::CONFIG['target_os'] == 'solaris2'
20
+ $CFLAGS << " -DUSE_INCLUDED_VASPRINTF"
21
+ else
22
+ $CFLAGS << " -g -DXP_UNIX"
23
+ end
24
+
25
+ use_macports = !(defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby')
26
+ $LIBPATH << "/opt/local/lib" if use_macports
27
+
28
+ $CFLAGS << " -O3 -Wall -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline"
29
+
30
+ if Config::CONFIG['target_os'] == 'mingw32'
31
+ header = File.join(ROOT, 'cross', 'curl-7.19.4.win32', 'include')
32
+ unless find_header('curl/curl.h', header)
33
+ abort "need libcurl"
34
+ end
35
+ else
36
+ HEADER_DIRS = [
37
+ File.join(INCLUDEDIR, "curl"),
38
+ INCLUDEDIR,
39
+ '/usr/include/curl',
40
+ '/usr/local/include/curl'
41
+ ]
42
+
43
+ [
44
+ '/opt/local/include/curl',
45
+ '/opt/local/include',
46
+ ].each { |x| HEADER_DIRS.unshift(x) } if use_macports
47
+
48
+ unless find_header('curl/curl.h', *HEADER_DIRS)
49
+ abort "need libcurl"
50
+ end
51
+ end
52
+
53
+ if Config::CONFIG['target_os'] == 'mingw32'
54
+ find_library('curl', 'curl_easy_init',
55
+ File.join(ROOT, 'cross', 'curl-7.19.4.win32', 'bin'))
56
+ else
57
+ find_library('curl', 'curl_easy_init',
58
+ LIBDIR,
59
+ '/opt/local/lib',
60
+ '/usr/local/lib',
61
+ '/usr/lib'
62
+ )
63
+ end
64
+
65
+ create_makefile("typhoeus/native")
@@ -0,0 +1,11 @@
1
+ #include <native.h>
2
+
3
+ VALUE mTyphoeus;
4
+
5
+ void Init_native()
6
+ {
7
+ mTyphoeus = rb_const_get(rb_cObject, rb_intern("Typhoeus"));
8
+
9
+ init_typhoeus_easy();
10
+ init_typhoeus_multi();
11
+ }
@@ -0,0 +1,21 @@
1
+ #ifndef TYPHOEUS_NATIVE
2
+ #define TYPHOEUS_NATIVE
3
+
4
+ #include <ruby.h>
5
+ #include <curl/curl.h>
6
+ #include <curl/easy.h>
7
+ #include <curl/multi.h>
8
+
9
+ void Init_native();
10
+ extern VALUE mTyphoeus;
11
+ extern void init_typhoeus_easy();
12
+ extern void init_typhoeus_multi();
13
+
14
+ #endif
15
+
16
+ #ifndef RSTRING_PTR
17
+
18
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
19
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
20
+
21
+ #endif
@@ -0,0 +1,220 @@
1
+ #include <typhoeus_easy.h>
2
+
3
+ static VALUE idAppend;
4
+ VALUE cTyphoeusEasy;
5
+
6
+ static void dealloc(CurlEasy *curl_easy) {
7
+ if (curl_easy->request_chunk != NULL) {
8
+ free(curl_easy->request_chunk);
9
+ }
10
+
11
+ if (curl_easy->headers != NULL) {
12
+ curl_slist_free_all(curl_easy->headers);
13
+ }
14
+
15
+ curl_easy_cleanup(curl_easy->curl);
16
+
17
+ free(curl_easy);
18
+ }
19
+
20
+ static VALUE easy_setopt_string(VALUE self, VALUE opt_name, VALUE parameter) {
21
+ CurlEasy *curl_easy;
22
+ Data_Get_Struct(self, CurlEasy, curl_easy);
23
+
24
+ CURLoption opt = NUM2LONG(opt_name);
25
+ curl_easy_setopt(curl_easy->curl, opt, StringValuePtr(parameter));
26
+ return opt_name;
27
+ }
28
+
29
+ static VALUE easy_setopt_long(VALUE self, VALUE opt_name, VALUE parameter) {
30
+ CurlEasy *curl_easy;
31
+ Data_Get_Struct(self, CurlEasy, curl_easy);
32
+
33
+ CURLoption opt = NUM2LONG(opt_name);
34
+ curl_easy_setopt(curl_easy->curl, opt, NUM2LONG(parameter));
35
+ return opt_name;
36
+ }
37
+
38
+ static VALUE easy_getinfo_string(VALUE self, VALUE info) {
39
+ char *info_string;
40
+ CurlEasy *curl_easy;
41
+ Data_Get_Struct(self, CurlEasy, curl_easy);
42
+
43
+ CURLoption opt = NUM2LONG(info);
44
+ curl_easy_getinfo(curl_easy->curl, opt, &info_string);
45
+
46
+ return rb_str_new2(info_string);
47
+ }
48
+
49
+ static VALUE easy_getinfo_long(VALUE self, VALUE info) {
50
+ long info_long;
51
+ CurlEasy *curl_easy;
52
+ Data_Get_Struct(self, CurlEasy, curl_easy);
53
+
54
+ CURLoption opt = NUM2LONG(info);
55
+ curl_easy_getinfo(curl_easy->curl, opt, &info_long);
56
+
57
+ return LONG2NUM(info_long);
58
+ }
59
+
60
+ static VALUE easy_getinfo_double(VALUE self, VALUE info) {
61
+ double info_double = 0;
62
+ CurlEasy *curl_easy;
63
+ Data_Get_Struct(self, CurlEasy, curl_easy);
64
+
65
+ CURLoption opt = NUM2LONG(info);
66
+ curl_easy_getinfo(curl_easy->curl, opt, &info_double);
67
+
68
+ return rb_float_new(info_double);
69
+ }
70
+
71
+ static VALUE easy_perform(VALUE self) {
72
+ CurlEasy *curl_easy;
73
+ CURLcode return_code;
74
+ Data_Get_Struct(self, CurlEasy, curl_easy);
75
+ return_code = curl_easy_perform(curl_easy->curl);
76
+ rb_iv_set(self, "@curl_return_code", INT2FIX(return_code));
77
+
78
+ return Qnil;
79
+ }
80
+
81
+ static size_t write_data_handler(char *stream, size_t size, size_t nmemb, VALUE val) {
82
+ long stream_size = (long)(size * nmemb);
83
+ rb_funcall(val, idAppend, 1, rb_str_new(stream, stream_size));
84
+ return size * nmemb;
85
+ }
86
+
87
+ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *data) {
88
+ size_t realsize = size * nmemb;
89
+ RequestChunk *mem = (RequestChunk *)data;
90
+
91
+ if (realsize > mem->size - mem->read) {
92
+ realsize = mem->size - mem->read;
93
+ }
94
+
95
+ if (realsize != 0) {
96
+ memcpy(ptr, &(mem->memory[mem->read]), realsize);
97
+ mem->read += realsize;
98
+ }
99
+
100
+ return realsize;
101
+ }
102
+
103
+ static void set_response_handlers(VALUE easy, CURL *curl) {
104
+ rb_iv_set(easy, "@response_body", rb_str_new2(""));
105
+ rb_iv_set(easy, "@response_header", rb_str_new2(""));
106
+
107
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&write_data_handler);
108
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rb_iv_get(easy, "@response_body"));
109
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&write_data_handler);
110
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rb_iv_get(easy, "@response_header"));
111
+ }
112
+
113
+ static VALUE easy_reset(VALUE self) {
114
+ CurlEasy *curl_easy;
115
+ Data_Get_Struct(self, CurlEasy, curl_easy);
116
+
117
+ if (curl_easy->request_chunk != NULL) {
118
+ free(curl_easy->request_chunk);
119
+ curl_easy->request_chunk = NULL;
120
+ }
121
+
122
+ if (curl_easy->headers != NULL) {
123
+ curl_slist_free_all(curl_easy->headers);
124
+ curl_easy->headers = NULL;
125
+ }
126
+
127
+ curl_easy_reset(curl_easy->curl);
128
+
129
+ set_response_handlers(self, curl_easy->curl);
130
+
131
+ return Qnil;
132
+ }
133
+
134
+ static VALUE easy_add_header(VALUE self, VALUE header) {
135
+ CurlEasy *curl_easy;
136
+ Data_Get_Struct(self, CurlEasy, curl_easy);
137
+
138
+ curl_easy->headers = curl_slist_append(curl_easy->headers, RSTRING_PTR(header));
139
+ return header;
140
+ }
141
+
142
+ static VALUE easy_set_headers(VALUE self) {
143
+ CurlEasy *curl_easy;
144
+ Data_Get_Struct(self, CurlEasy, curl_easy);
145
+
146
+ curl_easy_setopt(curl_easy->curl, CURLOPT_HTTPHEADER, curl_easy->headers);
147
+
148
+ return Qnil;
149
+ }
150
+
151
+ static VALUE easy_set_request_body(VALUE self, VALUE data, VALUE content_length_header) {
152
+ CurlEasy *curl_easy;
153
+ Data_Get_Struct(self, CurlEasy, curl_easy);
154
+
155
+ curl_easy->request_chunk = ALLOC(RequestChunk);
156
+ curl_easy->request_chunk->size = RSTRING_LEN(data);
157
+ curl_easy->request_chunk->memory = StringValuePtr(data);
158
+ curl_easy->request_chunk->read = 0;
159
+
160
+ curl_easy_setopt(curl_easy->curl, CURLOPT_READFUNCTION, (curl_read_callback)read_callback);
161
+ curl_easy_setopt(curl_easy->curl, CURLOPT_READDATA, curl_easy->request_chunk);
162
+ curl_easy_setopt(curl_easy->curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
163
+
164
+ return Qnil;
165
+ }
166
+
167
+ static VALUE easy_escape(VALUE self, VALUE data, VALUE length) {
168
+ CurlEasy *curl_easy;
169
+ Data_Get_Struct(self, CurlEasy, curl_easy);
170
+
171
+ return rb_str_new2(curl_easy_escape(curl_easy->curl, StringValuePtr(data), (int)NUM2INT(length)));
172
+ }
173
+
174
+ static VALUE version(VALUE self) {
175
+ return rb_str_new2(curl_version());
176
+ }
177
+
178
+ static VALUE new(int argc, VALUE *argv, VALUE klass) {
179
+ CURL *curl = curl_easy_init();
180
+ CurlEasy *curl_easy = ALLOC(CurlEasy);
181
+ curl_easy->curl = curl;
182
+ curl_easy->headers = NULL;
183
+ curl_easy->request_chunk = NULL;
184
+ VALUE easy = Data_Wrap_Struct(cTyphoeusEasy, 0, dealloc, curl_easy);
185
+
186
+ set_response_handlers(easy, curl);
187
+
188
+ rb_obj_call_init(easy, argc, argv);
189
+
190
+ return easy;
191
+ }
192
+
193
+ static VALUE curl_error_message(VALUE self) {
194
+ VALUE return_code = rb_iv_get(self, "@curl_return_code");
195
+ if (return_code == Qnil)
196
+ return Qnil;
197
+ else {
198
+ CURLcode rc = (CURLcode)FIX2INT(return_code);
199
+ return rb_str_new2(curl_easy_strerror(rc));
200
+ }
201
+ }
202
+
203
+ void init_typhoeus_easy() {
204
+ VALUE klass = cTyphoeusEasy = rb_define_class_under(mTyphoeus, "Easy", rb_cObject);
205
+ idAppend = rb_intern("<<");
206
+ rb_define_singleton_method(klass, "new", new, -1);
207
+ rb_define_method(klass, "curl_error_message", curl_error_message, 0);
208
+ rb_define_private_method(klass, "easy_setopt_string", easy_setopt_string, 2);
209
+ rb_define_private_method(klass, "easy_setopt_long", easy_setopt_long, 2);
210
+ rb_define_private_method(klass, "easy_getinfo_string", easy_getinfo_string, 1);
211
+ rb_define_private_method(klass, "easy_getinfo_long", easy_getinfo_long, 1);
212
+ rb_define_private_method(klass, "easy_getinfo_double", easy_getinfo_double, 1);
213
+ rb_define_private_method(klass, "easy_perform", easy_perform, 0);
214
+ rb_define_private_method(klass, "easy_reset", easy_reset, 0);
215
+ rb_define_private_method(klass, "easy_set_request_body", easy_set_request_body, 1);
216
+ rb_define_private_method(klass, "easy_set_headers", easy_set_headers, 0);
217
+ rb_define_private_method(klass, "easy_add_header", easy_add_header, 1);
218
+ rb_define_private_method(klass, "easy_escape", easy_escape, 2);
219
+ rb_define_private_method(klass, "version", version, 0);
220
+ }