patron 0.4.18 → 0.4.20

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- patron (0.4.18)
4
+ patron (0.4.20)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.1.3)
10
10
  rake (0.9.2.2)
@@ -1,13 +1,13 @@
1
- = Ruby HTTP Client
1
+ # Ruby HTTP Client
2
2
 
3
- == SYNOPSIS
3
+ ## SYNOPSIS
4
4
 
5
5
  Patron is a Ruby HTTP client library based on libcurl. It does not try to expose
6
6
  the full "power" (read complexity) of libcurl but instead tries to provide a
7
7
  sane API while taking advantage of libcurl under the hood.
8
8
 
9
9
 
10
- == USAGE
10
+ ## USAGE
11
11
 
12
12
  Usage is very simple. First, you instantiate a Session object. You can set a few
13
13
  default options on the Session instance that will be used by all subsequent
@@ -41,7 +41,7 @@ You can ship custom headers with a single request:
41
41
  That is pretty much all there is to it.
42
42
 
43
43
 
44
- == REQUIREMENTS
44
+ ## REQUIREMENTS
45
45
 
46
46
  You need a recent version of libcurl in order to install this gem. On MacOS X
47
47
  the provided libcurl is sufficient. You will have to install the libcurl
@@ -49,9 +49,9 @@ development packages on Debian or Ubuntu. Other Linux systems are probably
49
49
  similar. Windows users are on your own. Good luck with that.
50
50
 
51
51
 
52
- == INSTALL
52
+ ## INSTALL
53
53
 
54
- sudo gem install patron
54
+ sudo gem install patron
55
55
 
56
56
 
57
57
  Copyright (c) 2008 The Hive
@@ -260,10 +260,25 @@ static VALUE session_unescape(VALUE self, VALUE value) {
260
260
  /* Callback used to iterate over the HTTP headers and store them in an slist. */
261
261
  static int each_http_header(VALUE header_key, VALUE header_value, VALUE self) {
262
262
  struct curl_state *state = get_curl_state(self);
263
+ CURL* curl = state->handle;
264
+
263
265
  VALUE name = rb_obj_as_string(header_key);
264
266
  VALUE value = rb_obj_as_string(header_value);
265
267
  VALUE header_str = Qnil;
266
268
 
269
+ if (rb_str_cmp(name, rb_str_new2("Accept-Encoding")) == 0) {
270
+ if (rb_funcall(value, rb_intern("include?"), 1, rb_str_new2("gzip"))) {
271
+ #ifdef CURLOPT_ACCEPT_ENCODING
272
+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
273
+ #elif defined CURLOPT_ENCODING
274
+ curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
275
+ #else
276
+ rb_raise(rb_eArgError,
277
+ "The libcurl version installed doesn't support 'gzip'.");
278
+ #endif
279
+ }
280
+ }
281
+
267
282
  header_str = rb_str_plus(name, rb_str_new2(": "));
268
283
  header_str = rb_str_plus(header_str, value);
269
284
 
@@ -325,7 +340,10 @@ static void set_options_from_request(VALUE self, VALUE request) {
325
340
  VALUE credentials = Qnil;
326
341
  VALUE ignore_content_length = Qnil;
327
342
  VALUE insecure = Qnil;
343
+ VALUE cacert = Qnil;
344
+ VALUE ssl_version = Qnil;
328
345
  VALUE buffer_size = Qnil;
346
+ VALUE action_name = rb_iv_get(request, "@action");
329
347
 
330
348
  headers = rb_iv_get(request, "@headers");
331
349
  if (!NIL_P(headers)) {
@@ -336,7 +354,8 @@ static void set_options_from_request(VALUE self, VALUE request) {
336
354
  rb_hash_foreach(headers, each_http_header, self);
337
355
  }
338
356
 
339
- action = SYM2ID(rb_iv_get(request, "@action"));
357
+ action = SYM2ID(action_name);
358
+
340
359
  if (action == rb_intern("get")) {
341
360
  VALUE data = rb_iv_get(request, "@upload_data");
342
361
  VALUE download_file = rb_iv_get(request, "@file_name");
@@ -352,7 +371,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
352
371
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, len);
353
372
  }
354
373
  if (!NIL_P(download_file)) {
355
- state->download_file = open_file(download_file, "w");
374
+ state->download_file = open_file(download_file, "wb");
356
375
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, state->download_file);
357
376
  } else {
358
377
  state->download_file = NULL;
@@ -386,7 +405,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
386
405
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
387
406
  }
388
407
 
389
- state->upload_file = open_file(filename, "r");
408
+ state->upload_file = open_file(filename, "rb");
390
409
  curl_easy_setopt(curl, CURLOPT_READDATA, state->upload_file);
391
410
  } else if (!NIL_P(multipart)) {
392
411
  if (action == rb_intern("post")) {
@@ -405,6 +424,20 @@ static void set_options_from_request(VALUE self, VALUE request) {
405
424
  } else {
406
425
  rb_raise(rb_eArgError, "Must provide either data or a filename when doing a PUT or POST");
407
426
  }
427
+
428
+ // support for data passed with a DELETE request (e.g.: used by elasticsearch)
429
+ } else if (action == rb_intern("delete")) {
430
+ VALUE data = rb_iv_get(request, "@upload_data");
431
+
432
+ if (!NIL_P(data)) {
433
+ long len = RSTRING_LEN(data);
434
+ state->upload_buf = StringValuePtr(data);
435
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
436
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, state->upload_buf);
437
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
438
+ }
439
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
440
+
408
441
  } else if (action == rb_intern("head")) {
409
442
  curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
410
443
  } else {
@@ -440,7 +473,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
440
473
 
441
474
  proxy = rb_iv_get(request, "@proxy");
442
475
  if (!NIL_P(proxy)) {
443
- curl_easy_setopt(curl, CURLOPT_PROXY, StringValuePtr(proxy));
476
+ curl_easy_setopt(curl, CURLOPT_PROXY, StringValuePtr(proxy));
444
477
  }
445
478
 
446
479
  proxy_type = rb_iv_get(request, "@proxy_type");
@@ -462,7 +495,24 @@ static void set_options_from_request(VALUE self, VALUE request) {
462
495
  insecure = rb_iv_get(request, "@insecure");
463
496
  if(!NIL_P(insecure)) {
464
497
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
465
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
498
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
499
+ }
500
+
501
+ ssl_version = rb_iv_get(request, "@ssl_version");
502
+ if(!NIL_P(ssl_version)) {
503
+ char* version = StringValuePtr(ssl_version);
504
+ if(strcmp(version, "SSLv2") == 0) {
505
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv2);
506
+ } else if(strcmp(version, "SSLv3") == 0) {
507
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);
508
+ } else if(strcmp(version, "TLSv1") == 0) {
509
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
510
+ }
511
+ }
512
+
513
+ cacert = rb_iv_get(request, "@cacert");
514
+ if(!NIL_P(cacert)) {
515
+ curl_easy_setopt(curl, CURLOPT_CAINFO, StringValuePtr(cacert));
466
516
  }
467
517
 
468
518
  buffer_size = rb_iv_get(request, "@buffer_size");
@@ -672,7 +722,7 @@ static VALUE set_debug_file(VALUE self, VALUE file) {
672
722
  session_close_debug_file(state);
673
723
 
674
724
  if(file_path != NULL && strlen(file_path) != 0) {
675
- state->debug_file = open_file(file, "w");
725
+ state->debug_file = open_file(file, "wb");
676
726
  } else {
677
727
  state->debug_file = stderr;
678
728
  }
@@ -730,4 +780,3 @@ void Init_session_ext() {
730
780
  rb_define_const(mProxyType, "SOCKS4A", INT2FIX(CURLPROXY_SOCKS4A));
731
781
  rb_define_const(mProxyType, "SOCKS5_HOSTNAME", INT2FIX(CURLPROXY_SOCKS5_HOSTNAME));
732
782
  }
733
-
data/lib/patron.rb CHANGED
@@ -28,6 +28,7 @@ cwd = Pathname(__FILE__).dirname
28
28
  $:.unshift(cwd.to_s) unless $:.include?(cwd.to_s) || $:.include?(cwd.expand_path.to_s)
29
29
 
30
30
  require 'patron/session'
31
+ require 'patron/version'
31
32
 
32
33
  module Patron #:nodoc:
33
34
  # Returns the version number of the Patron library as a string
@@ -32,7 +32,7 @@ module Patron
32
32
  # used in every request.
33
33
  class Request
34
34
 
35
- VALID_ACTIONS = [:get, :put, :post, :delete, :head, :copy]
35
+ VALID_ACTIONS = %w[GET PUT POST DELETE HEAD COPY]
36
36
 
37
37
  def initialize
38
38
  @action = :get
@@ -42,9 +42,20 @@ module Patron
42
42
  @max_redirects = -1
43
43
  end
44
44
 
45
- attr_accessor :url, :username, :password, :file_name, :proxy, :proxy_type, :auth_type, :insecure, :ignore_content_length, :multipart
46
- attr_reader :action, :timeout, :connect_timeout, :max_redirects, :headers, :buffer_size
47
- attr_reader :auth_type
45
+ READER_VARS = [
46
+ :url, :username, :password, :file_name, :proxy, :proxy_type, :insecure,
47
+ :ignore_content_length, :multipart, :action, :timeout, :connect_timeout,
48
+ :max_redirects, :headers, :auth_type, :upload_data, :buffer_size, :cacert,
49
+ :ssl_version
50
+ ]
51
+
52
+ WRITER_VARS = [
53
+ :url, :username, :password, :file_name, :proxy, :proxy_type, :insecure,
54
+ :ignore_content_length, :multipart, :cacert, :ssl_version
55
+ ]
56
+
57
+ attr_reader *READER_VARS
58
+ attr_writer *WRITER_VARS
48
59
 
49
60
  # Set the type of authentication to use for this request.
50
61
  #
@@ -71,22 +82,17 @@ module Patron
71
82
  def upload_data=(data)
72
83
  @upload_data = case data
73
84
  when Hash
74
- self.multipart ? data : Util.build_query_string_from_hash(data, @action == :post)
85
+ self.multipart ? data : Util.build_query_string_from_hash(data, action == :post)
75
86
  else
76
87
  data
77
88
  end
78
89
  end
79
90
 
80
- def upload_data
81
- @upload_data
82
- end
83
-
84
- def action=(new_action)
85
- if !VALID_ACTIONS.include?(new_action)
91
+ def action=(action)
92
+ if !VALID_ACTIONS.include?(action.to_s.upcase)
86
93
  raise ArgumentError, "Action must be one of #{VALID_ACTIONS.join(', ')}"
87
94
  end
88
-
89
- @action = new_action
95
+ @action = action.downcase.to_sym
90
96
  end
91
97
 
92
98
  def timeout=(new_timeout)
@@ -129,13 +135,35 @@ module Patron
129
135
  @buffer_size = buffer_size != nil ? buffer_size.to_i : nil
130
136
  end
131
137
 
138
+ def credentials
139
+ return nil if username.nil? || password.nil?
140
+ "#{username}:#{password}"
141
+ end
142
+
132
143
  def action_name
133
144
  @action.to_s.upcase
134
145
  end
135
146
 
136
- def credentials
137
- return nil if username.nil? || password.nil?
138
- "#{username}:#{password}"
147
+ def eql?(request)
148
+ return false unless Request === request
149
+
150
+ READER_VARS.inject(true) do |memo, name|
151
+ memo && (self.send(name) == request.send(name))
152
+ end
153
+ end
154
+
155
+ alias_method :==, :eql?
156
+
157
+ def marshal_dump
158
+ [ @url, @username, @password, @file_name, @proxy, @proxy_type, @insecure,
159
+ @ignore_content_length, @multipart, @action, @timeout, @connect_timeout,
160
+ @max_redirects, @headers, @auth_type, @upload_data, @buffer_size, @cacert ]
161
+ end
162
+
163
+ def marshal_load(data)
164
+ @url, @username, @password, @file_name, @proxy, @proxy_type, @insecure,
165
+ @ignore_content_length, @multipart, @action, @timeout, @connect_timeout,
166
+ @max_redirects, @headers, @auth_type, @upload_data, @buffer_size, @cacert = data
139
167
  end
140
168
 
141
169
  end
@@ -35,13 +35,13 @@ module Patron
35
35
  @status = status
36
36
  @redirect_count = redirect_count
37
37
  @body = body
38
-
38
+
39
39
  @charset = determine_charset(header_data, body) || default_charset
40
-
40
+
41
41
  [url, header_data].each do |attr|
42
42
  convert_to_default_encoding!(attr)
43
43
  end
44
-
44
+
45
45
  parse_headers(header_data)
46
46
  if @headers["Content-Type"] && @headers["Content-Type"][0, 5] == "text/"
47
47
  convert_to_default_encoding!(@body)
@@ -55,14 +55,22 @@ module Patron
55
55
  "#<Patron::Response @status_line='#{@status_line}'>"
56
56
  end
57
57
 
58
+ def marshal_dump
59
+ [@url, @status, @status_line, @redirect_count, @body, @headers, @charset]
60
+ end
61
+
62
+ def marshal_load(data)
63
+ @url, @status, @status_line, @redirect_count, @body, @headers, @charset = data
64
+ end
65
+
58
66
  private
59
67
 
60
68
  def determine_charset(header_data, body)
61
69
  header_data.match(charset_regex) || (body && body.match(charset_regex))
62
-
70
+
63
71
  $1
64
72
  end
65
-
73
+
66
74
  def charset_regex
67
75
  /(?:charset|encoding)="?([a-z0-9-]+)"?/i
68
76
  end
@@ -59,7 +59,7 @@ module Patron
59
59
  attr_accessor :proxy_type
60
60
 
61
61
  # Standard set of headers that are used in all requests.
62
- attr_reader :headers
62
+ attr_accessor :headers
63
63
 
64
64
  # Set the authentication type for the request.
65
65
  # @see Patron::Request#auth_type
@@ -68,6 +68,12 @@ module Patron
68
68
  # Does this session stricly verify SSL certificates?
69
69
  attr_accessor :insecure
70
70
 
71
+ # Specifies the ssl version
72
+ attr_accessor :ssl_version
73
+
74
+ # What cacert file should this session use to verify SSL certificates?
75
+ attr_accessor :cacert
76
+
71
77
  # Does this session ignore Content-Size headers?
72
78
  attr_accessor :ignore_content_length
73
79
 
@@ -138,6 +144,8 @@ module Patron
138
144
  end
139
145
 
140
146
  # As #get but sends an HTTP DELETE request.
147
+ # Notice: this method doesn't accept any +data+ argument: if you need to send data with
148
+ # a delete request, please, use the #request method.
141
149
  def delete(url, headers = {})
142
150
  request(:delete, url, headers)
143
151
  end
@@ -189,39 +197,46 @@ module Patron
189
197
 
190
198
  # Send an HTTP request to the specified +url+.
191
199
  def request(action, url, headers, options = {})
200
+ req = build_request(action, url, headers, options)
201
+ handle_request(req)
202
+ end
203
+
204
+ # Build a request object that can be used in +handle_request+
205
+ def build_request(action, url, headers, options = {})
192
206
  # If the Expect header isn't set uploads are really slow
193
207
  headers['Expect'] ||= ''
194
208
 
195
- req = Request.new
196
- req.action = action
197
- req.headers = self.headers.merge headers
198
- req.timeout = options.fetch :timeout, self.timeout
199
- req.connect_timeout = options.fetch :connect_timeout, self.connect_timeout
200
- req.max_redirects = options.fetch :max_redirects, self.max_redirects
201
- req.username = options.fetch :username, self.username
202
- req.password = options.fetch :password, self.password
203
- req.proxy = options.fetch :proxy, self.proxy
204
- req.proxy_type = options.fetch :proxy_type, self.proxy_type
205
- req.auth_type = options.fetch :auth_type, self.auth_type
206
- req.insecure = options.fetch :insecure, self.insecure
207
- req.ignore_content_length = options.fetch :ignore_content_length, self.ignore_content_length
208
- req.buffer_size = options.fetch :buffer_size, self.buffer_size
209
- req.multipart = options[:multipart]
210
- req.upload_data = options[:data]
211
- req.file_name = options[:file]
212
-
213
- url = self.base_url.to_s + url.to_s
214
- uri = URI.parse(url)
215
- query = uri.query.to_s.split('&')
216
- query += options[:query].is_a?(Hash) ? Util.build_query_pairs_from_hash(options[:query]) : options[:query].to_s.split('&')
217
- uri.query = query.join('&')
218
- uri.query = nil if uri.query.empty?
219
- url = uri.to_s
220
- raise ArgumentError, "Empty URL" if url.empty?
221
- req.url = url
222
-
223
- handle_request(req)
209
+ Request.new.tap do |req|
210
+ req.action = action
211
+ req.headers = self.headers.merge headers
212
+ req.timeout = options.fetch :timeout, self.timeout
213
+ req.connect_timeout = options.fetch :connect_timeout, self.connect_timeout
214
+ req.max_redirects = options.fetch :max_redirects, self.max_redirects
215
+ req.username = options.fetch :username, self.username
216
+ req.password = options.fetch :password, self.password
217
+ req.proxy = options.fetch :proxy, self.proxy
218
+ req.proxy_type = options.fetch :proxy_type, self.proxy_type
219
+ req.auth_type = options.fetch :auth_type, self.auth_type
220
+ req.insecure = options.fetch :insecure, self.insecure
221
+ req.ssl_version = options.fetch :ssl_version, self.ssl_version
222
+ req.cacert = options.fetch :cacert, self.cacert
223
+ req.ignore_content_length = options.fetch :ignore_content_length, self.ignore_content_length
224
+ req.buffer_size = options.fetch :buffer_size, self.buffer_size
225
+ req.multipart = options[:multipart]
226
+ req.upload_data = options[:data]
227
+ req.file_name = options[:file]
228
+
229
+ base_url = self.base_url.to_s
230
+ url = url.to_s
231
+ raise ArgumentError, "Empty URL" if base_url.empty? && url.empty?
232
+ uri = URI.join(base_url, url)
233
+ query = uri.query.to_s.split('&')
234
+ query += options[:query].is_a?(Hash) ? Util.build_query_pairs_from_hash(options[:query]) : options[:query].to_s.split('&')
235
+ uri.query = query.join('&')
236
+ uri.query = nil if uri.query.empty?
237
+ url = uri.to_s
238
+ req.url = url
239
+ end
224
240
  end
225
-
226
241
  end
227
242
  end
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.4.18"
2
+ VERSION = "0.4.20"
3
3
  end
@@ -0,0 +1,36 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
35
+ djS6lZ9vTEbRM+GhU2PMKfvJbiQ/Y6Q=
36
+ -----END CERTIFICATE-----
@@ -0,0 +1,51 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ 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
38
+ Tmsg4oRHzfquVnr6GK6x7ZHIo5mpHHHdOiyp/UD+anfbbMRItcHkzHDctkaoOKWI
39
+ h3P0mYZ5LIJNVuErhucrP57tr+bOOttus9HLHXTYsjOGV4zSKUSVQTOxnTzZepd8
40
+ zIdo+wKCAQAg/Z80RPYGd/IVmD0NWxDbRhfEXn37XhRr1eIfNLjpktMGQENSiPEI
41
+ FM12S+xSUOC31Hs5u+BNop1kCfd1yuf4NxC8eyMjKO3tM90wc+KUMLeh9TdPZ96J
42
+ dD96eVftTuavTkdFZdWB8wSwxDZX3uV4ir1t6bIKDoyz+yqYM3v3HfweJIq0ox2p
43
+ TS40cDDWnt/ZIk3TyMS1QPWbr0Jl8or0JYmRVp1m8jiDwcsp9tUd9+/5bgKhC3uM
44
+ tY0HjOULzvvHkkul5ADAHyNS7zq9lEwEhIilkhX3M0wX3ZxvXwJPUbgYurcbNmgd
45
+ imp6DpuPJPdbg/8bz9YiaAZOnObnE9lFAoIBAGIdAhDDhqhPIW3xDx54TBfxQFi+
46
+ CeFw1g2duwXAXkBV98nKeLdTo3tL8gusb+32LzgVIq2spWUN72xXX40NJjW1Bxk5
47
+ SGatM1T13BaUFNYtzpM9arDPNr3tCiCSzeVvMKdLfp+Vx9R9arnOgLlGkhRCdEtb
48
+ lXAteE7Twuztvad/M0LGpbjN6BD23KLOfxx9C2TgfMuK/Fjt71ASV+80cq4SS2WK
49
+ fqZQnKfGIRE8wcY2R5g2AwEzubCRzD93pGG3KleQKxrUKNoV32M2ZZcM04l8woZX
50
+ vrkNxM3gbBkhFPAJ9LrmA4YExODUXzWt6Y2mCXuH2Ly60yiLa66HbEfhHrs=
51
+ -----END RSA PRIVATE KEY-----
data/spec/request_spec.rb CHANGED
@@ -83,4 +83,22 @@ describe Patron::Request do
83
83
  end
84
84
 
85
85
  end
86
+
87
+ describe :eql? do
88
+
89
+ it "should return true when two requests are equal" do
90
+ @request.should eql(Patron::Request.new)
91
+ end
92
+
93
+ it "should return false when two requests are not equal" do
94
+ req = Patron::Request.new
95
+ req.action = :post
96
+ @request.should_not eql(req)
97
+ end
98
+
99
+ end
100
+
101
+ it "should be able to serialize and deserialize itself" do
102
+ Marshal.load(Marshal.dump(@request)).should eql(@request)
103
+ end
86
104
  end
@@ -48,11 +48,15 @@ describe Patron::Response do
48
48
  response.headers['Content-Type'].should == 'image/png'
49
49
  response.body.encoding.should == Encoding::ASCII_8BIT
50
50
  end
51
-
51
+
52
52
  it "should not allow a default charset to be nil" do
53
53
  Encoding.stub(:default_internal).and_return("UTF-8")
54
54
  expect {
55
55
  Patron::Response.new("url", "status", 0, "", "", nil)
56
56
  }.to_not raise_error
57
57
  end
58
+
59
+ it "should be able to serialize and deserialize itself" do
60
+ Marshal.load(Marshal.dump(@request)).should eql(@request)
61
+ end
58
62
  end
data/spec/session_spec.rb CHANGED
@@ -56,6 +56,11 @@ describe Patron::Session do
56
56
  body.request_method.should == "GET"
57
57
  end
58
58
 
59
+ it 'should ignore #base_url when a full URL is provided' do
60
+ @session.base_url = "http://example.com:123"
61
+ lambda { @session.get("http://localhost:9001/test") }.should_not raise_error(URI::InvalidURIError)
62
+ end
63
+
59
64
  it "should download content with :get and a file path" do
60
65
  tmpfile = "/tmp/patron_test.yaml"
61
66
  response = @session.get_file "/test", tmpfile
@@ -65,12 +70,27 @@ describe Patron::Session do
65
70
  FileUtils.rm tmpfile
66
71
  end
67
72
 
73
+ it "should download correctly(md5 ok) with get_file" do
74
+ tmpfile = "/tmp/picture"
75
+ response = @session.get_file "/picture", tmpfile
76
+ response.body.should be_nil
77
+ File.size(File.join(File.dirname(__FILE__),"../pic.png")).should == File.size(tmpfile)
78
+ FileUtils.rm tmpfile
79
+ end
80
+
68
81
  it "should include custom headers in a request" do
69
82
  response = @session.get("/test", {"User-Agent" => "PatronTest"})
70
83
  body = YAML::load(response.body)
71
84
  body.header["user-agent"].should == ["PatronTest"]
72
85
  end
73
86
 
87
+ it "should include default headers in a request, if they were defined" do
88
+ @session.headers = {"User-Agent" => "PatronTest"}
89
+ response = @session.get("/test")
90
+ body = YAML::load(response.body)
91
+ body.header["user-agent"].should == ["PatronTest"]
92
+ end
93
+
74
94
  it "should merge custom headers with session headers" do
75
95
  @session.headers["X-Test"] = "Testing"
76
96
  response = @session.get("/test", {"User-Agent" => "PatronTest"})
@@ -146,6 +166,14 @@ describe Patron::Session do
146
166
  body.header['content-length'].should == [data.size.to_s]
147
167
  end
148
168
 
169
+ it "should upload data with :delete" do
170
+ data = "upload data"
171
+ response = @session.request(:delete, "/test", {}, :data => data)
172
+ body = YAML::load(response.body)
173
+ body.request_method.should == "DELETE"
174
+ body.header['content-length'].should == [data.size.to_s]
175
+ end
176
+
149
177
  it "should raise when no data is provided to :put" do
150
178
  lambda { @session.put("/test", nil) }.should raise_error(ArgumentError)
151
179
  end
@@ -0,0 +1,284 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Copyright (c) 2008 The Hive http://www.thehive.com/
4
+ ##
5
+ ## Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ ## of this software and associated documentation files (the "Software"), to deal
7
+ ## in the Software without restriction, including without limitation the rights
8
+ ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ ## copies of the Software, and to permit persons to whom the Software is
10
+ ## furnished to do so, subject to the following conditions:
11
+ ##
12
+ ## The above copyright notice and this permission notice shall be included in
13
+ ## all copies or substantial portions of the Software.
14
+ ##
15
+ ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ ## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ ## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ ## THE SOFTWARE.
22
+ ##
23
+ ## -------------------------------------------------------------------
24
+ require File.expand_path("./spec") + '/spec_helper.rb'
25
+ require 'webrick'
26
+ require 'yaml'
27
+ require 'base64'
28
+ require 'fileutils'
29
+
30
+ describe Patron::Session do
31
+
32
+ before(:each) do
33
+ @session = Patron::Session.new
34
+ @session.base_url = "https://localhost:9043"
35
+ @session.insecure = true
36
+ end
37
+
38
+ it "should retrieve a url with :get" do
39
+ response = @session.get("/test")
40
+ body = YAML::load(response.body)
41
+ body.request_method.should == "GET"
42
+ end
43
+
44
+ it "should download content with :get and a file path" do
45
+ tmpfile = "/tmp/patron_test.yaml"
46
+ response = @session.get_file "/test", tmpfile
47
+ response.body.should be_nil
48
+ body = YAML::load_file(tmpfile)
49
+ body.request_method.should == "GET"
50
+ FileUtils.rm tmpfile
51
+ end
52
+
53
+ it "should download correctly(md5 ok) with get_file" do
54
+ tmpfile = "/tmp/picture"
55
+ response = @session.get_file "/picture", tmpfile
56
+ response.body.should be_nil
57
+ File.size(File.join(File.dirname(__FILE__),"../pic.png")).should == File.size(tmpfile)
58
+ FileUtils.rm tmpfile
59
+ end
60
+
61
+ it "should include custom headers in a request" do
62
+ response = @session.get("/test", {"User-Agent" => "PatronTest"})
63
+ body = YAML::load(response.body)
64
+ body.header["user-agent"].should == ["PatronTest"]
65
+ end
66
+
67
+ it "should merge custom headers with session headers" do
68
+ @session.headers["X-Test"] = "Testing"
69
+ response = @session.get("/test", {"User-Agent" => "PatronTest"})
70
+ body = YAML::load(response.body)
71
+ body.header["user-agent"].should == ["PatronTest"]
72
+ body.header["x-test"].should == ["Testing"]
73
+ end
74
+
75
+ it "should raise an exception on timeout" do
76
+ @session.timeout = 1
77
+ lambda {@session.get("/timeout")}.should raise_error(Patron::TimeoutError)
78
+ end
79
+
80
+ it "should follow redirects by default" do
81
+ @session.max_redirects = 1
82
+ response = @session.get("/redirect")
83
+ body = YAML::load(response.body)
84
+ response.status.should == 200
85
+ body.path.should == "/test"
86
+ end
87
+
88
+ it "should include redirect count in response" do
89
+ @session.max_redirects = 1
90
+ response = @session.get("/redirect")
91
+ response.redirect_count.should == 1
92
+ end
93
+
94
+ it "should not follow redirects when configured to do so" do
95
+ @session.max_redirects = 0
96
+ response = @session.get("/redirect")
97
+ response.status.should == 301
98
+ response.body.should be_empty
99
+ end
100
+
101
+ it "should retrieve URL metadata with :head" do
102
+ response = @session.head("/test")
103
+ response.status.should == 200
104
+ response.body.should be_empty
105
+ response.headers.should_not be_empty
106
+ end
107
+
108
+ it "should send a delete request with :delete" do
109
+ response = @session.delete("/test")
110
+ body = YAML::load(response.body)
111
+ body.request_method.should == "DELETE"
112
+ end
113
+
114
+ it "should send a COPY request with :copy" do
115
+ response = @session.copy("/test", "/test2")
116
+ body = YAML::load(response.body)
117
+ body.request_method.should == "COPY"
118
+ end
119
+
120
+ it "should include a Destination header in COPY requests" do
121
+ response = @session.copy("/test", "/test2")
122
+ body = YAML::load(response.body)
123
+ body.header['destination'].first.should == "/test2"
124
+ end
125
+
126
+ it "should upload data with :get" do
127
+ data = "upload data"
128
+ response = @session.request(:get, "/test", {}, :data => data)
129
+ body = YAML::load(response.body)
130
+ body.request_method.should == "GET"
131
+ body.header['content-length'].should == [data.size.to_s]
132
+ end
133
+
134
+ it "should upload data with :put" do
135
+ data = "upload data"
136
+ response = @session.put("/test", data)
137
+ body = YAML::load(response.body)
138
+ body.request_method.should == "PUT"
139
+ body.header['content-length'].should == [data.size.to_s]
140
+ end
141
+
142
+ it "should raise when no data is provided to :put" do
143
+ lambda { @session.put("/test", nil) }.should raise_error(ArgumentError)
144
+ end
145
+
146
+ it "should upload a file with :put" do
147
+ response = @session.put_file("/test", "LICENSE")
148
+ body = YAML::load(response.body)
149
+ body.request_method.should == "PUT"
150
+ end
151
+
152
+ it "should raise when no file is provided to :put" do
153
+ lambda { @session.put_file("/test", nil) }.should raise_error(ArgumentError)
154
+ end
155
+
156
+ it "should use chunked encoding when uploading a file with :put" do
157
+ response = @session.put_file("/test", "LICENSE")
158
+ body = YAML::load(response.body)
159
+ body.header['transfer-encoding'].first.should == "chunked"
160
+ end
161
+
162
+ it "should upload data with :post" do
163
+ data = "upload data"
164
+ response = @session.post("/test", data)
165
+ body = YAML::load(response.body)
166
+ body.request_method.should == "POST"
167
+ body.header['content-length'].should == [data.size.to_s]
168
+ end
169
+
170
+ it "should post a hash of arguments as a urlencoded form" do
171
+ data = {:foo => 123, 'baz' => '++hello world++'}
172
+ response = @session.post("/testpost", data)
173
+ body = YAML::load(response.body)
174
+ body['content_type'].should == "application/x-www-form-urlencoded"
175
+ body['body'].should match(/baz=%2B%2Bhello%20world%2B%2B/)
176
+ body['body'].should match(/foo=123/)
177
+ end
178
+
179
+ it "should raise when no data is provided to :post" do
180
+ lambda { @session.post("/test", nil) }.should raise_error(ArgumentError)
181
+ end
182
+
183
+ it "should upload a file with :post" do
184
+ response = @session.post_file("/test", "LICENSE")
185
+ body = YAML::load(response.body)
186
+ body.request_method.should == "POST"
187
+ end
188
+
189
+ it "should upload a multipart with :post" do
190
+ response = @session.post_multipart("/test", { :test_data => "123" }, { :test_file => "LICENSE" } )
191
+ body = YAML::load(response.body)
192
+ body.request_method.should == "POST"
193
+ end
194
+
195
+ it "should raise when no file is provided to :post" do
196
+ lambda { @session.post_file("/test", nil) }.should raise_error(ArgumentError)
197
+ end
198
+
199
+ it "should use chunked encoding when uploading a file with :post" do
200
+ response = @session.post_file("/test", "LICENSE")
201
+ body = YAML::load(response.body)
202
+ body.header['transfer-encoding'].first.should == "chunked"
203
+ end
204
+
205
+ it "should handle cookies if set" do
206
+ @session.handle_cookies
207
+ response = @session.get("/setcookie").body
208
+ YAML::load(response).header['cookie'].first.should == "session_id=foo123"
209
+ end
210
+
211
+ it "should not handle cookies by default" do
212
+ response = @session.get("/setcookie").body
213
+ YAML::load(response).header.should_not include('cookie')
214
+ end
215
+
216
+ it "should ignore a wrong Content-Length when asked to" do
217
+ lambda {
218
+ @session.ignore_content_length = true
219
+ @session.get("/wrongcontentlength")
220
+ }.should_not raise_error
221
+ end
222
+
223
+ it "should fail by default with a Content-Length too high" do
224
+ lambda {
225
+ @session.ignore_content_length = nil
226
+ @session.get("/wrongcontentlength")
227
+ }.should raise_error(Patron::PartialFileError)
228
+ end
229
+
230
+ it "should raise exception if cookie store is not writable or readable" do
231
+ lambda { @session.handle_cookies("/trash/clash/foo") }.should raise_error(ArgumentError)
232
+ end
233
+
234
+ it "should work with multiple threads" do
235
+ threads = []
236
+ 3.times do
237
+ threads << Thread.new do
238
+ session = Patron::Session.new
239
+ session.base_url = "https://localhost:9043"
240
+ session.insecure = true
241
+ session.post_file("/test", "LICENSE")
242
+ end
243
+ end
244
+ threads.each {|t| t.join }
245
+ end
246
+
247
+ xit "should fail when insecure mode is off" do
248
+ # This spec fails, but I suspect that it is a setup problem.
249
+ lambda {
250
+ @session.insecure = nil
251
+ response = @session.get("/test")
252
+ }.should raise_error(Patron::Error)
253
+ end
254
+
255
+ it "should work when insecure mode is off but certificate is supplied" do
256
+ @session.insecure = nil
257
+ @session.cacert = 'spec/certs/cacert.pem'
258
+ response = @session.get("/test")
259
+ body = YAML::load(response.body)
260
+ body.request_method.should == "GET"
261
+ end
262
+
263
+ it "should work with different SSL versions" do
264
+ ['SSLv3', 'TLSv1'].each do |version|
265
+ @session.ssl_version = version
266
+ response = @session.get("/test")
267
+ response.status.should == 200
268
+ end
269
+ end
270
+
271
+ # ------------------------------------------------------------------------
272
+ describe 'when debug is enabled' do
273
+ it 'it should not clobber stderr' do
274
+ rdev = STDERR.stat.rdev
275
+
276
+ @session.enable_debug
277
+ STDERR.stat.rdev.should be == rdev
278
+
279
+ @session.enable_debug
280
+ STDERR.stat.rdev.should be == rdev
281
+ end
282
+ end
283
+
284
+ end
data/spec/spec_helper.rb CHANGED
@@ -29,4 +29,5 @@ require 'patron'
29
29
 
30
30
  Dir['./spec/support/**/*.rb'].each { |fn| require fn }
31
31
 
32
- PatronTestServer.start if RUBY_VERSION >= '1.9'
32
+ PatronTestServer.start(nil, false, 9001) if RUBY_VERSION >= '1.9'
33
+ PatronTestServer.start(nil, true, 9043) if RUBY_VERSION >= '1.9'
@@ -24,6 +24,9 @@
24
24
  ## -------------------------------------------------------------------
25
25
  require 'yaml'
26
26
  require 'webrick'
27
+ require 'webrick/https'
28
+ require 'openssl'
29
+
27
30
  include WEBrick
28
31
 
29
32
  # This ugly little hack is necessary to make the specs pass when running
@@ -125,22 +128,32 @@ end
125
128
 
126
129
  class PatronTestServer
127
130
 
128
- def self.start( log_file = nil )
129
- new(log_file).start
131
+ def self.start( log_file = nil, ssl = false, port = 9001 )
132
+ new(log_file, ssl, port).start
130
133
  end
131
134
 
132
- def initialize( log_file = nil )
135
+ def initialize( log_file = nil, ssl = false, port = 9001 )
133
136
  log_file ||= StringIO.new
134
137
  log = WEBrick::Log.new(log_file)
135
138
 
136
- @server = WEBrick::HTTPServer.new(
137
- :Port => 9001,
139
+ options = {
140
+ :Port => port,
138
141
  :Logger => log,
139
142
  :AccessLog => [
140
143
  [ log, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
141
144
  [ log, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
142
145
  ]
143
- )
146
+ }
147
+
148
+ if ssl
149
+ options[:SSLEnable] = true
150
+ options[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.open("spec/certs/cacert.pem").read)
151
+ options[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.open("spec/certs/privkey.pem").read)
152
+ options[:SSLCertName] = [ ["CN", WEBrick::Utils::getservername ] ]
153
+ end
154
+
155
+ @server = WEBrick::HTTPServer.new(options)
156
+
144
157
  @server.mount("/test", TestServlet)
145
158
  @server.mount("/testpost", TestPostBodyServlet)
146
159
  @server.mount("/timeout", TimeoutServlet)
@@ -149,6 +162,7 @@ class PatronTestServer
149
162
  @server.mount("/setcookie", SetCookieServlet)
150
163
  @server.mount("/repetitiveheader", RepetitiveHeaderServlet)
151
164
  @server.mount("/wrongcontentlength", WrongContentLengthServlet)
165
+
152
166
  end
153
167
 
154
168
  def start
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.18
4
+ version: 0.4.20
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-05 00:00:00.000000000 Z
12
+ date: 2015-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
- requirement: &70336820705120 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 1.0.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70336820705120
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.0
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rake-compiler
27
- requirement: &70336820704660 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: 0.7.5
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *70336820704660
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.7.5
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rspec
38
- requirement: &70336820704200 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: 2.3.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70336820704200
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.3.0
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: rcov
49
- requirement: &70336820703740 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,7 +69,12 @@ dependencies:
54
69
  version: 0.9.9
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *70336820703740
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 0.9.9
58
78
  description: Ruby HTTP client library based on libcurl
59
79
  email:
60
80
  - phil.toland@gmail.com
@@ -69,7 +89,7 @@ files:
69
89
  - Gemfile
70
90
  - Gemfile.lock
71
91
  - LICENSE
72
- - README.txt
92
+ - README.md
73
93
  - Rakefile
74
94
  - ext/patron/.gitignore
75
95
  - ext/patron/extconf.rb
@@ -89,10 +109,13 @@ files:
89
109
  - pic.png
90
110
  - script/console
91
111
  - script/test_server
112
+ - spec/certs/cacert.pem
113
+ - spec/certs/privkey.pem
92
114
  - spec/patron_spec.rb
93
115
  - spec/request_spec.rb
94
116
  - spec/response_spec.rb
95
117
  - spec/session_spec.rb
118
+ - spec/session_ssl_spec.rb
96
119
  - spec/spec_helper.rb
97
120
  - spec/support/test_server.rb
98
121
  - spec/util_spec.rb
@@ -117,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
140
  version: 1.2.0
118
141
  requirements: []
119
142
  rubyforge_project: patron
120
- rubygems_version: 1.8.10
143
+ rubygems_version: 1.8.23
121
144
  signing_key:
122
145
  specification_version: 3
123
146
  summary: Patron HTTP Client