rest-client-next 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,48 +1,64 @@
1
1
  module RestClient
2
- module Mixin
3
- module Response
4
- attr_reader :net_http_res
2
+ module Mixin
3
+ module Response
4
+ attr_reader :net_http_res
5
5
 
6
- # HTTP status code, always 200 since RestClient throws exceptions for
7
- # other codes.
8
- def code
9
- @code ||= @net_http_res.code.to_i
10
- end
6
+ # HTTP status code
7
+ def code
8
+ @code ||= @net_http_res.code.to_i
9
+ end
11
10
 
12
- # A hash of the headers, beautified with symbols and underscores.
13
- # e.g. "Content-type" will become :content_type.
14
- def headers
15
- @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
16
- end
11
+ # A hash of the headers, beautified with symbols and underscores.
12
+ # e.g. "Content-type" will become :content_type.
13
+ def headers
14
+ @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
15
+ end
17
16
 
18
- # The raw headers.
19
- def raw_headers
20
- @raw_headers ||= @net_http_res.to_hash
21
- end
17
+ # The raw headers.
18
+ def raw_headers
19
+ @raw_headers ||= @net_http_res.to_hash
20
+ end
22
21
 
23
- # Hash of cookies extracted from response headers
24
- def cookies
25
- @cookies ||= (self.headers[:set_cookie] || "").split('; ').inject({}) do |out, raw_c|
26
- key, val = raw_c.split('=')
27
- unless %w(expires domain path secure).member?(key)
28
- out[key] = val
29
- end
30
- out
31
- end
32
- end
22
+ # Hash of cookies extracted from response headers
23
+ def cookies
24
+ @cookies ||= (self.headers[:set_cookie] || []).inject({}) do |out, cookie_content|
25
+ # correctly parse comma-separated cookies containing HTTP dates (which also contain a comma)
26
+ cookie_content.split(/,\s*/).inject([""]) { |array, blob|
27
+ blob =~ /expires=.+?$/ ? array.push(blob) : array.last.concat(blob)
28
+ array
29
+ }.each do |cookie|
30
+ next if cookie.empty?
31
+ key, *val = cookie.split(";").first.split("=")
32
+ out[key] = val.join("=")
33
+ end
34
+ out
35
+ end
36
+ end
33
37
 
34
- def self.included(receiver)
35
- receiver.extend(RestClient::Mixin::Response::ClassMethods)
36
- end
38
+ # Return the default behavior corresponding to the response code:
39
+ # the response itself for code in 200..206 and an exception in other cases
40
+ def return!
41
+ if (200..206).include? code
42
+ self
43
+ elsif Exceptions::EXCEPTIONS_MAP[code]
44
+ raise Exceptions::EXCEPTIONS_MAP[code], self
45
+ else
46
+ raise RequestFailed, self
47
+ end
48
+ end
37
49
 
38
- module ClassMethods
39
- def beautify_headers(headers)
40
- headers.inject({}) do |out, (key, value)|
41
- out[key.gsub(/-/, '_').downcase.to_sym] = value.first
42
- out
43
- end
44
- end
45
- end
46
- end
47
- end
50
+ def self.included(receiver)
51
+ receiver.extend(RestClient::Mixin::Response::ClassMethods)
52
+ end
53
+
54
+ module ClassMethods
55
+ def beautify_headers(headers)
56
+ headers.inject({}) do |out, (key, value)|
57
+ out[key.gsub(/-/, '_').downcase.to_sym] = %w{set-cookie}.include?(key.downcase) ? value : value.first
58
+ out
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
48
64
  end
@@ -6,16 +6,16 @@
6
6
  # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
7
7
 
8
8
  module Net
9
- class HTTP
10
- alias __request__ request
9
+ class HTTP
10
+ alias __request__ request
11
11
 
12
- def request(req, body=nil, &block)
13
- if body != nil && body.respond_to?(:read)
14
- req.body_stream = body
15
- return __request__(req, nil, &block)
16
- else
17
- return __request__(req, body, &block)
18
- end
19
- end
20
- end
12
+ def request(req, body=nil, &block)
13
+ if body != nil && body.respond_to?(:read)
14
+ req.body_stream = body
15
+ return __request__(req, nil, &block)
16
+ else
17
+ return __request__(req, body, &block)
18
+ end
19
+ end
20
+ end
21
21
  end
@@ -1,171 +1,178 @@
1
- require "tempfile"
2
- require "stringio"
3
- require "mime/types"
1
+ require 'tempfile'
2
+ require 'stringio'
3
+ require 'mime/types'
4
4
 
5
5
  module RestClient
6
- module Payload
7
- extend self
8
-
9
- def generate(params)
10
- if params.is_a?(String)
11
- Base.new(params)
12
- elsif params
13
- if params.delete(:multipart) == true || has_file?(params)
14
- Multipart.new(params)
15
- else
16
- UrlEncoded.new(params)
17
- end
18
- else
19
- nil
20
- end
21
- end
22
-
23
- def has_file?(params)
24
- params.any? do |_, v|
25
- case v
26
- when Hash
27
- has_file?(v)
28
- else
29
- v.respond_to?(:path) && v.respond_to?(:read)
30
- end
31
- end
32
- end
33
-
34
- class Base
35
- def initialize(params)
36
- build_stream(params)
37
- end
38
-
39
- def build_stream(params)
40
- @stream = StringIO.new(params)
41
- @stream.seek(0)
42
- end
43
-
44
- def read(bytes=nil)
45
- @stream.read(bytes)
46
- end
47
- alias :to_s :read
48
-
49
- def escape(v)
50
- URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
51
- end
52
-
53
- # Flatten parameters by converting hashes of hashes to flat hashes
54
- # {keys1 => {keys2 => value}} will be transformed into {keys1[key2] => value}
55
- def flatten_params(params, parent_key = nil)
56
- result = {}
57
- params.keys.map do |key|
58
- calculated_key = parent_key ? "#{parent_key}[#{escape key}]" : escape(key)
59
- value = params[key]
60
- if value.is_a? Hash
61
- result.merge!(flatten_params(value, calculated_key))
62
- else
63
- result[calculated_key] = value
64
- end
65
- end
66
- result
67
- end
68
-
69
- def headers
70
- { 'Content-Length' => size.to_s }
71
- end
72
-
73
- def size
74
- @stream.size
75
- end
76
- alias :length :size
77
-
78
- def close
79
- @stream.close
80
- end
81
-
82
- def inspect
83
- result = to_s.inspect
84
- @stream.seek(0)
85
- result
86
- end
87
- end
88
-
89
- class UrlEncoded < Base
90
- def build_stream(params = nil)
91
- @stream = StringIO.new(flatten_params(params).map do |k,v|
92
- "#{k}=#{escape(v)}"
93
- end.join("&"))
94
- @stream.seek(0)
95
- end
96
-
97
- def headers
98
- super.merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
99
- end
100
- end
101
-
102
- class Multipart < Base
103
- EOL = "\r\n"
104
-
105
- def build_stream(params)
106
- b = "--#{boundary}"
107
-
108
- @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
109
- @stream.write(b + EOL)
110
-
111
- if params.is_a? Hash
112
- x = flatten_params(params).to_a
113
- else
114
- x = params.to_a
115
- end
116
-
117
- last_index = x.length - 1
118
- x.each_with_index do |a, index|
119
- k, v = *a
120
- if v.respond_to?(:read) && v.respond_to?(:path)
121
- create_file_field(@stream, k,v)
122
- else
123
- create_regular_field(@stream, k,v)
124
- end
125
- @stream.write(EOL + b)
126
- @stream.write(EOL) unless last_index == index
127
- end
128
- @stream.write('--')
129
- @stream.write(EOL)
130
- @stream.seek(0)
131
- end
132
-
133
- def create_regular_field(s, k, v)
134
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"")
135
- s.write(EOL)
136
- s.write(EOL)
137
- s.write(v)
138
- end
139
-
140
- def create_file_field(s, k, v)
141
- begin
142
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
143
- s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
144
- s.write(EOL)
145
- while data = v.read(8124)
146
- s.write(data)
147
- end
148
- ensure
149
- v.close
150
- end
151
- end
152
-
153
- def mime_for(path)
154
- mime = MIME::Types.type_for path
155
- mime.empty? ? 'text/plain' : mime[0].content_type
156
- end
157
-
158
- def boundary
159
- @boundary ||= rand(1_000_000).to_s
160
- end
161
-
162
- def headers
163
- super.merge({'Content-Type' => %Q{multipart/form-data; boundary="#{boundary}"}})
164
- end
165
-
166
- def close
167
- @stream.close
168
- end
169
- end
170
- end
6
+ module Payload
7
+ extend self
8
+
9
+ def generate(params)
10
+ if params.is_a?(String)
11
+ Base.new(params)
12
+ elsif params
13
+ if params.delete(:multipart) == true || has_file?(params)
14
+ Multipart.new(params)
15
+ else
16
+ UrlEncoded.new(params)
17
+ end
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def has_file?(params)
24
+ params.any? do |_, v|
25
+ case v
26
+ when Hash
27
+ has_file?(v)
28
+ else
29
+ v.respond_to?(:path) && v.respond_to?(:read)
30
+ end
31
+ end
32
+ end
33
+
34
+ class Base
35
+ def initialize(params)
36
+ build_stream(params)
37
+ end
38
+
39
+ def build_stream(params)
40
+ @stream = StringIO.new(params)
41
+ @stream.seek(0)
42
+ end
43
+
44
+ def read(bytes=nil)
45
+ @stream.read(bytes)
46
+ end
47
+
48
+ alias :to_s :read
49
+
50
+ def escape(v)
51
+ URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
52
+ end
53
+
54
+ # Flatten parameters by converting hashes of hashes to flat hashes
55
+ # {keys1 => {keys2 => value}} will be transformed into {keys1[key2] => value}
56
+ def flatten_params(params, parent_key = nil)
57
+ result = {}
58
+ params.keys.map do |key|
59
+ calculated_key = parent_key ? "#{parent_key}[#{escape key}]" : escape(key)
60
+ value = params[key]
61
+ if value.is_a? Hash
62
+ result.merge!(flatten_params(value, calculated_key))
63
+ else
64
+ result[calculated_key] = value
65
+ end
66
+ end
67
+ result
68
+ end
69
+
70
+ def headers
71
+ { 'Content-Length' => size.to_s }
72
+ end
73
+
74
+ def size
75
+ @stream.size
76
+ end
77
+
78
+ alias :length :size
79
+
80
+ def close
81
+ @stream.close
82
+ end
83
+
84
+ def inspect
85
+ result = to_s.inspect
86
+ @stream.seek(0)
87
+ result
88
+ end
89
+
90
+ def short_inspect
91
+ (size > 100 ? "#{size} byte length" : inspect)
92
+ end
93
+
94
+ end
95
+
96
+ class UrlEncoded < Base
97
+ def build_stream(params = nil)
98
+ @stream = StringIO.new(flatten_params(params).map do |k, v|
99
+ "#{k}=#{escape(v)}"
100
+ end.join("&"))
101
+ @stream.seek(0)
102
+ end
103
+
104
+ def headers
105
+ super.merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
106
+ end
107
+ end
108
+
109
+ class Multipart < Base
110
+ EOL = "\r\n"
111
+
112
+ def build_stream(params)
113
+ b = "--#{boundary}"
114
+
115
+ @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
116
+ @stream.write(b + EOL)
117
+
118
+ if params.is_a? Hash
119
+ x = flatten_params(params).to_a
120
+ else
121
+ x = params.to_a
122
+ end
123
+
124
+ last_index = x.length - 1
125
+ x.each_with_index do |a, index|
126
+ k, v = *a
127
+ if v.respond_to?(:read) && v.respond_to?(:path)
128
+ create_file_field(@stream, k, v)
129
+ else
130
+ create_regular_field(@stream, k, v)
131
+ end
132
+ @stream.write(EOL + b)
133
+ @stream.write(EOL) unless last_index == index
134
+ end
135
+ @stream.write('--')
136
+ @stream.write(EOL)
137
+ @stream.seek(0)
138
+ end
139
+
140
+ def create_regular_field(s, k, v)
141
+ s.write("Content-Disposition: form-data; name=\"#{k}\"")
142
+ s.write(EOL)
143
+ s.write(EOL)
144
+ s.write(v)
145
+ end
146
+
147
+ def create_file_field(s, k, v)
148
+ begin
149
+ s.write("Content-Disposition: form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
150
+ s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
151
+ s.write(EOL)
152
+ while data = v.read(8124)
153
+ s.write(data)
154
+ end
155
+ ensure
156
+ v.close
157
+ end
158
+ end
159
+
160
+ def mime_for(path)
161
+ mime = MIME::Types.type_for path
162
+ mime.empty? ? 'text/plain' : mime[0].content_type
163
+ end
164
+
165
+ def boundary
166
+ @boundary ||= rand(1_000_000).to_s
167
+ end
168
+
169
+ def headers
170
+ super.merge({'Content-Type' => %Q{multipart/form-data; boundary="#{boundary}"}})
171
+ end
172
+
173
+ def close
174
+ @stream.close
175
+ end
176
+ end
177
+ end
171
178
  end