patron 0.4.14 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
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