├── .gitignore ├── Makefile ├── README.md ├── example ├── example.rb ├── gist.rb ├── google_translate.rb └── twitter_stream.rb ├── mrbgem.rake ├── mrblib └── curl.rb └── src ├── mrb_curl.c └── mrb_curl.h /.gitignore: -------------------------------------------------------------------------------- 1 | gem_* 2 | gem-* 3 | mrb-*.a 4 | src/*.o 5 | .local.vimrc 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GEM := mruby-curl 2 | 3 | include $(MAKEFILE_4_GEM) 4 | 5 | ifeq ($(OS),Windows_NT) 6 | MRUBY_LIBS = -lcurldll 7 | else 8 | MRUBY_LIBS = -lcurl 9 | endif 10 | 11 | GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) 12 | GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) 13 | 14 | gem-all : $(GEM_OBJECTS) gem-c-files 15 | 16 | gem-clean : gem-clean-c-files 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | = mruby-curl 2 | 3 | mruby-curl is an [mruby](http://mruby.org) wrapper for 4 | [libcurl](https://curl.haxx.se/libcurl/). 5 | 6 | == Usage 7 | 8 | Example: 9 | 10 | ```ruby 11 | curl = Curl.new 12 | 13 | headers = { 14 | 'User-Agent' => 'mruby-curl' 15 | } 16 | 17 | response = curl.get("http://www.ruby-lang.org/ja/", headers) 18 | 19 | puts response.body 20 | ``` 21 | 22 | mruby-curl has support for HTTP methods DELETE, GET, PATCH, POST, and PUT 23 | through instance methods on the Curl object and supports arbitrary HTTP 24 | requests using `Curl#send` with an `HTTP::Request` object from 25 | [mruby-http](https://github.com/mattn/mruby-http). 26 | 27 | 28 | === Use HTTP 1.0 instead of 1.1 29 | 30 | ```ruby 31 | curl = Curl.new 32 | Curl::HTTP_VERSION = Curl::HTTP_1_0 33 | response = curl.get("http://www.ruby-lang.org/ja/") 34 | ``` 35 | 36 | == Threaded use 37 | 38 | By default mruby-curl does not call 39 | [curl_global_init](https://curl.haxx.se/libcurl/c/curl_global_init.html). If 40 | you are using mruby-curl in a multithreaded environment you must call it 41 | yourself. 42 | 43 | If threads are started from within mruby the `Curl.global_init` method will 44 | initialize curl with the default flags. You must call it before starting 45 | threads that will use mruby-curl methods. 46 | 47 | If mruby is started from a multi-threaded program you must call 48 | `curl_global_init` before starting any mruby threads. 49 | 50 | See the 51 | [curl_global_init](https://curl.haxx.se/libcurl/c/curl_global_init.html) 52 | documentation for more details. 53 | 54 | -------------------------------------------------------------------------------- /example/example.rb: -------------------------------------------------------------------------------- 1 | #!mruby 2 | 3 | curl = Curl.new 4 | 5 | headers = { 6 | 'User-Agent' => 'mruby-curl', 7 | } 8 | 9 | curl.timeout_ms = 3000 10 | response = curl.get("http://www.ruby-lang.org/ja/", headers) 11 | 12 | puts response.body 13 | -------------------------------------------------------------------------------- /example/gist.rb: -------------------------------------------------------------------------------- 1 | #!mruby 2 | 3 | if ARGV.size != 1 4 | raise "gist.rb [GIST_TOKEN]" 5 | end 6 | 7 | req = HTTP::Request.new 8 | req.method = "POST" 9 | req.body = JSON::stringify({ 10 | "description"=> "We love mruby!", 11 | "public"=> true, 12 | "files"=> { 13 | "file1.txt"=> { 14 | "content"=> "mruby is awesome!" 15 | } 16 | } 17 | }) 18 | req.headers['Authorization'] = "token #{ARGV[0]}" 19 | req.headers['Content-Type'] = "application/json" 20 | Curl::SSL_VERIFYPEER = 0 21 | res = Curl.new.send("https://api.github.com/gists", req) 22 | puts JSON::parse(res.body)['html_url'] 23 | -------------------------------------------------------------------------------- /example/google_translate.rb: -------------------------------------------------------------------------------- 1 | #!mruby 2 | 3 | url = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=mruby&rsz=large" 4 | for result in JSON::parse(Curl.new.get(url).body)['responseData']['results'] 5 | puts "#{result['titleNoFormatting']}\n #{result['url']}" 6 | end 7 | -------------------------------------------------------------------------------- /example/twitter_stream.rb: -------------------------------------------------------------------------------- 1 | #!mruby 2 | 3 | if ARGV.size != 2 4 | raise "twitterstream.rb [USER] [PASSWORD]" 5 | end 6 | 7 | Curl::SSL_VERIFYPEER = 0 8 | Curl.new.get("https://stream.twitter.com/1.1/statuses/sample.json", {"Authorization"=> "Basic #{Base64::encode(ARGV[0] + ":" + ARGV[1])}"}) do |h,b| 9 | begin 10 | tweet = JSON::parse(b) 11 | puts Iconv.conv("char", "utf-8", "#{tweet['user']['screen_name']}: #{tweet['text']}") if tweet.has_key?('text') 12 | rescue RuntimeError, NameError 13 | puts "#{tweet['user']['screen_name']}: #{tweet['text']}" if tweet.has_key?('text') 14 | rescue ArgumentError 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /mrbgem.rake: -------------------------------------------------------------------------------- 1 | MRuby::Gem::Specification.new('mruby-curl') do |spec| 2 | spec.license = 'MIT' 3 | spec.authors = 'mattn' 4 | 5 | spec.linker.libraries << 'curl' 6 | 7 | spec.add_dependency 'mruby-http' 8 | end 9 | -------------------------------------------------------------------------------- /mrblib/curl.rb: -------------------------------------------------------------------------------- 1 | class Curl 2 | def self.delete(url, headers = nil, &block) 3 | @curl ||= new 4 | @curl.delete url, headers, &block 5 | end 6 | 7 | def self.get(url, headers = nil, &block) 8 | @curl ||= new 9 | @curl.get url, headers, &block 10 | end 11 | 12 | def self.patch(url, data, headers = nil, &block) 13 | @curl ||= new 14 | @curl.patch url, data, headers, &block 15 | end 16 | 17 | def self.post(url, data, headers = nil, &block) 18 | @curl ||= new 19 | @curl.post url, data, headers, &block 20 | end 21 | 22 | def self.put(url, data, headers = nil, &block) 23 | @curl ||= new 24 | @curl.put url, data, headers, &block 25 | end 26 | 27 | def self.send(url, req, headers = nil, &block) 28 | @curl ||= new 29 | @curl.send url, req, headers, &block 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /src/mrb_curl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define REQ_GET(mrb, instance, name) \ 14 | RSTRING_PTR(mrb_iv_get(mrb, instance, mrb_intern_cstr(mrb, name))) 15 | 16 | static void mrb_curl_free(mrb_state *, void *); 17 | 18 | static struct mrb_data_type mrb_curl_type = { 19 | "Curl", mrb_curl_free 20 | }; 21 | 22 | typedef struct { 23 | char* data; // response data from server 24 | size_t size; // response size of data 25 | mrb_state* mrb; 26 | mrb_value proc; 27 | mrb_value header; 28 | } MEMFILE; 29 | 30 | static MEMFILE* 31 | memfopen() { 32 | MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE)); 33 | if (mf) { 34 | mf->data = NULL; 35 | mf->size = 0; 36 | } 37 | return mf; 38 | } 39 | 40 | static void 41 | memfclose(MEMFILE* mf) { 42 | if (mf->data) free(mf->data); 43 | free(mf); 44 | } 45 | 46 | static size_t 47 | memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) { 48 | MEMFILE* mf = (MEMFILE*) stream; 49 | int block = size * nmemb; 50 | if (!mf) return block; // through 51 | if (!mf->data) 52 | mf->data = (char*) malloc(block); 53 | else 54 | mf->data = (char*) realloc(mf->data, mf->size + block); 55 | if (mf->data) { 56 | memcpy(mf->data + mf->size, ptr, block); 57 | mf->size += block; 58 | } 59 | return block; 60 | } 61 | 62 | static size_t 63 | memfwrite_callback(char* ptr, size_t size, size_t nmemb, void* stream) { 64 | MEMFILE* mf = (MEMFILE*) stream; 65 | int block = size * nmemb; 66 | 67 | mrb_value args[2]; 68 | mrb_state* mrb = mf->mrb; 69 | 70 | int ai = mrb_gc_arena_save(mrb); \ 71 | if (mf->data && mrb_nil_p(mf->header)) { 72 | mrb_value str = mrb_str_new(mrb, mf->data, mf->size); 73 | struct RClass* _class_http = mrb_module_get(mrb, "HTTP"); 74 | struct RClass* _class_http_parser = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern_cstr(mrb, "Parser"))); 75 | mrb_value parser = mrb_obj_new(mrb, _class_http_parser, 0, NULL); 76 | args[0] = str; 77 | mf->header = mrb_funcall_argv(mrb, parser, mrb_intern_cstr(mrb, "parse_response"), 1, args); 78 | } 79 | 80 | args[0] = mf->header; 81 | args[1] = mrb_str_new(mrb, ptr, block); 82 | mrb_gc_arena_restore(mrb, ai); 83 | mrb_yield_argv(mrb, mf->proc, 2, args); 84 | return block; 85 | } 86 | 87 | static mrb_value 88 | mrb_curl_global_init(mrb_state *mrb, mrb_value self) { 89 | CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT); 90 | 91 | if (res != CURLE_OK) { 92 | mrb_raise(mrb, E_RUNTIME_ERROR, "unable to initialize libcurl"); 93 | } 94 | 95 | return mrb_true_value(); 96 | } 97 | 98 | static mrb_value 99 | mrb_curl_init(mrb_state *mrb, mrb_value self) { 100 | CURL* curl; 101 | 102 | curl = DATA_CHECK_GET_PTR(mrb, self, &mrb_curl_type, CURL); 103 | 104 | if (curl) 105 | curl_easy_cleanup(curl); 106 | 107 | mrb_data_init(self, NULL, &mrb_curl_type); 108 | 109 | curl = curl_easy_init(); 110 | 111 | mrb_data_init(self, curl, &mrb_curl_type); 112 | 113 | return self; 114 | } 115 | 116 | static void 117 | mrb_curl_free(mrb_state *mrb, void *curl) { 118 | curl_easy_cleanup((CURL *)curl); 119 | } 120 | 121 | static struct curl_slist* 122 | mrb_curl_headers(mrb_state *mrb, CURL* curl, mrb_value headers) { 123 | struct curl_slist* headerlist = NULL; 124 | 125 | if (!mrb_nil_p(headers) && mrb_type(headers) != MRB_TT_HASH) { 126 | mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument"); 127 | } 128 | 129 | if (!mrb_nil_p(headers)) { 130 | mrb_value keys = mrb_hash_keys(mrb, headers); 131 | int i, l = RARRAY_LEN(keys); 132 | for (i = 0; i < l; i++) { 133 | mrb_value key = mrb_ary_entry(keys, i); 134 | mrb_value header = mrb_str_dup(mrb, key); 135 | mrb_str_cat2(mrb, header, ": "); 136 | mrb_str_concat(mrb, header, mrb_hash_get(mrb, headers, key)); 137 | headerlist = curl_slist_append(headerlist, RSTRING_PTR(header)); 138 | } 139 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); 140 | } 141 | 142 | return headerlist; 143 | } 144 | 145 | static void 146 | mrb_curl_set_options(mrb_state *mrb, mrb_value self) { 147 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 148 | 149 | int ssl_verifypeer; 150 | mrb_value http_version; 151 | mrb_value mv_cainfo = mrb_nil_value(); 152 | mrb_value timeout; 153 | mrb_value timeout_ms; 154 | struct RClass* _class_curl; 155 | 156 | _class_curl = mrb_class_get(mrb, "Curl"); 157 | 158 | ssl_verifypeer = mrb_fixnum(mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "SSL_VERIFYPEER"))); 159 | 160 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, ssl_verifypeer); 161 | 162 | mv_cainfo = mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "CAINFO")); 163 | 164 | if (!mrb_nil_p(mv_cainfo)) { 165 | curl_easy_setopt(curl, CURLOPT_CAINFO, RSTRING_PTR(mv_cainfo)); 166 | } 167 | http_version = mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "HTTP_VERSION")); 168 | curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, mrb_int(mrb, http_version)); 169 | 170 | timeout = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "timeout")); 171 | if (mrb_nil_p(timeout)) { 172 | timeout = mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "TIMEOUT")); 173 | } 174 | if (!mrb_nil_p(timeout)) { 175 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, mrb_int(mrb, timeout)); 176 | } 177 | 178 | timeout_ms = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "timeout_ms")); 179 | if (mrb_nil_p(timeout_ms)) { 180 | timeout_ms = mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "TIMEOUT_MS")); 181 | } 182 | if (!mrb_nil_p(timeout_ms)) { 183 | curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, mrb_int(mrb, timeout_ms)); 184 | } 185 | } 186 | 187 | static mrb_value 188 | mrb_curl_perform(mrb_state *mrb, mrb_value self, mrb_value url, mrb_value headers, mrb_value b) { 189 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 190 | CURLcode res = CURLE_OK; 191 | MEMFILE* mf; 192 | char error[CURL_ERROR_SIZE] = {0}; 193 | mrb_value args[1]; 194 | mrb_value parser; 195 | mrb_value str; 196 | struct RClass* _class_http; 197 | struct RClass* _class_http_parser; 198 | struct curl_slist* headerlist; 199 | 200 | curl_easy_setopt(curl, CURLOPT_URL, RSTRING_PTR(url)); 201 | 202 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); 203 | 204 | mf = memfopen(); 205 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf); 206 | 207 | if (mrb_nil_p(b)) { 208 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite); 209 | } else { 210 | mf->mrb = mrb; 211 | mf->proc = b; 212 | mf->header = mrb_nil_value(); 213 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite_callback); 214 | } 215 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, mf); 216 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, memfwrite); 217 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0); 218 | curl_easy_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L); 219 | 220 | mrb_curl_set_options(mrb, self); 221 | 222 | headerlist = mrb_curl_headers(mrb, curl, headers); 223 | 224 | res = curl_easy_perform(curl); 225 | 226 | if (headerlist) 227 | curl_slist_free_all(headerlist); 228 | 229 | if (res != CURLE_OK) { 230 | mrb_raise(mrb, E_RUNTIME_ERROR, error); 231 | } 232 | if (!mrb_nil_p(b)) { 233 | return mrb_nil_value(); 234 | } 235 | 236 | str = mrb_str_new(mrb, mf->data, mf->size); 237 | memfclose(mf); 238 | 239 | _class_http = mrb_module_get(mrb, "HTTP"); 240 | _class_http_parser = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern_cstr(mrb, "Parser"))); 241 | parser = mrb_obj_new(mrb, _class_http_parser, 0, NULL); 242 | args[0] = str; 243 | return mrb_funcall_argv(mrb, parser, mrb_intern_cstr(mrb, "parse_response"), 1, args); 244 | } 245 | 246 | static mrb_value 247 | mrb_curl_delete(mrb_state *mrb, mrb_value self) 248 | { 249 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 250 | 251 | mrb_value url = mrb_nil_value(); 252 | mrb_value headers = mrb_nil_value(); 253 | mrb_value b = mrb_nil_value(); 254 | mrb_get_args(mrb, "S|H!&", &url, &headers, &b); 255 | 256 | curl_easy_reset(curl); 257 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 258 | curl_easy_setopt(curl, CURLOPT_UPLOAD, 0); 259 | curl_easy_setopt(curl, CURLOPT_NOBODY, 0); 260 | 261 | return mrb_curl_perform(mrb, self, url, headers, b); 262 | } 263 | 264 | static mrb_value 265 | mrb_curl_get(mrb_state *mrb, mrb_value self) 266 | { 267 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 268 | 269 | mrb_value url = mrb_nil_value(); 270 | mrb_value headers = mrb_nil_value(); 271 | mrb_value b = mrb_nil_value(); 272 | mrb_get_args(mrb, "S|H!&", &url, &headers, &b); 273 | 274 | curl_easy_reset(curl); 275 | curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); 276 | 277 | return mrb_curl_perform(mrb, self, url, headers, b); 278 | } 279 | 280 | static mrb_value 281 | mrb_curl_patch(mrb_state *mrb, mrb_value self) 282 | { 283 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 284 | 285 | mrb_value url = mrb_nil_value(); 286 | mrb_value data = mrb_nil_value(); 287 | mrb_value headers = mrb_nil_value(); 288 | mrb_value b = mrb_nil_value(); 289 | mrb_get_args(mrb, "SS|H!&", &url, &data, &headers, &b); 290 | 291 | curl_easy_reset(curl); 292 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, RSTRING_PTR(data)); 293 | 294 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); 295 | 296 | return mrb_curl_perform(mrb, self, url, headers, b); 297 | } 298 | 299 | static mrb_value 300 | mrb_curl_post(mrb_state *mrb, mrb_value self) 301 | { 302 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 303 | 304 | mrb_value url = mrb_nil_value(); 305 | mrb_value data = mrb_nil_value(); 306 | mrb_value headers = mrb_nil_value(); 307 | mrb_value b = mrb_nil_value(); 308 | mrb_get_args(mrb, "SS|H!&", &url, &data, &headers, &b); 309 | 310 | curl_easy_reset(curl); 311 | curl_easy_setopt(curl, CURLOPT_POST, 1); 312 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, RSTRING_PTR(data)); 313 | 314 | return mrb_curl_perform(mrb, self, url, headers, b); 315 | } 316 | 317 | static mrb_value 318 | mrb_curl_put(mrb_state *mrb, mrb_value self) 319 | { 320 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 321 | 322 | mrb_value url = mrb_nil_value(); 323 | mrb_value data = mrb_nil_value(); 324 | mrb_value headers = mrb_nil_value(); 325 | mrb_value b = mrb_nil_value(); 326 | mrb_get_args(mrb, "SS|H!&", &url, &data, &headers, &b); 327 | 328 | curl_easy_reset(curl); 329 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, RSTRING_PTR(data)); 330 | 331 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); 332 | 333 | return mrb_curl_perform(mrb, self, url, headers, b); 334 | } 335 | 336 | static mrb_value 337 | mrb_curl_send(mrb_state *mrb, mrb_value self) 338 | { 339 | char error[CURL_ERROR_SIZE] = {0}; 340 | CURL* curl = DATA_GET_PTR(mrb, self, &mrb_curl_type, CURL); 341 | CURLcode res = CURLE_OK; 342 | MEMFILE* mf; 343 | struct curl_slist* headerlist; 344 | mrb_value body; 345 | mrb_value method; 346 | mrb_value _class_http_request; 347 | mrb_value name; 348 | mrb_value headers; 349 | mrb_value str; 350 | struct RClass* _class_http; 351 | struct RClass* _class_http_parser; 352 | mrb_value parser; 353 | mrb_value args[1]; 354 | 355 | mrb_value url = mrb_nil_value(); 356 | mrb_value req = mrb_nil_value(); 357 | mrb_value b = mrb_nil_value(); 358 | mrb_get_args(mrb, "So&", &url, &req, &b); 359 | 360 | _class_http_request = mrb_funcall(mrb, req, "class", 0, NULL); 361 | name = mrb_funcall(mrb, _class_http_request, "to_s", 0, NULL); 362 | if (strcmp(RSTRING_PTR(name), "HTTP::Request")) { 363 | mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument"); 364 | } 365 | 366 | mf = memfopen(); 367 | curl_easy_setopt(curl, CURLOPT_URL, RSTRING_PTR(url)); 368 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); 369 | method = mrb_funcall(mrb, req, "method", 0, NULL); 370 | if (strcmp("GET", RSTRING_PTR(method))) { 371 | curl_easy_setopt(curl, CURLOPT_POST, 1); 372 | body = mrb_funcall(mrb, req, "body", 0, NULL); 373 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, RSTRING_PTR(body)); 374 | } 375 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf); 376 | if (mrb_nil_p(b)) { 377 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite); 378 | } else { 379 | mf->mrb = mrb; 380 | mf->proc = b; 381 | mf->header = mrb_nil_value(); 382 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite_callback); 383 | } 384 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, mf); 385 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, memfwrite); 386 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0); 387 | curl_easy_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L); 388 | 389 | mrb_curl_set_options(mrb, self); 390 | 391 | headers = mrb_funcall(mrb, req, "headers", 0, NULL); 392 | 393 | headerlist = mrb_curl_headers(mrb, curl, headers); 394 | 395 | res = curl_easy_perform(curl); 396 | 397 | if (headerlist) 398 | curl_slist_free_all(headerlist); 399 | 400 | if (res != CURLE_OK) { 401 | mrb_raise(mrb, E_RUNTIME_ERROR, error); 402 | } 403 | if (!mrb_nil_p(b)) { 404 | return mrb_nil_value(); 405 | } 406 | 407 | str = mrb_str_new(mrb, mf->data, mf->size); 408 | memfclose(mf); 409 | 410 | _class_http = mrb_module_get(mrb, "HTTP"); 411 | _class_http_parser = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern_cstr(mrb, "Parser"))); 412 | parser = mrb_obj_new(mrb, _class_http_parser, 0, NULL); 413 | args[0] = str; 414 | return mrb_funcall_argv(mrb, parser, mrb_intern_cstr(mrb, "parse_response"), 1, args); 415 | } 416 | 417 | static mrb_value 418 | mrb_curl_set_timeout(mrb_state *mrb, mrb_value self) 419 | { 420 | mrb_value timeout = mrb_nil_value(); 421 | mrb_get_args(mrb, "o", &timeout); 422 | mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "timeout"), timeout); 423 | 424 | return timeout; 425 | } 426 | 427 | static mrb_value 428 | mrb_curl_get_timeout(mrb_state *mrb, mrb_value self) 429 | { 430 | mrb_value timeout = mrb_nil_value(); 431 | timeout = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "timeout")); 432 | 433 | return timeout; 434 | } 435 | 436 | static mrb_value 437 | mrb_curl_set_timeout_ms(mrb_state *mrb, mrb_value self) 438 | { 439 | mrb_value timeout_ms = mrb_nil_value(); 440 | mrb_get_args(mrb, "o", &timeout_ms); 441 | mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "timeout_ms"), timeout_ms); 442 | 443 | return timeout_ms; 444 | } 445 | 446 | static mrb_value 447 | mrb_curl_get_timeout_ms(mrb_state *mrb, mrb_value self) 448 | { 449 | mrb_value timeout_ms = mrb_nil_value(); 450 | timeout_ms = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "timeout_ms")); 451 | 452 | return timeout_ms; 453 | } 454 | 455 | void 456 | mrb_mruby_curl_gem_init(mrb_state* mrb) 457 | { 458 | struct RClass* _class_curl; 459 | int ai = mrb_gc_arena_save(mrb); 460 | 461 | _class_curl = mrb_define_class(mrb, "Curl", mrb->object_class); 462 | MRB_SET_INSTANCE_TT(_class_curl, MRB_TT_DATA); 463 | 464 | mrb_define_method(mrb, _class_curl, "initialize", mrb_curl_init, MRB_ARGS_NONE()); 465 | 466 | mrb_define_method(mrb, _class_curl, "delete", mrb_curl_delete, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); 467 | mrb_define_method(mrb, _class_curl, "get", mrb_curl_get, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); 468 | mrb_define_method(mrb, _class_curl, "patch", mrb_curl_patch, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); 469 | mrb_define_method(mrb, _class_curl, "post", mrb_curl_post, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); 470 | mrb_define_method(mrb, _class_curl, "put", mrb_curl_put, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); 471 | mrb_define_method(mrb, _class_curl, "send", mrb_curl_send, MRB_ARGS_REQ(2)); 472 | 473 | mrb_define_method(mrb, _class_curl, "timeout=", mrb_curl_set_timeout, MRB_ARGS_REQ(1)); 474 | mrb_define_method(mrb, _class_curl, "timeout", mrb_curl_get_timeout, MRB_ARGS_REQ(1)); 475 | mrb_define_method(mrb, _class_curl, "timeout_ms=", mrb_curl_set_timeout_ms, MRB_ARGS_REQ(1)); 476 | mrb_define_method(mrb, _class_curl, "timeout_ms", mrb_curl_get_timeout_ms, MRB_ARGS_REQ(1)); 477 | 478 | mrb_define_class_method(mrb, _class_curl, "global_init", mrb_curl_global_init, MRB_ARGS_REQ(0)); 479 | 480 | mrb_define_const(mrb, _class_curl, "SSL_VERIFYPEER", mrb_fixnum_value(1)); 481 | mrb_define_const(mrb, _class_curl, "CAINFO", mrb_nil_value()); 482 | mrb_define_const(mrb, _class_curl, "HTTP_VERSION", mrb_fixnum_value(CURL_HTTP_VERSION_1_1)); 483 | mrb_define_const(mrb, _class_curl, "HTTP_1_0", mrb_fixnum_value(CURL_HTTP_VERSION_1_0)); 484 | mrb_define_const(mrb, _class_curl, "HTTP_1_1", mrb_fixnum_value(CURL_HTTP_VERSION_1_1)); 485 | mrb_define_const(mrb, _class_curl, "TIMEOUT", mrb_nil_value()); 486 | mrb_define_const(mrb, _class_curl, "TIMEOUT_MS", mrb_nil_value()); 487 | 488 | mrb_gc_arena_restore(mrb, ai); 489 | } 490 | 491 | void 492 | mrb_mruby_curl_gem_final(mrb_state* mrb) 493 | { 494 | } 495 | 496 | /* vim:set et ts=2 sts=2 sw=2 tw=0: */ 497 | -------------------------------------------------------------------------------- /src/mrb_curl.h: -------------------------------------------------------------------------------- 1 | #ifndef MRB_CURL_H 2 | #define MRB_CURL_H 3 | 4 | void mrb_mruby_curl_gem_init(mrb_state*); 5 | 6 | #endif /* MRB_CURL_H */ 7 | --------------------------------------------------------------------------------