patron 0.4.14 → 0.4.15

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.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ .rbenv*
2
+ .rvmrc
1
3
  *.bundle
2
4
  coverage
3
5
  rdoc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- patron (0.4.13)
4
+ patron (0.4.15)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -355,23 +355,25 @@ static void set_options_from_request(VALUE self, VALUE request) {
355
355
  }
356
356
 
357
357
  // Use the info in a Curl handle to create a new Response object.
358
- static VALUE create_response(CURL* curl) {
359
- VALUE response = rb_class_new_instance(0, 0,
360
- rb_const_get(mPatron, rb_intern("Response")));
361
-
362
- char* url = NULL;
363
- curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
364
- rb_iv_set(response, "@url", rb_str_new2(url));
358
+ static VALUE create_response(VALUE self, CURL* curl, VALUE header_buffer, VALUE body_buffer) {
359
+ char* effective_url = NULL;
360
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
361
+ VALUE url = rb_str_new2(effective_url);
365
362
 
366
363
  long code = 0;
367
364
  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
368
- rb_iv_set(response, "@status", INT2NUM(code));
365
+ VALUE status = INT2NUM(code);
369
366
 
370
367
  long count = 0;
371
368
  curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &count);
372
- rb_iv_set(response, "@redirect_count", INT2NUM(count));
369
+ VALUE redirect_count = INT2NUM(count);
370
+
371
+ VALUE default_charset = rb_iv_get(self, "@default_response_charset");
373
372
 
374
- return response;
373
+ VALUE args[6] = { url, status, redirect_count, header_buffer, body_buffer, default_charset };
374
+
375
+ return rb_class_new_instance(6, args,
376
+ rb_const_get(mPatron, rb_intern("Response")));
375
377
  }
376
378
 
377
379
  // Raise an exception based on the Curl error code.
@@ -419,12 +421,7 @@ static VALUE perform_request(VALUE self) {
419
421
  #endif
420
422
 
421
423
  if (CURLE_OK == ret) {
422
- VALUE response = create_response(curl);
423
- if (!NIL_P(body_buffer)) {
424
- rb_iv_set(response, "@body", body_buffer);
425
- }
426
- rb_funcall(response, rb_intern("parse_headers"), 1, header_buffer);
427
- return response;
424
+ return create_response(self, curl, header_buffer, body_buffer);
428
425
  } else {
429
426
  rb_raise(select_error(ret), "%s", state->error_buf);
430
427
  }
@@ -28,11 +28,22 @@ module Patron
28
28
  # Represents the response from the HTTP server.
29
29
  class Response
30
30
 
31
- def initialize
32
- @headers = {}
31
+ def initialize(url, status, redirect_count, header_data, body, default_charset = "ASCII-8BIT")
32
+ @url = url
33
+ @status = status
34
+ @redirect_count = redirect_count
35
+ @body = body
36
+
37
+ @charset = determine_charset(header_data, body) || default_charset
38
+
39
+ [url, header_data, body].each do |attr|
40
+ convert_to_default_encoding!(attr)
41
+ end
42
+
43
+ parse_headers(header_data)
33
44
  end
34
45
 
35
- attr_reader :url, :status, :status_line, :redirect_count, :body, :headers
46
+ attr_reader :url, :status, :status_line, :redirect_count, :body, :headers, :charset
36
47
 
37
48
  def inspect
38
49
  # Avoid spamming the console with the header and body data
@@ -41,8 +52,26 @@ module Patron
41
52
 
42
53
  private
43
54
 
55
+ def determine_charset(header_data, body)
56
+ header_data.match(charset_regex) || (body && body.match(charset_regex))
57
+
58
+ $1
59
+ end
60
+
61
+ def charset_regex
62
+ /(?:charset|encoding)="?([a-z0-9-]+)"?/i
63
+ end
64
+
65
+ def convert_to_default_encoding!(str)
66
+ if str.respond_to?(:encode) && Encoding.default_internal
67
+ str.force_encoding(charset).encode!(Encoding.default_internal)
68
+ end
69
+ end
70
+
44
71
  # Called by the C code to parse and set the headers
45
72
  def parse_headers(header_data)
73
+ @headers = {}
74
+
46
75
  header_data.split(/\r\n/).each do |header|
47
76
  if header =~ %r|^HTTP/1.[01]|
48
77
  @status_line = header.strip
@@ -75,6 +75,9 @@ module Patron
75
75
  # only be set if buffer_size is non-nil
76
76
  attr_accessor :buffer_size
77
77
 
78
+ # Default encoding of responses. Used if no charset is provided by the host.
79
+ attr_accessor :default_response_charset
80
+
78
81
  private :ext_initialize, :handle_request, :enable_cookie_session, :set_debug_file
79
82
 
80
83
  # Create a new Session object.
@@ -150,8 +153,12 @@ module Patron
150
153
  end
151
154
 
152
155
  # Uploads the passed +data+ to the specified +url+ using HTTP POST. +data+
153
- # must be a string.
156
+ # can be a string or a hash.
154
157
  def post(url, data, headers = {})
158
+ if data.is_a?(Hash)
159
+ data = data.map {|k,v| urlencode(k.to_s) + '=' + urlencode(v.to_s) }.join('&')
160
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
161
+ end
155
162
  request(:post, url, headers, :data => data)
156
163
  end
157
164
 
@@ -185,22 +192,22 @@ module Patron
185
192
  headers['Expect'] ||= ''
186
193
 
187
194
  req = Request.new
188
- req.action = action
189
- req.timeout = self.timeout
190
- req.connect_timeout = self.connect_timeout
191
- req.max_redirects = self.max_redirects
192
- req.headers = self.headers.merge(headers)
193
- req.username = self.username
194
- req.password = self.password
195
- req.multipart = options[:multipart]
196
- req.upload_data = options[:data]
197
- req.file_name = options[:file]
198
- req.proxy = proxy
199
- req.proxy_type = proxy_type
200
- req.auth_type = auth_type
201
- req.insecure = insecure
202
- req.ignore_content_length = ignore_content_length
203
- req.buffer_size = buffer_size
195
+ req.action = action
196
+ req.headers = self.headers.merge headers
197
+ req.timeout = options.fetch :timeout, self.timeout
198
+ req.connect_timeout = options.fetch :connect_timeout, self.connect_timeout
199
+ req.max_redirects = options.fetch :max_redirects, self.max_redirects
200
+ req.username = options.fetch :username, self.username
201
+ req.password = options.fetch :password, self.password
202
+ req.proxy = options.fetch :proxy, self.proxy
203
+ req.proxy_type = options.fetch :proxy_type, self.proxy_type
204
+ req.auth_type = options.fetch :auth_type, self.auth_type
205
+ req.insecure = options.fetch :insecure, self.insecure
206
+ req.ignore_content_length = options.fetch :ignore_content_length, self.ignore_content_length
207
+ req.buffer_size = options.fetch :buffer_size, self.buffer_size
208
+ req.multipart = options[:multipart]
209
+ req.upload_data = options[:data]
210
+ req.file_name = options[:file]
204
211
 
205
212
  url = self.base_url.to_s + url.to_s
206
213
  uri = URI.parse(url)
@@ -214,5 +221,12 @@ module Patron
214
221
 
215
222
  handle_request(req)
216
223
  end
224
+
225
+ private
226
+
227
+ def urlencode(str)
228
+ str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0].ord) }
229
+ end
230
+
217
231
  end
218
232
  end
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.4.14"
2
+ VERSION = "0.4.15"
3
3
  end
data/script/test_server CHANGED
@@ -36,11 +36,16 @@ class URI::Parser
36
36
  end
37
37
  end
38
38
 
39
- class TestServlet < HTTPServlet::AbstractServlet
39
+ module RespondWith
40
40
  def respond_with(method, req, res)
41
41
  res.body = req.to_yaml
42
42
  res['Content-Type'] = "text/plain"
43
43
  end
44
+ end
45
+
46
+ class TestServlet < HTTPServlet::AbstractServlet
47
+
48
+ include RespondWith
44
49
 
45
50
  def do_GET(req,res)
46
51
  respond_with(:GET, req, res)
@@ -76,6 +81,16 @@ class RedirectServlet < HTTPServlet::AbstractServlet
76
81
  end
77
82
  end
78
83
 
84
+
85
+ class TestPostBodyServlet < HTTPServlet::AbstractServlet
86
+ include RespondWith
87
+ def do_POST(req, res)
88
+ respond_with(:POST, {'body' => req.body, 'content_type' => req.content_type}, res)
89
+ end
90
+ end
91
+
92
+
93
+
79
94
  class SetCookieServlet < HTTPServlet::AbstractServlet
80
95
  def do_GET(req, res)
81
96
  res['Set-Cookie'] = "session_id=foo123"
@@ -104,6 +119,7 @@ end
104
119
 
105
120
  server = WEBrick::HTTPServer.new :Port => 9001
106
121
  server.mount("/test", TestServlet)
122
+ server.mount("/testpost", TestPostBodyServlet)
107
123
  server.mount("/timeout", TimeoutServlet)
108
124
  server.mount("/redirect", RedirectServlet)
109
125
  server.mount("/setcookie", SetCookieServlet)
data/spec/session_spec.rb CHANGED
@@ -23,6 +23,7 @@
23
23
  ## -------------------------------------------------------------------
24
24
  require File.expand_path("./spec") + '/spec_helper.rb'
25
25
  require 'webrick'
26
+ require 'yaml'
26
27
  require 'base64'
27
28
  require 'fileutils'
28
29
 
@@ -165,6 +166,15 @@ describe Patron::Session do
165
166
  body.header['content-length'].should == [data.size.to_s]
166
167
  end
167
168
 
169
+ it "should post a hash of arguments as a urlencoded form" do
170
+ data = {:foo => 123, 'baz' => '++hello world++'}
171
+ response = @session.post("/testpost", data)
172
+ body = YAML::load(response.body)
173
+ body['content_type'].should == "application/x-www-form-urlencoded"
174
+ body['body'].should match(/baz=%2b%2bhello%20world%2b%2b/)
175
+ body['body'].should match(/foo=123/)
176
+ end
177
+
168
178
  it "should raise when no data is provided to :post" do
169
179
  lambda { @session.post("/test", nil) }.should raise_error(ArgumentError)
170
180
  end
metadata CHANGED
@@ -1,76 +1,71 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: patron
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.15
4
5
  prerelease:
5
- version: 0.4.14
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Phillip Toland
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-07-28 00:00:00 -05:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2011-08-24 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
17
15
  name: bundler
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2157493740 !ruby/object:Gem::Requirement
20
17
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
24
21
  version: 1.0.0
25
22
  type: :development
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: rake-compiler
29
23
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2157493740
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake-compiler
27
+ requirement: &2157493280 !ruby/object:Gem::Requirement
31
28
  none: false
32
- requirements:
29
+ requirements:
33
30
  - - ~>
34
- - !ruby/object:Gem::Version
31
+ - !ruby/object:Gem::Version
35
32
  version: 0.7.5
36
33
  type: :development
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: rspec
40
34
  prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *2157493280
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2157492820 !ruby/object:Gem::Requirement
42
39
  none: false
43
- requirements:
40
+ requirements:
44
41
  - - ~>
45
- - !ruby/object:Gem::Version
42
+ - !ruby/object:Gem::Version
46
43
  version: 2.3.0
47
44
  type: :development
48
- version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
50
- name: rcov
51
45
  prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
46
+ version_requirements: *2157492820
47
+ - !ruby/object:Gem::Dependency
48
+ name: rcov
49
+ requirement: &2157492360 !ruby/object:Gem::Requirement
53
50
  none: false
54
- requirements:
51
+ requirements:
55
52
  - - ~>
56
- - !ruby/object:Gem::Version
53
+ - !ruby/object:Gem::Version
57
54
  version: 0.9.9
58
55
  type: :development
59
- version_requirements: *id004
56
+ prerelease: false
57
+ version_requirements: *2157492360
60
58
  description: Ruby HTTP client library based on libcurl
61
- email:
59
+ email:
62
60
  - phil.toland@gmail.com
63
61
  executables: []
64
-
65
- extensions:
62
+ extensions:
66
63
  - ext/patron/extconf.rb
67
64
  extra_rdoc_files: []
68
-
69
- files:
65
+ files:
70
66
  - .autotest
71
67
  - .gitignore
72
68
  - .rspec
73
- - .rvmrc
74
69
  - Gemfile
75
70
  - Gemfile.lock
76
71
  - LICENSE
@@ -96,34 +91,29 @@ files:
96
91
  - spec/session_spec.rb
97
92
  - spec/spec_helper.rb
98
93
  - spec/util_spec.rb
99
- has_rdoc: true
100
94
  homepage: https://github.com/toland/patron
101
95
  licenses: []
102
-
103
96
  post_install_message:
104
97
  rdoc_options: []
105
-
106
- require_paths:
98
+ require_paths:
107
99
  - lib
108
100
  - ext
109
- required_ruby_version: !ruby/object:Gem::Requirement
101
+ required_ruby_version: !ruby/object:Gem::Requirement
110
102
  none: false
111
- requirements:
112
- - - ">="
113
- - !ruby/object:Gem::Version
114
- version: "0"
115
- required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
108
  none: false
117
- requirements:
118
- - - ">="
119
- - !ruby/object:Gem::Version
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
120
112
  version: 1.2.0
121
113
  requirements: []
122
-
123
114
  rubyforge_project: patron
124
- rubygems_version: 1.6.2
115
+ rubygems_version: 1.8.7
125
116
  signing_key:
126
117
  specification_version: 3
127
118
  summary: Patron HTTP Client
128
119
  test_files: []
129
-
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm gemset use patron