dusty-patron 0.4.3

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/lib/patron.rb ADDED
@@ -0,0 +1,39 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Patron HTTP Client: Bootstrap script
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
+ require 'yaml'
26
+ require 'pathname'
27
+ require 'patron/session'
28
+
29
+ module Patron #:nodoc:
30
+ # Returns the version number of the Patron library as a string
31
+ def self.version
32
+ cwd = Pathname(__FILE__).dirname
33
+ yaml = YAML.load_file(cwd.expand_path + '../VERSION.yml')
34
+ major = (yaml['major'] || yaml[:major]).to_i
35
+ minor = (yaml['minor'] || yaml[:minor]).to_i
36
+ patch = (yaml['patch'] || yaml[:patch]).to_i
37
+ "#{major}.#{minor}.#{patch}"
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Patron HTTP Client: Error definitions
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
+ module Patron
27
+
28
+ # Base class for Patron exceptions.
29
+ class Error < StandardError; end
30
+
31
+ # The URL you passed to Patron used a protocol that it does not support.
32
+ # This most likely the result of a misspelled protocol string.
33
+ class UnsupportedProtocol < Error; end
34
+
35
+ # The URL was not properly formatted.
36
+ class URLFormatError < Error; end
37
+
38
+ # Could not resolve the remote host name.
39
+ class HostResolutionError < Error; end
40
+
41
+ # Failed to connect to the remote host.
42
+ class ConnectionFailed < Error; end
43
+
44
+ # A file transfer was shorter or larger than expected.
45
+ # This happens when the server first reports an expected transfer size,
46
+ # and then delivers data that doesn't match the previously given size.
47
+ class PartialFileError < Error; end
48
+
49
+ # Operation timeout. The specified time-out period was reached.
50
+ class TimeoutError < Error; end
51
+
52
+ # Too many redirects. When following redirects, Patron hit the maximum amount.
53
+ class TooManyRedirects < Error; end
54
+
55
+ end
@@ -0,0 +1,147 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Patron HTTP Client: Request 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
+ module Patron
27
+
28
+ # Represents the information necessary for an HTTP request.
29
+ # This is basically a data object with validation. Not all fields will be
30
+ # used in every request.
31
+ class Request
32
+
33
+ VALID_ACTIONS = [:get, :put, :post, :delete, :head, :copy]
34
+
35
+ def initialize
36
+ @action = :get
37
+ @headers = {}
38
+ @timeout = 0
39
+ @connect_timeout = 0
40
+ @max_redirects = -1
41
+ end
42
+
43
+ attr_accessor :url, :username, :password, :file_name, :proxy, :auth_type, :insecure
44
+ attr_reader :action, :timeout, :connect_timeout, :max_redirects, :headers
45
+ attr_reader :auth_type
46
+
47
+ # Set the type of authentication to use for this request.
48
+ #
49
+ # @param [String, Symbol] type - The type of authentication to use for this request, can be one of
50
+ # :basic, :digest, or :any
51
+ #
52
+ # @example
53
+ # sess.username = "foo"
54
+ # sess.password = "sekrit"
55
+ # sess.auth_type = :digest
56
+ def auth_type=(type=:basic)
57
+ @auth_type = case type
58
+ when :basic, "basic"
59
+ Request::AuthBasic
60
+ when :digest, "digest"
61
+ Request::AuthDigest
62
+ when :any, "any"
63
+ Request::AuthAny
64
+ else
65
+ raise "#{type.inspect} is an unknown authentication type"
66
+ end
67
+ end
68
+
69
+ def upload_data=(data)
70
+ @upload_data = case data
71
+ when Hash
72
+ hash_to_string(data)
73
+ else
74
+ data
75
+ end
76
+ end
77
+
78
+ def upload_data
79
+ @upload_data
80
+ end
81
+
82
+ def action=(new_action)
83
+ if !VALID_ACTIONS.include?(new_action)
84
+ raise ArgumentError, "Action must be one of #{VALID_ACTIONS.join(', ')}"
85
+ end
86
+
87
+ @action = new_action
88
+ end
89
+
90
+ def timeout=(new_timeout)
91
+ if new_timeout && new_timeout.to_i < 1
92
+ raise ArgumentError, "Timeout must be a positive integer greater than 0"
93
+ end
94
+
95
+ @timeout = new_timeout.to_i
96
+ end
97
+
98
+ def connect_timeout=(new_timeout)
99
+ if new_timeout && new_timeout.to_i < 1
100
+ raise ArgumentError, "Timeout must be a positive integer greater than 0"
101
+ end
102
+
103
+ @connect_timeout = new_timeout.to_i
104
+ end
105
+
106
+ def max_redirects=(new_max_redirects)
107
+ if new_max_redirects.to_i < -1
108
+ raise ArgumentError, "Max redirects must be a positive integer, 0 or -1"
109
+ end
110
+
111
+ @max_redirects = new_max_redirects.to_i
112
+ end
113
+
114
+ def headers=(new_headers)
115
+ if !new_headers.kind_of?(Hash)
116
+ raise ArgumentError, "Headers must be a hash"
117
+ end
118
+
119
+ @headers = new_headers
120
+ end
121
+
122
+ def action_name
123
+ @action.to_s.upcase
124
+ end
125
+
126
+ def credentials
127
+ return nil if username.nil? || password.nil?
128
+ "#{username}:#{password}"
129
+ end
130
+
131
+ private
132
+
133
+ # serialize hash for Rails-style params
134
+ def hash_to_string(hash)
135
+ pairs = []
136
+ recursive = Proc.new do |h, prefix|
137
+ h.each_pair do |k,v|
138
+ key = prefix == '' ? k : "#{prefix}[#{k}]"
139
+ v.is_a?(Hash) ? recursive.call(v, key) : pairs << "#{key}=#{v}"
140
+ end
141
+ end
142
+ recursive.call(hash, '')
143
+ return pairs.join('&')
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,58 @@
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
+ module Patron
27
+
28
+ # Represents the response from the HTTP server.
29
+ class Response
30
+
31
+ def initialize
32
+ @headers = {}
33
+ end
34
+
35
+ attr_reader :url, :status, :status_line, :redirect_count, :body, :headers
36
+
37
+ def inspect
38
+ # Avoid spamming the console with the header and body data
39
+ "#<Patron::Response @status_line='#{@status_line}'>"
40
+ end
41
+
42
+ private
43
+
44
+ # Called by the C code to parse and set the headers
45
+ def parse_headers(header_data)
46
+ header_data.split(/\r\n/).each do |header|
47
+ if header =~ %r|^HTTP/1.[01]|
48
+ @status_line = header.strip
49
+ else
50
+ parts = header.split(':', 2)
51
+ parts[1].strip! unless parts[1].nil?
52
+ @headers[parts[0]] = parts[1]
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,183 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Patron HTTP Client: Session 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
+ require 'patron/error'
26
+ require 'patron/request'
27
+ require 'patron/response'
28
+ require 'patron/session_ext'
29
+
30
+
31
+ module Patron
32
+
33
+ # This class represents multiple request/response transactions with an HTTP
34
+ # server. This is the primary API for Patron.
35
+ class Session
36
+
37
+ # HTTP connection timeout in milliseconds. Defaults to 1 second (1000 ms).
38
+ attr_accessor :connect_timeout
39
+
40
+ # HTTP transaction timeout in seconds. Defaults to 5 seconds.
41
+ attr_accessor :timeout
42
+
43
+ # Maximum number of times to follow redirects.
44
+ # Set to 0 to disable and -1 to follow all redirects (the default).
45
+ attr_accessor :max_redirects
46
+
47
+ # Prepended to the URL in all requests.
48
+ attr_accessor :base_url
49
+
50
+ # Username and password for http authentication
51
+ attr_accessor :username, :password
52
+
53
+ # HTTP proxy URL
54
+ attr_accessor :proxy
55
+
56
+ # Standard set of headers that are used in all requests.
57
+ attr_reader :headers
58
+
59
+ # Set the authentication type for the request.
60
+ # @see Patron::Request#auth_type
61
+ attr_accessor :auth_type
62
+
63
+ # Does this session stricly verify SSL certificates?
64
+ attr_accessor :insecure
65
+
66
+ private :ext_initialize, :handle_request, :enable_cookie_session
67
+
68
+ # Create a new Session object.
69
+ def initialize
70
+ ext_initialize
71
+ @headers = {}
72
+ @timeout = 5
73
+ @connect_timeout = 1000
74
+ @max_redirects = -1
75
+ @auth_type = :basic
76
+ end
77
+
78
+ # Makes this session handle cookies and store them in in +file+.
79
+ # If file is nil they will be stored in memory. Otherwise the +file+
80
+ # must be readable and writable. Calling multiple times will add more files.
81
+ def handle_cookies(file = nil)
82
+ if file
83
+ path = Pathname(file).expand_path
84
+ unless File.exists?(file) and File.writable?(path.dirname)
85
+ raise ArgumentError, "Can't create file #{path} (permission error)"
86
+ end
87
+ unless File.readable?(file) or File.writable?(path)
88
+ raise ArgumentError, "Cant read or write file #{path} (permission error)"
89
+ end
90
+ end
91
+ enable_cookie_session(path.to_s)
92
+ self
93
+ end
94
+
95
+ ###################################################################
96
+ ### Standard HTTP methods
97
+ ###
98
+
99
+ # Retrieve the contents of the specified +url+ optionally sending the
100
+ # specified headers. If the +base_url+ varaible is set then it is prepended
101
+ # to the +url+ parameter. Any custom headers are merged with the contents
102
+ # of the +headers+ instance variable. The results are returned in a
103
+ # Response object.
104
+ def get(url, headers = {})
105
+ request(:get, url, headers)
106
+ end
107
+
108
+ # Retrieve the contents of the specified +url+ as with #get, but the
109
+ # content at the URL is downloaded directly into the specified file.
110
+ def get_file(url, filename, headers = {})
111
+ request(:get, url, headers, :file => filename)
112
+ end
113
+
114
+ # As #get but sends an HTTP HEAD request.
115
+ def head(url, headers = {})
116
+ request(:head, url, headers)
117
+ end
118
+
119
+ # As #get but sends an HTTP DELETE request.
120
+ def delete(url, headers = {})
121
+ request(:delete, url, headers)
122
+ end
123
+
124
+ # Uploads the passed +data+ to the specified +url+ using HTTP PUT. +data+
125
+ # must be a string.
126
+ def put(url, data, headers = {})
127
+ request(:put, url, headers, :data => data)
128
+ end
129
+
130
+ # Uploads the contents of a file to the specified +url+ using HTTP PUT.
131
+ def put_file(url, filename, headers = {})
132
+ request(:put, url, headers, :file => filename)
133
+ end
134
+
135
+ # Uploads the passed +data+ to the specified +url+ using HTTP POST. +data+
136
+ # must be a string.
137
+ def post(url, data, headers = {})
138
+ request(:post, url, headers, :data => data)
139
+ end
140
+
141
+ # Uploads the contents of a file to the specified +url+ using HTTP POST.
142
+ def post_file(url, filename, headers = {})
143
+ request(:post, url, headers, :file => filename)
144
+ end
145
+
146
+ ###################################################################
147
+ ### WebDAV methods
148
+ ###
149
+
150
+ # Sends a WebDAV COPY request to the specified +url+.
151
+ def copy(url, dest, headers = {})
152
+ headers['Destination'] = dest
153
+ request(:copy, url, headers)
154
+ end
155
+
156
+ ###################################################################
157
+ ### Basic API methods
158
+ ###
159
+
160
+ # Send an HTTP request to the specified +url+.
161
+ def request(action, url, headers, options = {})
162
+ req = Request.new
163
+ req.action = action
164
+ req.timeout = self.timeout
165
+ req.connect_timeout = self.connect_timeout
166
+ req.max_redirects = self.max_redirects
167
+ req.headers = self.headers.merge(headers)
168
+ req.username = self.username
169
+ req.password = self.password
170
+ req.upload_data = options[:data]
171
+ req.file_name = options[:file]
172
+ req.proxy = proxy
173
+ req.auth_type = auth_type
174
+ req.insecure = insecure
175
+
176
+ req.url = self.base_url.to_s + url.to_s
177
+ raise ArgumentError, "Empty URL" if req.url.empty?
178
+
179
+ handle_request(req)
180
+ end
181
+
182
+ end
183
+ end