curb 0.1.4 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of curb might be problematic. Click here for more details.

@@ -0,0 +1,25 @@
1
+ /* curb_multi.h - Curl easy mode
2
+ * Copyright (c)2008 Todd A. Fisher.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ *
5
+ * $Id$
6
+ */
7
+ #ifndef __CURB_MULTI_H
8
+ #define __CURB_MULTI_H
9
+
10
+ #include "curb.h"
11
+ #include "curb_easy.h"
12
+ #include <curl/multi.h>
13
+
14
+ typedef struct {
15
+ int active;
16
+ int running;
17
+ VALUE requests; /* hash of handles currently added */
18
+ CURLM *handle;
19
+ } ruby_curl_multi;
20
+
21
+ extern VALUE cCurlMulti;
22
+ void init_curb_multi();
23
+
24
+
25
+ #endif
@@ -429,9 +429,10 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
429
429
 
430
430
  if ((rbcpf->local_file == Qnil) && (rbcpf->remote_file == Qnil)) {
431
431
  if (rbcpf->name != Qnil) {
432
- char *tmpchrs;
432
+
433
+ char *tmpchrs = curl_escape(RSTRING_PTR(rbcpf->name), RSTRING_LEN(rbcpf->name));
433
434
 
434
- if ((tmpchrs = curl_escape(StringValuePtr(rbcpf->name), RSTRING_LEN(rbcpf->name))) == NULL) {
435
+ if (!tmpchrs) {
435
436
  rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
436
437
  } else {
437
438
  VALUE tmpcontent = Qnil;
@@ -445,8 +446,17 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
445
446
  } else {
446
447
  tmpcontent = rb_str_new2("");
447
448
  }
448
-
449
- if ((tmpchrs = curl_escape(StringValuePtr(tmpcontent), RSTRING_LEN(tmpcontent))) == NULL) {
449
+ if (TYPE(tmpcontent) != T_STRING) {
450
+ if (rb_respond_to(tmpcontent, rb_intern("to_s"))) {
451
+ tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
452
+ }
453
+ else {
454
+ rb_raise(rb_eRuntimeError, "postfield(%s) is not a string and does not respond_to to_s", RSTRING_PTR(escd_name) );
455
+ }
456
+ }
457
+ //fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
458
+ tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), RSTRING_LEN(tmpcontent));
459
+ if (!tmpchrs) {
450
460
  rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
451
461
  } else {
452
462
  VALUE escd_content = rb_str_new2(tmpchrs);
@@ -2,23 +2,120 @@ require 'mkmf'
2
2
 
3
3
  dir_config('curl')
4
4
 
5
- unless have_library('curl') &&
6
- have_header('curl/curl.h')
5
+ if find_executable('curl-config')
6
+ $CFLAGS << " #{`curl-config --cflags`.strip}"
7
+ $LIBS << " #{`curl-config --libs`.strip}"
8
+ elsif !have_library('curl') or !have_header('curl/curl.h')
7
9
  fail <<-EOM
8
10
  Can't find libcurl or curl/curl.h
9
-
11
+
10
12
  Try passing --with-curl-dir or --with-curl-lib and --with-curl-include
11
13
  options to extconf.
12
14
  EOM
13
15
  end
14
16
 
15
- #install_rb("curb.rb", "$(RUBYLIBDIR)", '../lib')
16
- #install_rb("curl.rb", "$(RUBYLIBDIR)", '../lib')
17
- $INSTALLFILES = [["curb.rb", "$(RUBYLIBDIR)", "../ext"], ["curl.rb", "$(RUBYLIBDIR)", "../ext"]]
17
+ def define(s)
18
+ $defs.push( format("-D HAVE_%s", s.to_s.upcase) )
19
+ end
20
+
21
+ def have_constant(name)
22
+ checking_for name do
23
+ src = %{
24
+ #include <curl/curl.h>
25
+ int main() {
26
+ int test = (int)#{name.upcase};
27
+ return 0;
28
+ }
29
+ }
30
+ if try_compile(src,"#{$CFLAGS} #{$LIBS}")
31
+ define name
32
+ true
33
+ else
34
+ false
35
+ end
36
+ end
37
+ end
38
+
39
+ have_constant "curlinfo_redirect_time"
40
+ have_constant "curlinfo_response_code"
41
+ have_constant "curlinfo_filetime"
42
+ have_constant "curlinfo_redirect_count"
43
+ have_constant "curlinfo_os_errno"
44
+ have_constant "curlinfo_num_connects"
45
+ have_constant "curlinfo_ftp_entry_path"
46
+ have_constant "curl_version_ssl"
47
+ have_constant "curl_version_libz"
48
+ have_constant "curl_version_ntlm"
49
+ have_constant "curl_version_gssnegotiate"
50
+ have_constant "curl_version_debug"
51
+ have_constant "curl_version_asynchdns"
52
+ have_constant "curl_version_spnego"
53
+ have_constant "curl_version_largefile"
54
+ have_constant "curl_version_idn"
55
+ have_constant "curl_version_sspi"
56
+ have_constant "curl_version_conv"
57
+ have_constant "curlproxy_http"
58
+ have_constant "curlproxy_socks4"
59
+ have_constant "curlproxy_socks5"
60
+ have_constant "curlauth_basic"
61
+ have_constant "curlauth_digest"
62
+ have_constant "curlauth_gssnegotiate"
63
+ have_constant "curlauth_ntlm"
64
+ have_constant "curlauth_anysafe"
65
+ have_constant "curlauth_any"
66
+ have_constant "curle_tftp_notfound"
67
+ have_constant "curle_tftp_perm"
68
+ have_constant "curle_tftp_diskfull"
69
+ have_constant "curle_tftp_illegal"
70
+ have_constant "curle_tftp_unknownid"
71
+ have_constant "curle_tftp_exists"
72
+ have_constant "curle_tftp_nosuchuser"
73
+ # older versions of libcurl 7.12
74
+ have_constant "curle_send_fail_rewind"
75
+ have_constant "curle_ssl_engine_initfailed"
76
+ have_constant "curle_login_denied"
18
77
 
19
78
  if try_compile('int main() { return 0; }','-Wall')
20
79
  $CFLAGS << ' -Wall'
21
80
  end
22
81
 
23
- create_makefile('curb_core')
82
+ # do some checking to detect ruby 1.8 hash.c vs ruby 1.9 hash.c
83
+ def test_for(name, const, src)
84
+ checking_for name do
85
+ if try_compile(src,"#{$CFLAGS} #{$LIBS}")
86
+ define const
87
+ true
88
+ else
89
+ false
90
+ end
91
+ end
92
+ end
93
+ test_for("Ruby 1.9 Hash", "RUBY19_HASH", %{
94
+ #include <ruby.h>
95
+ int main() {
96
+ VALUE hash = rb_hash_new();
97
+ if( RHASH(hash)->ntbl->num_entries ) {
98
+ return 0;
99
+ }
100
+ return 1;
101
+ }
102
+ })
103
+ test_for("Ruby 1.9 st.h", "RUBY19_ST_H", %{
104
+ #include <ruby.h>
105
+ #include <ruby/st.h>
106
+ int main() {
107
+ return 0;
108
+ }
109
+ })
24
110
 
111
+ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
112
+ #include <curl/curl.h>
113
+ int main() {
114
+ CURL *easy = curl_easy_init();
115
+ curl_easy_escape(easy,"hello",5);
116
+ return 0;
117
+ }
118
+ })
119
+
120
+ create_header('curb_config.h')
121
+ create_makefile('curb_core')
@@ -39,6 +39,8 @@ module Curl
39
39
 
40
40
  curl.perform
41
41
  end
42
+
43
+ return curl
42
44
  end
43
45
  end
44
46
  end
File without changes
@@ -0,0 +1,52 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+ require 'webrick'
3
+ class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
4
+ class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
5
+
6
+ class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
7
+ def test_bug
8
+ server = WEBrick::HTTPServer.new( :Port => 9999 )
9
+ server.mount_proc("/test") do|req,res|
10
+ sleep 0.5
11
+ res.body = "hi"
12
+ res['Content-Type'] = "text/html"
13
+ end
14
+
15
+ thread = Thread.new(server) do|srv|
16
+ srv.start
17
+ end
18
+
19
+ threads = []
20
+ timer = Time.now
21
+
22
+ 5.times do |i|
23
+ t = Thread.new do
24
+ c = Curl::Easy.perform('http://localhost:9999/test')
25
+ c.header_str
26
+ end
27
+ threads << t
28
+ end
29
+
30
+ multi_responses = threads.collect do|t|
31
+ t.value
32
+ end
33
+
34
+ multi_time = (Time.now - timer)
35
+ puts "requested in #{multi_time}"
36
+
37
+ timer = Time.now
38
+ single_responses = []
39
+ 5.times do |i|
40
+ c = Curl::Easy.perform('http://localhost:9999/test')
41
+ single_responses << c.header_str
42
+ end
43
+
44
+ single_time = (Time.now - timer)
45
+ puts "requested in #{single_time}"
46
+
47
+ assert single_time > multi_time
48
+
49
+ server.shutdown
50
+ thread.join
51
+ end
52
+ end
@@ -13,3 +13,144 @@ require 'curb'
13
13
  require 'test/unit'
14
14
 
15
15
  $TEST_URL = "file://#{URI.escape(File.expand_path(__FILE__).tr('\\','/').tr(':','|'))}"
16
+
17
+ require 'thread'
18
+ require 'webrick'
19
+
20
+ # set this to true to avoid testing with multiple threads
21
+ # or to test with multiple threads set it to false
22
+ # this is important since, some code paths will change depending
23
+ # on the presence of multiple threads
24
+ TEST_SINGLE_THREADED=false
25
+
26
+ # keep webrick quiet
27
+ class ::WEBrick::HTTPServer
28
+ def access_log(config, req, res)
29
+ # nop
30
+ end
31
+ end
32
+ class ::WEBrick::BasicLog
33
+ def log(level, data)
34
+ # nop
35
+ end
36
+ end
37
+
38
+ #
39
+ # Simple test server to record number of times a request is sent/recieved of a specific
40
+ # request type, e.g. GET,POST,PUT,DELETE
41
+ #
42
+ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
43
+
44
+ def self.port=(p)
45
+ @port = p
46
+ end
47
+
48
+ def self.port
49
+ (@port or 9129)
50
+ end
51
+
52
+ def self.path
53
+ '/methods'
54
+ end
55
+
56
+ def self.url
57
+ "http://127.0.0.1:#{port}#{path}"
58
+ end
59
+
60
+ def respond_with(method,req,res)
61
+ res.body = method.to_s
62
+ res['Content-Type'] = "text/plain"
63
+ end
64
+
65
+ def do_GET(req,res)
66
+ respond_with(:GET,req,res)
67
+ end
68
+
69
+ def do_HEAD(req,res)
70
+ res['Location'] = "/nonexistent"
71
+ respond_with(:HEAD, req, res)
72
+ end
73
+
74
+ def do_POST(req,res)
75
+ respond_with(:POST,req,res)
76
+ end
77
+
78
+ def do_PUT(req,res)
79
+ respond_with("PUT\n#{req.body}",req,res)
80
+ end
81
+
82
+ def do_DELETE(req,res)
83
+ respond_with(:DELETE,req,res)
84
+ end
85
+
86
+ end
87
+
88
+ module TestServerMethods
89
+ def locked_file
90
+ File.join(File.dirname(__FILE__),"server_lock-#{@__port}")
91
+ end
92
+
93
+ def server_setup(port=9129,servlet=TestServlet)
94
+ @__port = port
95
+ if @server.nil? and !File.exist?(locked_file)
96
+
97
+ File.open(locked_file,'w') {|f| f << 'locked' }
98
+ if TEST_SINGLE_THREADED
99
+ rd, wr = IO.pipe
100
+ @__pid = fork do
101
+ rd.close
102
+ rd = nil
103
+
104
+ # start up a webrick server for testing delete
105
+ server = WEBrick::HTTPServer.new :Port => port, :DocumentRoot => File.expand_path(File.dirname(__FILE__))
106
+
107
+ server.mount(servlet.path, servlet)
108
+ trap("INT") { server.shutdown }
109
+ GC.start
110
+ wr.flush
111
+ wr.close
112
+ server.start
113
+ end
114
+ wr.close
115
+ rd.read
116
+ rd.close
117
+ else
118
+ # start up a webrick server for testing delete
119
+ @server = WEBrick::HTTPServer.new :Port => port, :DocumentRoot => File.expand_path(File.dirname(__FILE__))
120
+
121
+ @server.mount(servlet.path, servlet)
122
+ queue = Queue.new # synchronize the thread startup to the main thread
123
+
124
+ @test_thread = Thread.new { queue << 1; @server.start }
125
+
126
+ # wait for the queue
127
+ value = queue.pop
128
+ if !value
129
+ STDERR.puts "Failed to startup test server!"
130
+ exit(1)
131
+ end
132
+
133
+ end
134
+
135
+ exit_code = lambda do
136
+ begin
137
+ if File.exist?(locked_file)
138
+ File.unlink locked_file
139
+ if TEST_SINGLE_THREADED
140
+ Process.kill 'INT', @__pid
141
+ else
142
+ @server.shutdown unless @server.nil?
143
+ end
144
+ end
145
+ #@server.shutdown unless @server.nil?
146
+ rescue Object => e
147
+ puts "Error #{__FILE__}:#{__LINE__}\n#{e.message}"
148
+ end
149
+ end
150
+
151
+ trap("INT"){exit_code.call}
152
+ at_exit{exit_code.call}
153
+
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class TestCurbCurlDownload < Test::Unit::TestCase
4
+ include TestServerMethods
5
+
6
+ def setup
7
+ server_setup(9130)
8
+ end
9
+
10
+ def test_download_url_to_file
11
+ dl_url = "http://127.0.0.1:9130/ext/curb_easy.c"
12
+ dl_path = File.join("/tmp/dl_url_test.file")
13
+
14
+ curb = Curl::Easy.download(dl_url, dl_path)
15
+ assert File.exist?(dl_path)
16
+ end
17
+
18
+ def test_download_bad_url_gives_404
19
+ dl_url = "http://127.0.0.1:9130/this_file_does_not_exist.html"
20
+ dl_path = File.join("/tmp/dl_url_test.file")
21
+
22
+ curb = Curl::Easy.download(dl_url, dl_path)
23
+ assert_equal Curl::Easy, curb.class
24
+ assert_equal 404, curb.response_code
25
+ end
26
+
27
+ end
@@ -86,7 +86,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
86
86
 
87
87
  def test_get_01
88
88
  c = Curl::Easy.new($TEST_URL)
89
- assert_equal true, c.http_get
89
+ assert_equal true, c.http_get
90
90
  assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
91
91
  assert_equal "", c.header_str
92
92
  end
@@ -110,7 +110,8 @@ class TestCurbCurlEasy < Test::Unit::TestCase
110
110
  assert_equal "", c.body_str
111
111
  assert_equal "", c.header_str
112
112
  end
113
-
113
+
114
+
114
115
  def test_last_effective_url_01
115
116
  c = Curl::Easy.new($TEST_URL)
116
117
 
@@ -438,5 +439,68 @@ class TestCurbCurlEasy < Test::Unit::TestCase
438
439
  assert_equal "some.file", c.cookiejar = "some.file"
439
440
  assert_equal "some.file", c.cookiejar
440
441
  end
442
+
443
+ def test_on_success
444
+ curl = Curl::Easy.new($TEST_URL)
445
+ on_success_called = false
446
+ curl.on_success {|c|
447
+ on_success_called = true
448
+ assert_not_nil c.body_str
449
+ assert_equal "", c.header_str
450
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
451
+ }
452
+ curl.perform
453
+ assert on_success_called, "Success handler not called"
454
+ end
455
+
456
+ def test_on_success_with_on_failure
457
+ curl = Curl::Easy.new("#{$TEST_URL.gsub(/file:\/\//,'')}/not_here")
458
+ on_failure_called = false
459
+ curl.on_success {|c| } # make sure we get the failure call even though this handler is defined
460
+ curl.on_failure {|c| on_failure_called = true }
461
+ curl.perform
462
+ assert on_failure_called, "Failure handler not called"
463
+ end
464
+
465
+ def test_get_remote
466
+ curl = Curl::Easy.new(TestServlet.url)
467
+ curl.http_get
468
+ assert_equal 'GET', curl.body_str
469
+ end
441
470
 
442
- end
471
+ def test_post_remote
472
+ curl = Curl::Easy.new(TestServlet.url)
473
+ curl.http_post
474
+ assert_equal 'POST', curl.body_str
475
+ end
476
+
477
+ def test_delete_remote
478
+ curl = Curl::Easy.new(TestServlet.url)
479
+ curl.http_delete
480
+ assert_equal 'DELETE', curl.body_str
481
+ end
482
+
483
+ def test_head_remote
484
+ curl = Curl::Easy.new(TestServlet.url)
485
+ curl.http_head
486
+
487
+ redirect = curl.header_str.match(/Location: (.*)/)
488
+
489
+ assert_equal '', curl.body_str
490
+ assert_match '/nonexistent', redirect[1]
491
+ end
492
+
493
+ def test_put_remote
494
+ curl = Curl::Easy.new(TestServlet.url)
495
+ assert curl.http_put("message")
496
+ assert_match /^PUT/, curl.body_str
497
+ assert_match /message$/, curl.body_str
498
+ end
499
+
500
+ include TestServerMethods
501
+
502
+ def setup
503
+ server_setup
504
+ end
505
+
506
+ end