patron 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/lib/patron/error.rb +17 -8
- data/lib/patron/response.rb +59 -37
- data/lib/patron/response_decoding.rb +128 -0
- data/lib/patron/session.rb +4 -3
- data/lib/patron/version.rb +1 -1
- data/spec/response_spec.rb +59 -33
- data/spec/session_spec.rb +4 -3
- data/spec/spec_helper.rb +1 -0
- data/spec/support/test_server.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e89c04473c18143c350dcbbbf6f98b1c66b2e7e
|
4
|
+
data.tar.gz: 5a019a6f724c14056f949eb4fafb538454b959c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6468281adbd09ad4cbc02eaaa64c36926e108ecd6c9b7a38ffcf8223e5c9930147197c858dac1d30b0f728ece4065f97f32604e07f4016036363b5e110f30ce6
|
7
|
+
data.tar.gz: 897c874cf04b2f3d8fa5e327a5cc78bd86d3ba4a6b27828812c67bc3433cdc0d4c4e6bad266ef655a9349d8f7d711cd95d60bd8c166ede3c8456c788fcc21197
|
data/.travis.yml
CHANGED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
### 0.8.0
|
2
|
+
|
3
|
+
* Add `Response#inspectable_body`, `Response#decoded_body`. `decoded_body` will atempt to decode
|
4
|
+
the HTTP response into your internal encoding, using the charset header that the server has
|
5
|
+
provided. Note that this operation may fail - if the server said that the body is in a certain
|
6
|
+
encoding, but this is then overridden with, say, `meta` elements in the HTML Patron is _not_
|
7
|
+
going to parse the HTML to figure out how to decode.
|
8
|
+
|
1
9
|
### 0.7.0
|
2
10
|
|
3
11
|
* Allow Ruby File objects to be passed as `data` to `Session#put`, `Sesion#post` etc.
|
data/Gemfile.lock
CHANGED
data/lib/patron/error.rb
CHANGED
@@ -31,29 +31,38 @@ module Patron
|
|
31
31
|
|
32
32
|
# Gets raised when the URL passed to Patron used a protocol that it does not support.
|
33
33
|
# This most likely the result of a misspelled protocol string.
|
34
|
-
class UnsupportedProtocol
|
34
|
+
class UnsupportedProtocol < Error; end
|
35
35
|
|
36
36
|
# Gets raised when a request is attempted with an unsupported SSL version.
|
37
|
-
class UnsupportedSSLVersion
|
37
|
+
class UnsupportedSSLVersion < Error; end
|
38
38
|
|
39
39
|
# Gets raised when the URL was not properly formatted.
|
40
|
-
class URLFormatError
|
40
|
+
class URLFormatError < Error; end
|
41
41
|
|
42
42
|
# Gets raised when the remote host name could not be resolved.
|
43
|
-
class HostResolutionError
|
43
|
+
class HostResolutionError < Error; end
|
44
44
|
|
45
45
|
# Gets raised when failing to connect to the remote host.
|
46
|
-
class ConnectionFailed
|
46
|
+
class ConnectionFailed < Error; end
|
47
47
|
|
48
48
|
# Gets raised when the response was shorter or larger than expected.
|
49
49
|
# This happens when the server first reports an expected transfer size,
|
50
50
|
# and then delivers data that doesn't match the previously given size.
|
51
|
-
class PartialFileError
|
51
|
+
class PartialFileError < Error; end
|
52
52
|
|
53
53
|
# Gets raised on an operation timeout. The specified time-out period was reached.
|
54
|
-
class TimeoutError
|
54
|
+
class TimeoutError < Error; end
|
55
55
|
|
56
56
|
# Gets raised on too many redirects. When following redirects, Patron hit the maximum amount.
|
57
|
-
class TooManyRedirects
|
57
|
+
class TooManyRedirects < Error; end
|
58
58
|
|
59
|
+
# Gets raised when the server specifies an encoding that could not be found, or has an invalid name,
|
60
|
+
# or when the server "lies" about the encoding of the response body (such as can be the case
|
61
|
+
# when the server specifies an encoding in `Content-Type`) which the HTML generator then overrides
|
62
|
+
# with a `meta` element.
|
63
|
+
class HeaderCharsetInvalid < Error; end
|
64
|
+
|
65
|
+
# Gets raised when you try to use `decoded_body` but it can't
|
66
|
+
# be represented by your Ruby process's current internal encoding
|
67
|
+
class NonRepresentableBody < HeaderCharsetInvalid; end
|
59
68
|
end
|
data/lib/patron/response.rb
CHANGED
@@ -28,6 +28,8 @@ module Patron
|
|
28
28
|
|
29
29
|
# Represents the response from the HTTP server.
|
30
30
|
class Response
|
31
|
+
include ResponseDecoding
|
32
|
+
|
31
33
|
# @return [String] the original URL used to perform the request (contains the final URL after redirects)
|
32
34
|
attr_reader :url
|
33
35
|
|
@@ -40,14 +42,16 @@ module Patron
|
|
40
42
|
# @return [Fixnum] how many redirects were followed when fulfilling this request
|
41
43
|
attr_reader :redirect_count
|
42
44
|
|
43
|
-
# @return [String, nil] the response body
|
45
|
+
# @return [String, nil] the response body as a String encoded as `Encoding::BINARY` or
|
46
|
+
# or `nil` if the response was written directly to a file
|
44
47
|
attr_reader :body
|
45
|
-
|
48
|
+
|
46
49
|
# @return [Hash] the response headers. If there were multiple headers received for the same value
|
47
50
|
# (like "Cookie"), the header values will be within an Array under the key for the header, in order.
|
48
51
|
attr_reader :headers
|
49
52
|
|
50
|
-
# @return [String] the recognized name of the charset for the response
|
53
|
+
# @return [String] the recognized name of the charset for the response. The name is not checked
|
54
|
+
# to be a valid charset name, just stored. To check the charset for validity, use #body_decodable?
|
51
55
|
attr_reader :charset
|
52
56
|
|
53
57
|
# Overridden so that the output is shorter and there is no response body printed
|
@@ -56,24 +60,15 @@ module Patron
|
|
56
60
|
"#<Patron::Response @status_line='#{@status_line}'>"
|
57
61
|
end
|
58
62
|
|
59
|
-
def initialize(url, status, redirect_count,
|
60
|
-
|
61
|
-
default_charset = "ASCII-8BIT" unless default_charset
|
62
|
-
@url = url
|
63
|
+
def initialize(url, status, redirect_count, raw_header_data, body, default_charset = nil)
|
64
|
+
@url = url.force_encoding(Encoding::ASCII) # the URL is always an ASCII subset, _always_.
|
63
65
|
@status = status
|
64
66
|
@redirect_count = redirect_count
|
65
|
-
@body = body
|
66
|
-
|
67
|
-
@charset = determine_charset(header_data, body) || default_charset
|
68
|
-
|
69
|
-
[url, header_data].each do |attr|
|
70
|
-
convert_to_default_encoding!(attr)
|
71
|
-
end
|
67
|
+
@body = body.force_encoding(Encoding::BINARY) if body
|
72
68
|
|
69
|
+
header_data = decode_header_data(raw_header_data)
|
73
70
|
parse_headers(header_data)
|
74
|
-
|
75
|
-
convert_to_default_encoding!(@body)
|
76
|
-
end
|
71
|
+
@charset = charset_from_content_type
|
77
72
|
end
|
78
73
|
|
79
74
|
# Tells whether the HTTP response code is less than 400
|
@@ -90,30 +85,58 @@ module Patron
|
|
90
85
|
status >= 400
|
91
86
|
end
|
92
87
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
88
|
+
# Tells whether the response body can be decoded losslessly into the curren internal encoding
|
89
|
+
#
|
90
|
+
# @return [Boolean] true if the body is decodable, false if otherwise
|
91
|
+
def body_decodable?
|
92
|
+
return true if @body.nil?
|
93
|
+
return true if decoded_body
|
94
|
+
rescue HeaderCharsetInvalid, NonRepresentableBody
|
95
|
+
false
|
100
96
|
end
|
101
97
|
|
102
|
-
|
103
|
-
|
98
|
+
# Returns the response body converted into the Ruby process internal encoding (the one set as `Encoding.default_internal`).
|
99
|
+
# As the response gets returned, the response body is not assumed to be in any encoding whatsoever - it will be explicitly
|
100
|
+
# set to `Encoding::BINARY` (as if you were reading a file in binary mode).
|
101
|
+
#
|
102
|
+
# When you call `decoded_body`, the method will
|
103
|
+
# look at the `Content-Type` response header, and check if that header specified a charset. If it did, the method will then
|
104
|
+
# check whether the specified charset is valid (whether it is possible to find a matching `Encoding` class in the VM).
|
105
|
+
# Once that succeeds, the method will check whether the response body _is_ in the encoding that the server said it is.
|
106
|
+
#
|
107
|
+
# This might not be the case - you can, for instance, easily serve an HTML document with a UTF-8 header (with the header
|
108
|
+
# being configured somewhere on the webserver level) and then have the actual HTML document override it with a
|
109
|
+
# `meta` element or `charset` containing an overriding charset. However, parsing the response body is outside of scope for
|
110
|
+
# Patron, so if this situation happens (the server sets a charset in the header but this header does not match what the server
|
111
|
+
# actually sends in the body) you will get an exception stating this is a problem.
|
112
|
+
#
|
113
|
+
# The next step is actually converting the body to the internal Ruby encoding. That stage may raise an exception as well, if
|
114
|
+
# you are using an internal encoding which can't represent the response body faithfully. For example, if you run Ruby with
|
115
|
+
# a CJK internal encoding, and the response you are trying to decode uses Greek characters and is UTF-8, you are going to
|
116
|
+
# get an exception since it is impossible to coerce those characters to your internal encoding.
|
117
|
+
#
|
118
|
+
# @raise {Patron::HeaderCharsetInvalid} when the server supplied a wrong or incorrect charset, {Patron::NonRepresentableBody}
|
119
|
+
# when unable to decode the body into the current process encoding.
|
120
|
+
# @return [String, nil]
|
121
|
+
def decoded_body
|
122
|
+
return unless @body
|
123
|
+
@decoded_body ||= decode_body(true)
|
104
124
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
125
|
+
|
126
|
+
# Works the same as `decoded_body`, with one substantial difference: characters which can't be represented
|
127
|
+
# in your process' default encoding are going to be replaced with question marks. This can be used for raising
|
128
|
+
# errors when you receive responses which indicate errors on the server you are calling. For example, if you expect
|
129
|
+
# a binary download, and the server sends you an error message and you don't really want to bother figuring out
|
130
|
+
# the encoding it has - but you need to append this response to an error log or similar.
|
131
|
+
#
|
132
|
+
# @see Patron::Response#decoded_body
|
133
|
+
# @return [String, nil]
|
134
|
+
def inspectable_body
|
135
|
+
return unless @body
|
136
|
+
@inspectable_body ||= decode_body(false)
|
110
137
|
end
|
111
138
|
|
112
|
-
|
113
|
-
if str.respond_to?(:encode) && Encoding.default_internal
|
114
|
-
str.force_encoding(charset).encode!(Encoding.default_internal)
|
115
|
-
end
|
116
|
-
end
|
139
|
+
private
|
117
140
|
|
118
141
|
# Called by the C code to parse and set the headers
|
119
142
|
def parse_headers(header_data)
|
@@ -138,6 +161,5 @@ module Patron
|
|
138
161
|
end
|
139
162
|
end
|
140
163
|
end
|
141
|
-
|
142
164
|
end
|
143
165
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Patron HTTP Client: Response class
|
4
|
+
## Copyright (c) 2008 The Hive http://www.thehive.com/
|
5
|
+
##
|
6
|
+
## Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
## of this software and associated documentation files (the "Software"), to deal
|
8
|
+
## in the Software without restriction, including without limitation the rights
|
9
|
+
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
## copies of the Software, and to permit persons to whom the Software is
|
11
|
+
## furnished to do so, subject to the following conditions:
|
12
|
+
##
|
13
|
+
## The above copyright notice and this permission notice shall be included in
|
14
|
+
## all copies or substantial portions of the Software.
|
15
|
+
##
|
16
|
+
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
## THE SOFTWARE.
|
23
|
+
##
|
24
|
+
## -------------------------------------------------------------------
|
25
|
+
|
26
|
+
|
27
|
+
module Patron
|
28
|
+
# Contains methods used for decoding the HTTP response body. These are only ever used internally
|
29
|
+
# by the Response class.
|
30
|
+
module ResponseDecoding
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
CHARSET_CONTENT_TYPE_RE = /(?:charset|encoding)="?([a-z0-9-]+)"?/i.freeze
|
35
|
+
|
36
|
+
MISREPORTED_ENCODING_ERROR = <<-EOF
|
37
|
+
The server stated that the response has the charset matching %{declared}, but the actual
|
38
|
+
response body failed to decode as such (not flagged as `valid_encoding?')
|
39
|
+
Maybe the response body has a different encoding than suggested by the
|
40
|
+
server, or a binary response has been tagged by the server as text by mistake.
|
41
|
+
If you are performing requests against servers that are known to report wrong or invalid charsets, use
|
42
|
+
`Response#body' instead and handle the character set coercion externally. For instance, you may elect to parse
|
43
|
+
the resulting HTML/XML for charset declarations.
|
44
|
+
EOF
|
45
|
+
|
46
|
+
INVALID_CHARSET_NAME_ERROR = <<-EOF
|
47
|
+
The server specified an invalid charset in the Content-Type header (%{content_type}), \
|
48
|
+
or Ruby does not support this charset. If you are performing requests against servers \
|
49
|
+
that are known to report wrong or invalid charsets, use 'Response#body` instead \
|
50
|
+
and handle the character set coercion at call site.
|
51
|
+
EOF
|
52
|
+
|
53
|
+
INTERNAL_CHARSET_MISMATCH_ERROR = <<-EOF
|
54
|
+
The response body is %{source_encoding}, but the current \
|
55
|
+
`Encoding.default_internal' (or the encoding for a new empty string if you never \
|
56
|
+
set `Encoding.default_internal') - %{target_encoding} - cannot be used to represent the response body in \
|
57
|
+
a lossless way. Your options are:
|
58
|
+
a) using `Response#body' instead
|
59
|
+
b) switching your Ruby process to an encoding that supports the needed repertoire
|
60
|
+
c) using `Response#inspectable_body' to convert the body in a lossy way
|
61
|
+
EOF
|
62
|
+
|
63
|
+
def decode_body(strict)
|
64
|
+
# Try to detect the body encoding from headers
|
65
|
+
body_encoding = encoding_from_headers_or_binary
|
66
|
+
|
67
|
+
# See if the body actually _is_ in this encoding.
|
68
|
+
encoding_matched = @body.force_encoding(body_encoding).valid_encoding?
|
69
|
+
if !encoding_matched
|
70
|
+
raise HeaderCharsetInvalid, MISREPORTED_ENCODING_ERROR % {declared: body_encoding}
|
71
|
+
end
|
72
|
+
|
73
|
+
if strict
|
74
|
+
convert_encoding_and_raise(@body)
|
75
|
+
else
|
76
|
+
@body.encode(internal_encoding, :undefined => :replace, :replace => '?')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def convert_encoding_and_raise(str)
|
81
|
+
internal = internal_encoding
|
82
|
+
str.encode(internal)
|
83
|
+
rescue Encoding::UndefinedConversionError => e
|
84
|
+
enc = str.encoding == Encoding::BINARY ? 'binary' : str.encoding.to_s
|
85
|
+
raise NonRepresentableBody,
|
86
|
+
INTERNAL_CHARSET_MISMATCH_ERROR % {source_encoding: enc, target_encoding: internal}
|
87
|
+
end
|
88
|
+
|
89
|
+
def charset_from_content_type
|
90
|
+
return $1 if @headers["Content-Type"].to_s =~ CHARSET_CONTENT_TYPE_RE
|
91
|
+
end
|
92
|
+
|
93
|
+
def encoding_from_headers_or_binary
|
94
|
+
return Encoding::BINARY unless charset_name = charset_from_content_type
|
95
|
+
Encoding.find(charset_name)
|
96
|
+
rescue ArgumentError => e # invalid charset name
|
97
|
+
raise HeaderCharsetInvalid,
|
98
|
+
INVALID_CHARSET_NAME_ERROR % {content_type: @headers['Content-Type'].inspect}
|
99
|
+
end
|
100
|
+
|
101
|
+
def internal_encoding
|
102
|
+
# Use a trick here - instead of using `default_internal` we will create
|
103
|
+
# an empty string, and then get it's encoding instead. For example, this holds
|
104
|
+
# true on 2.1+ on OSX:
|
105
|
+
#
|
106
|
+
# Encoding.default_internal #=> nil
|
107
|
+
# ''.encoding #=> #<Encoding:UTF-8>
|
108
|
+
Encoding.default_internal || ''.encoding
|
109
|
+
end
|
110
|
+
|
111
|
+
def decode_header_data(str)
|
112
|
+
# Header data is tricky. Strictly speaking, it _must_ be ISO-encoded. However, Content-Disposition
|
113
|
+
# sometimes gets sent as raw UTF8 - and most browsers (except for localized IE versions on Windows)
|
114
|
+
# treat it as such. So a fallback chain of 8859-1->UTF8->binary seems the most sane.
|
115
|
+
tries = [Encoding::ISO8859_1, Encoding::UTF_8, Encoding::BINARY]
|
116
|
+
tries.each do |possible_enc|
|
117
|
+
begin
|
118
|
+
return str.encode(possible_enc)
|
119
|
+
rescue ::Encoding::UndefinedConversionError
|
120
|
+
next
|
121
|
+
end
|
122
|
+
end
|
123
|
+
str # if it doesn't encode, just give back what we got
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private_constant :ResponseDecoding if respond_to?(:private_constant)
|
128
|
+
end
|
data/lib/patron/session.rb
CHANGED
@@ -27,6 +27,7 @@
|
|
27
27
|
require 'uri'
|
28
28
|
require 'patron/error'
|
29
29
|
require 'patron/request'
|
30
|
+
require 'patron/response_decoding'
|
30
31
|
require 'patron/response'
|
31
32
|
require 'patron/session_ext'
|
32
33
|
require 'patron/util'
|
@@ -347,9 +348,9 @@ module Patron
|
|
347
348
|
# the Request object, and not it's public methods.
|
348
349
|
#
|
349
350
|
# @param action[String] the HTTP verb
|
350
|
-
# @
|
351
|
-
# @
|
352
|
-
# @
|
351
|
+
# @param url[#to_s] the addition to the base url component, or a complete URL
|
352
|
+
# @param headers[Hash] a hash of headers, "Accept" will be automatically set to an empty string if not provided
|
353
|
+
# @param options[Hash] any overriding options (will shadow the options from the Session object)
|
353
354
|
# @return [Patron::Request] the request that will be passed to ++handle_request++
|
354
355
|
def build_request(action, url, headers, options = {})
|
355
356
|
# If the Expect header isn't set uploads are really slow
|
data/lib/patron/version.rb
CHANGED
data/spec/response_spec.rb
CHANGED
@@ -32,6 +32,12 @@ require 'base64'
|
|
32
32
|
require 'fileutils'
|
33
33
|
|
34
34
|
describe Patron::Response do
|
35
|
+
around(:each) do |example|
|
36
|
+
previous_internal = Encoding.default_internal
|
37
|
+
example.run
|
38
|
+
Encoding.default_internal = previous_internal
|
39
|
+
end
|
40
|
+
|
35
41
|
before(:each) do
|
36
42
|
@session = Patron::Session.new
|
37
43
|
@session.base_url = "http://localhost:9001"
|
@@ -75,47 +81,67 @@ describe Patron::Response do
|
|
75
81
|
response = @session.get("/repetitiveheader")
|
76
82
|
expect(response.headers['Set-Cookie']).to be == ["a=1","b=2"]
|
77
83
|
end
|
84
|
+
|
85
|
+
describe '#decoded_body and #inspectable_body' do
|
86
|
+
it "should raise with explicitly binary response bodies but allow an inspectable body" do
|
87
|
+
Encoding.default_internal = Encoding::UTF_8
|
88
|
+
response = @session.get("/picture")
|
89
|
+
expect(response.headers['Content-Type']).to be == 'image/png'
|
90
|
+
expect(response.body.encoding).to be == Encoding::BINARY
|
91
|
+
expect(response).not_to be_body_decodable
|
92
|
+
expect {
|
93
|
+
response.decoded_body
|
94
|
+
}.to raise_error(Patron::NonRepresentableBody)
|
95
|
+
|
96
|
+
inspectable = response.inspectable_body
|
97
|
+
expect(inspectable.encoding).to eq(Encoding::UTF_8)
|
98
|
+
expect(inspectable).to be_valid_encoding
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should encode body in the internal charset" do
|
102
|
+
allow(Encoding).to receive(:default_internal).and_return("UTF-8")
|
78
103
|
|
79
|
-
|
80
|
-
|
81
|
-
expect(response.headers['Content-Type']).to be == 'image/png'
|
82
|
-
expect(response.body.encoding).to be == Encoding::ASCII_8BIT
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should not allow a default charset to be nil" do
|
86
|
-
allow(Encoding).to receive(:default_internal).and_return("UTF-8")
|
87
|
-
expect {
|
88
|
-
Patron::Response.new("url", "status", 0, "", "", nil)
|
89
|
-
}.to_not raise_error
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should be able to serialize and deserialize itself" do
|
93
|
-
expect(Marshal.load(Marshal.dump(@request))).to eql(@request)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should encode body in the internal charset" do
|
97
|
-
allow(Encoding).to receive(:default_internal).and_return("UTF-8")
|
98
|
-
|
99
|
-
greek_encoding = Encoding.find("ISO-8859-7")
|
100
|
-
utf_encoding = Encoding.find("UTF-8")
|
104
|
+
greek_encoding = Encoding.find("ISO-8859-7")
|
105
|
+
utf_encoding = Encoding.find("UTF-8")
|
101
106
|
|
102
|
-
|
103
|
-
|
107
|
+
headers = "HTTP/1.1 200 OK \r\nContent-Type: text/css;charset=ISO-8859-7\r\n"
|
108
|
+
body = "Ππ".encode(greek_encoding) # Greek alphabet
|
104
109
|
|
105
|
-
|
110
|
+
response = Patron::Response.new("url", "status", 0, headers, body, nil)
|
106
111
|
|
107
|
-
|
112
|
+
expect(response).to be_body_decodable
|
113
|
+
expect(response.decoded_body.encoding).to eql(utf_encoding)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should fallback to default charset when header or body charset is not valid" do
|
117
|
+
allow(Encoding).to receive(:default_internal).and_return("UTF-8")
|
118
|
+
|
119
|
+
encoding = Encoding.find("UTF-8")
|
120
|
+
headers = "HTTP/1.1 200 OK \r\nContent-Type: text/css; charset=invalid\r\n"
|
121
|
+
body = "who knows which encoding this CSS is in?"
|
122
|
+
|
123
|
+
response = Patron::Response.new("url", "status", 0, headers, body, "UTF-8")
|
124
|
+
expect(response.charset).to eq('invalid')
|
125
|
+
|
126
|
+
expect(response).not_to be_body_decodable
|
127
|
+
expect {
|
128
|
+
response.decoded_body
|
129
|
+
}.to raise_error(Patron::HeaderCharsetInvalid)
|
130
|
+
end
|
108
131
|
end
|
109
132
|
|
110
|
-
it "
|
111
|
-
|
112
|
-
|
133
|
+
it "decodes a header that contains UTF-8 even though internal encoding is ASCII" do
|
134
|
+
Encoding.default_internal = Encoding::ASCII
|
113
135
|
encoding = Encoding.find("UTF-8")
|
114
|
-
headers = "HTTP/1.1 200 OK \r\nContent-
|
115
|
-
body = "
|
136
|
+
headers = "HTTP/1.1 200 OK \r\nContent-Disposition: attachment,filename=\"žфайлец.txt\"\r\n"
|
137
|
+
body = "this is a file with a Russian filename set in content-disposition"
|
116
138
|
|
117
139
|
response = Patron::Response.new("url", "status", 0, headers, body, "UTF-8")
|
118
|
-
|
119
|
-
expect(
|
140
|
+
dispo = response.headers['Content-Disposition']
|
141
|
+
expect(dispo.encoding).to eq(Encoding::UTF_8)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should be able to serialize and deserialize itself" do
|
145
|
+
expect(Marshal.load(Marshal.dump(@request))).to eql(@request)
|
120
146
|
end
|
121
147
|
end
|
data/spec/session_spec.rb
CHANGED
@@ -28,6 +28,7 @@ require 'webrick'
|
|
28
28
|
require 'yaml'
|
29
29
|
require 'base64'
|
30
30
|
require 'fileutils'
|
31
|
+
require 'securerandom'
|
31
32
|
|
32
33
|
describe Patron::Session do
|
33
34
|
|
@@ -233,7 +234,7 @@ describe Patron::Session do
|
|
233
234
|
# but it does get used nevertheless - for instance, it is a usual
|
234
235
|
# practice when interacting with an ElasticSearch cluster where
|
235
236
|
# you can have very deeply going queries, which are still technically GETs
|
236
|
-
data =
|
237
|
+
data = Random.new.bytes(1024 * 24)
|
237
238
|
response = @session.request(:get, "/test", {}, :data => data)
|
238
239
|
body = YAML::load(response.body)
|
239
240
|
expect(body.request_method).to be == "GET"
|
@@ -241,7 +242,7 @@ describe Patron::Session do
|
|
241
242
|
end
|
242
243
|
|
243
244
|
it "should upload data with :put" do
|
244
|
-
data =
|
245
|
+
data = Random.new.bytes(1024 * 24)
|
245
246
|
response = @session.put("/test", data)
|
246
247
|
body = YAML::load(response.body)
|
247
248
|
expect(body.request_method).to be == "PUT"
|
@@ -518,7 +519,7 @@ describe Patron::Session do
|
|
518
519
|
session = Patron::Session.new do |patron|
|
519
520
|
patron.timeout = args[:timeout]
|
520
521
|
patron.base_url = args[:base_url]
|
521
|
-
patron.headers =
|
522
|
+
patron.headers = args[:headers]
|
522
523
|
end
|
523
524
|
|
524
525
|
it 'sets the base_url' do
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/test_server.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phillip Toland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- ".gitignore"
|
93
93
|
- ".rspec"
|
94
94
|
- ".travis.yml"
|
95
|
+
- ".yardopts"
|
95
96
|
- CHANGELOG.md
|
96
97
|
- Gemfile
|
97
98
|
- Gemfile.lock
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/patron/proxy_type.rb
|
110
111
|
- lib/patron/request.rb
|
111
112
|
- lib/patron/response.rb
|
113
|
+
- lib/patron/response_decoding.rb
|
112
114
|
- lib/patron/session.rb
|
113
115
|
- lib/patron/util.rb
|
114
116
|
- lib/patron/version.rb
|