curb 0.8.5 → 1.3.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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +579 -0
  3. data/Rakefile +85 -27
  4. data/doc.rb +48 -8
  5. data/ext/banned.h +32 -0
  6. data/ext/curb.c +563 -233
  7. data/ext/curb.h +19 -10
  8. data/ext/curb_easy.c +3229 -368
  9. data/ext/curb_easy.h +42 -0
  10. data/ext/curb_errors.c +117 -18
  11. data/ext/curb_errors.h +9 -5
  12. data/ext/curb_macros.h +33 -21
  13. data/ext/curb_multi.c +1904 -272
  14. data/ext/curb_multi.h +11 -3
  15. data/ext/curb_postfield.c +149 -77
  16. data/ext/curb_postfield.h +1 -0
  17. data/ext/curb_upload.c +38 -11
  18. data/ext/curb_upload.h +2 -0
  19. data/ext/extconf.rb +355 -35
  20. data/lib/curb.rb +1 -0
  21. data/lib/curl/download.rb +160 -0
  22. data/lib/curl/easy.rb +422 -88
  23. data/lib/curl/multi.rb +295 -56
  24. data/lib/curl.rb +676 -11
  25. data/tests/bug_crash_on_debug.rb +14 -28
  26. data/tests/bug_crash_on_progress.rb +32 -16
  27. data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
  28. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
  29. data/tests/bug_follow_redirect_288.rb +83 -0
  30. data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
  31. data/tests/bug_issue102.rb +17 -0
  32. data/tests/bug_issue_noproxy.rb +56 -0
  33. data/tests/bug_issue_post_redirect.rb +93 -0
  34. data/tests/bug_issue_spnego.rb +41 -0
  35. data/tests/bug_multi_segfault.rb +1 -0
  36. data/tests/bug_poison.rb +29 -0
  37. data/tests/bug_raise_on_callback.rb +30 -0
  38. data/tests/helper.rb +400 -44
  39. data/tests/leak_trace.rb +237 -0
  40. data/tests/mem_check.rb +3 -0
  41. data/tests/tc_curl.rb +31 -1
  42. data/tests/tc_curl_download.rb +98 -7
  43. data/tests/tc_curl_easy.rb +985 -66
  44. data/tests/tc_curl_easy_cookielist.rb +277 -0
  45. data/tests/tc_curl_easy_request_target.rb +41 -0
  46. data/tests/tc_curl_easy_resolve.rb +48 -0
  47. data/tests/tc_curl_maxfilesize.rb +212 -0
  48. data/tests/tc_curl_multi.rb +1111 -51
  49. data/tests/tc_curl_native_coverage.rb +145 -0
  50. data/tests/tc_curl_network_policy.rb +1475 -0
  51. data/tests/tc_curl_postfield.rb +207 -30
  52. data/tests/tc_curl_protocols.rb +388 -0
  53. data/tests/tc_fiber_scheduler.rb +584 -0
  54. data/tests/tc_ftp_options.rb +39 -0
  55. data/tests/tc_gc_compact.rb +223 -0
  56. data/tests/tc_test_server_methods.rb +110 -0
  57. data/tests/timeout.rb +30 -6
  58. metadata +66 -31
  59. data/README +0 -194
data/Rakefile CHANGED
@@ -2,10 +2,11 @@
2
2
  #
3
3
  require 'rake/clean'
4
4
  require 'rake/testtask'
5
+ require "ruby_memcheck"
6
+ require 'shellwords'
5
7
  begin
6
- require 'rdoc/task'
7
- rescue LoadError => e
8
- require 'rake/rdoctask'
8
+ require 'mixlib/shellout'
9
+ rescue LoadError
9
10
  end
10
11
 
11
12
  CLEAN.include '**/*.o'
@@ -15,6 +16,15 @@ CLOBBER.include '**/*.log'
15
16
  CLOBBER.include '**/Makefile'
16
17
  CLOBBER.include '**/extconf.h'
17
18
 
19
+ # Load support ruby and rake files (in this order)
20
+ Dir.glob('tasks/*.rb').each { |r| load r}
21
+ Dir.glob('tasks/*.rake').each { |r| load r}
22
+
23
+ desc 'Print Ruby major version (ie "2_5")'
24
+ task :ruby_version do
25
+ print current_ruby_major
26
+ end
27
+
18
28
  def announce(msg='')
19
29
  $stderr.puts msg
20
30
  end
@@ -43,40 +53,31 @@ end
43
53
  make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
44
54
  MAKECMD = ENV['MAKE_CMD'] || make_program
45
55
  MAKEOPTS = ENV['MAKE_OPTS'] || ''
46
-
47
56
  CURB_SO = "ext/curb_core.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
48
57
 
49
58
  file 'ext/Makefile' => 'ext/extconf.rb' do
50
- Dir.chdir('ext') do
51
- ruby "extconf.rb #{ENV['EXTCONF_OPTS']}"
52
- end
59
+ shell(['ruby', 'extconf.rb', ENV['EXTCONF_OPTS'].to_s],
60
+ { :live_stdout => STDOUT , :cwd => "#{Dir.pwd}/ext" }
61
+ ).error!
53
62
  end
54
63
 
55
64
  def make(target = '')
56
- Dir.chdir('ext') do
57
- pid = system("#{MAKECMD} #{MAKEOPTS} #{target}")
58
- $?.exitstatus
59
- end
65
+ shell(["#{MAKECMD}", "#{MAKEOPTS}", "#{target}"].reject(&:empty?),
66
+ { :live_stdout => STDOUT, :cwd => "#{Dir.pwd}/ext" }
67
+ ).error!
60
68
  end
61
69
 
62
70
  # Let make handle dependencies between c/o/so - we'll just run it.
63
71
  file CURB_SO => (['ext/Makefile'] + Dir['ext/*.c'] + Dir['ext/*.h']) do
64
- m = make
65
- fail "Make failed (status #{m})" unless m == 0
72
+ make
66
73
  end
67
74
 
68
75
  desc "Compile the shared object"
69
76
  task :compile => [CURB_SO]
70
77
 
71
- desc "Create the markdown file"
72
- task :markdown do
73
- cp "README", "README.markdown"
74
- end
75
-
76
78
  desc "Install to your site_ruby directory"
77
- task :install => :alltests do
78
- m = make 'install'
79
- fail "Make install failed (status #{m})" unless m == 0
79
+ task :install do
80
+ make 'install'
80
81
  end
81
82
 
82
83
  # Test Tasks ---------------------------------------------------------
@@ -88,18 +89,65 @@ task :rmpid do
88
89
  FileUtils.rm_rf Dir.glob("tests/server_lock-*")
89
90
  end
90
91
 
92
+ at_exit do
93
+ next unless defined?(Rake.application)
94
+
95
+ top_level_tasks = Rake.application.top_level_tasks
96
+ test_tasks = %w[default test ta tu alltests unittests bugtests test:valgrind]
97
+ should_cleanup = top_level_tasks.empty? || top_level_tasks.any? { |task| test_tasks.include?(task) }
98
+
99
+ FileUtils.rm_rf Dir.glob("tests/server_lock-*") if should_cleanup
100
+ end
101
+
91
102
  if ENV['RELTEST']
92
103
  announce "Release task testing - not running regression tests on alltests"
93
104
  task :alltests => [:unittests]
94
105
  else
95
106
  task :alltests => [:unittests, :bugtests]
96
107
  end
97
-
108
+
109
+ ruby_memcheck_config = { binary_name: 'curb_core' }
110
+ ruby_version = Gem::Version.new(RUBY_VERSION)
111
+
112
+ if RUBY_ENGINE == 'ruby' && ruby_version >= Gem::Version.new('4.0.4') && ruby_version < Gem::Version.new('4.1.0')
113
+ # Ruby 4.0.4+ reports fiber/block-handler VM stack accesses under Valgrind.
114
+ # Keep reporting errors that originate in curb_core, but filter Ruby-side noise.
115
+ ruby_memcheck_config[:filter_all_errors] = true
116
+ if RubyMemcheck::Configuration.instance_method(:initialize).parameters.any? { |type, name|
117
+ type == :key && name == :use_only_ruby_free_at_exit
118
+ }
119
+ ruby_memcheck_config[:use_only_ruby_free_at_exit] = false
120
+ end
121
+ ruby_memcheck_config[:skipped_ruby_functions] =
122
+ RubyMemcheck::Configuration::DEFAULT_SKIPPED_RUBY_FUNCTIONS + [
123
+ /\Arb_vm_frame_block_handler\z/
124
+ ]
125
+ end
126
+
127
+ RubyMemcheck.config(**ruby_memcheck_config)
128
+ namespace :test do
129
+ RubyMemcheck::TestTask.new(valgrind: :compile) do|t|
130
+ t.test_files = FileList['tests/tc_*.rb']
131
+ t.verbose = false
132
+ end
133
+
134
+ desc 'Run the standalone leak trace helper'
135
+ task :leak_trace => :compile do
136
+ ruby_opts = Shellwords.split(ENV['LEAK_TRACE_OPTS'].to_s)
137
+ sh RbConfig.ruby, '-Ilib', '-Iext', 'tests/leak_trace.rb', *ruby_opts
138
+ end
139
+ end
140
+
141
+ Rake::Task['test:valgrind'].enhance([:rmpid]) do
142
+ Rake::Task[:rmpid].reenable
143
+ Rake::Task[:rmpid].invoke
144
+ end
145
+
98
146
  Rake::TestTask.new(:unittests) do |t|
99
147
  t.test_files = FileList['tests/tc_*.rb']
100
148
  t.verbose = false
101
149
  end
102
-
150
+
103
151
  Rake::TestTask.new(:bugtests) do |t|
104
152
  t.test_files = FileList['tests/bug_*.rb']
105
153
  t.verbose = false
@@ -136,11 +184,21 @@ end
136
184
  # RDoc Tasks ---------------------------------------------------------
137
185
  desc "Create the RDOC documentation"
138
186
  task :doc do
139
- ruby "doc.rb #{ENV['DOC_OPTS']}"
187
+ doc_opts = Shellwords.split(ENV.fetch('DOC_OPTS', ''))
188
+ unsupported_opts = doc_opts - ['--cpp']
189
+ fail "Unsupported DOC_OPTS: #{unsupported_opts.join(' ')}" unless unsupported_opts.empty?
190
+
191
+ ruby 'doc.rb', *doc_opts
140
192
  end
141
193
 
142
194
  desc "Publish the RDoc documentation to project web site"
143
195
  task :doc_upload => [ :doc ] do
196
+ begin
197
+ require 'rdoc/task'
198
+ rescue LoadError => e
199
+ require 'rake/rdoctask'
200
+ end
201
+
144
202
  if ENV['RELTEST']
145
203
  announce "Release Task Testing, skipping doc upload"
146
204
  else
@@ -171,13 +229,13 @@ else
171
229
 
172
230
  desc 'Build gem'
173
231
  task :package => :gemspec do
174
- require 'rubygems/specification'
232
+ require 'rubygems/package'
175
233
  spec_source = File.read File.join(File.dirname(__FILE__),'curb.gemspec')
176
234
  spec = nil
177
235
  # see: http://gist.github.com/16215
178
- Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
236
+ Thread.new { spec = eval("#{spec_source}") }.join
179
237
  spec.validate
180
- Gem::Builder.new(spec).build
238
+ Gem::Package.build(spec)
181
239
  end
182
240
 
183
241
  task :static do
data/doc.rb CHANGED
@@ -1,10 +1,35 @@
1
1
  require 'fileutils'
2
+ require 'open3'
3
+ require 'shellwords'
2
4
  include FileUtils
3
5
 
4
- begin
5
- incflags = File.read('ext/Makefile')[/INCFLAGS\s*=\s*(.*)$/,1]
6
+ def makefile_variables(path)
7
+ variables = {}
8
+
9
+ File.foreach(path) do |line|
10
+ line = line.chomp
11
+ variables[$1] = $2.strip if line =~ /\A([A-Za-z_]\w*)\s*=\s*(.*)\z/
12
+ end
13
+
14
+ variables
15
+ end
16
+
17
+ def expand_make_variables(value, variables, seen = [])
18
+ value.gsub(/\$\(([^)]+)\)/) do
19
+ key = Regexp.last_match(1)
20
+ raise ArgumentError, "unsupported Makefile variable in INCFLAGS: #{key}" unless variables.key?(key)
21
+ raise ArgumentError, "recursive Makefile variable in INCFLAGS: #{key}" if seen.include?(key)
22
+
23
+ expand_make_variables(variables[key], variables, seen + [key])
24
+ end
25
+ end
26
+
27
+ def makefile_incflags
28
+ variables = makefile_variables('ext/Makefile')
29
+ Shellwords.split(expand_make_variables(variables.fetch('INCFLAGS', ''), variables))
6
30
  rescue Errno::ENOENT
7
31
  $stderr.puts("No makefile found; run `rake ext/Makefile' first.")
32
+ []
8
33
  end
9
34
 
10
35
  pp_srcdir = 'ext'
@@ -15,26 +40,41 @@ mkdir(tmpdir)
15
40
  begin
16
41
  if ARGV.include?('--cpp')
17
42
  begin
18
- if `cpp --version` =~ /\(GCC\)/
43
+ cpp_version, status = Open3.capture2e('cpp', '--version')
44
+
45
+ if status.success? && cpp_version =~ /\(GCC\)/
19
46
  # gnu cpp
20
47
  $stderr.puts "Running GNU cpp over source"
48
+ incflags = makefile_incflags
21
49
 
22
- Dir['ext/*.c'].each do |fn|
23
- system("cpp -DRDOC_NEVER_DEFINED -C #{incflags} -o " +
24
- "#{File.join(tmpdir, File.basename(fn))} #{fn}")
50
+ Dir['ext/*.c'].sort.each do |fn|
51
+ out = File.join(tmpdir, File.basename(fn))
52
+ abort "cpp failed for #{fn}" unless system('cpp', '-DRDOC_NEVER_DEFINED', '-C', *incflags, '-o', out, fn)
25
53
  end
26
54
 
27
55
  pp_srcdir = tmpdir
28
56
  else
29
57
  $stderr.puts "Not running cpp (non-GNU)"
30
58
  end
31
- rescue
59
+ rescue Errno::ENOENT
32
60
  # no cpp
33
61
  $stderr.puts "No cpp found"
62
+ rescue ArgumentError => e
63
+ abort e.message
34
64
  end
35
65
  end
36
66
 
37
- system("rdoc --title='Curb - libcurl bindings for ruby' --main=README #{pp_srcdir}/*.c README LICENSE lib/curb.rb")
67
+ main = File.exist?('README.md') ? 'README.md' : 'README'
68
+ sources = Dir[File.join(pp_srcdir, '*.c')].sort
69
+ abort 'rdoc failed' unless system(
70
+ 'rdoc',
71
+ '--title', 'Curb - libcurl bindings for ruby',
72
+ '--main', main,
73
+ *sources,
74
+ main,
75
+ 'LICENSE',
76
+ 'lib/curb.rb'
77
+ )
38
78
  ensure
39
79
  rm_rf(tmpdir)
40
80
  end
data/ext/banned.h ADDED
@@ -0,0 +1,32 @@
1
+ #ifndef BANNED_H
2
+ #define BANNED_H
3
+
4
+ /*
5
+ * This header lists functions that have been banned from our code base,
6
+ * because they're too easy to misuse (and even if used correctly,
7
+ * complicate audits). Including this header turns them into compile-time
8
+ * errors.
9
+ */
10
+
11
+ #define BANNED(func) sorry_##func##_is_a_banned_function
12
+
13
+ #undef strcpy
14
+ #define strcpy(x,y) BANNED(strcpy)
15
+ #undef strcat
16
+ #define strcat(x,y) BANNED(strcat)
17
+ #undef strncpy
18
+ #define strncpy(x,y,n) BANNED(strncpy)
19
+ #undef strncat
20
+ #define strncat(x,y,n) BANNED(strncat)
21
+
22
+ #undef sprintf
23
+ #undef vsprintf
24
+ #ifdef HAVE_VARIADIC_MACROS
25
+ #define sprintf(...) BANNED(sprintf)
26
+ #define vsprintf(...) BANNED(vsprintf)
27
+ #else
28
+ #define sprintf(buf,fmt,arg) BANNED(sprintf)
29
+ #define vsprintf(buf,fmt,arg) BANNED(sprintf)
30
+ #endif
31
+
32
+ #endif /* BANNED_H */