1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
require 'thread' unless defined? Mutex # For Ruby 1.8.7
require 'cgi'
module Postmark
class HttpClient
attr_accessor :api_token
attr_reader :http, :secure, :proxy_host, :proxy_port, :proxy_user,
:proxy_pass, :host, :port, :path_prefix,
:http_open_timeout, :http_read_timeout, :http_ssl_version,
:auth_header_name
alias_method :api_key, :api_token
alias_method :api_key=, :api_token=
DEFAULTS = {
:auth_header_name => 'X-Postmark-Server-Token',
:host => 'api.postmarkapp.com',
:secure => true,
:path_prefix => '/',
:http_read_timeout => 60,
:http_open_timeout => 60
}
def initialize(api_token, options = {})
@api_token = api_token
@request_mutex = Mutex.new
apply_options(options)
@http = build_http
end
def post(path, data = '')
do_request { |client| client.post(url_path(path), data, headers) }
end
def put(path, data = '')
do_request { |client| client.put(url_path(path), data, headers) }
end
def patch(path, data = '')
do_request { |client| client.patch(url_path(path), data, headers) }
end
def get(path, query = {})
do_request { |client| client.get(url_path(path + to_query_string(query)), headers) }
end
def delete(path, query = {})
do_request { |client| client.delete(url_path(path + to_query_string(query)), headers) }
end
def protocol
self.secure ? 'https' : 'http'
end
protected
def apply_options(options = {})
options = Hash[*options.select { |_, v| !v.nil? }.flatten]
DEFAULTS.merge(options).each_pair do |name, value|
instance_variable_set(:"@#{name}", value)
end
@port = options[:port] || (@secure ? 443 : 80)
end
def to_query_string(hash)
return "" if hash.empty?
"?" + hash.map { |key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}" }.join("&")
end
def url
URI.parse("#{protocol}://#{self.host}:#{self.port}/")
end
def handle_response(response)
if response.code.to_i == 200
Postmark::Json.decode(response.body)
else
raise HttpServerError.build(response.code, response.body)
end
end
def headers
HEADERS.merge(self.auth_header_name => self.api_token.to_s)
end
def url_path(path)
self.path_prefix + path
end
def do_request
@request_mutex.synchronize do
handle_response(yield(http))
end
rescue Timeout::Error => e
raise TimeoutError.new(e)
rescue Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError => e
raise HttpClientError.new(e.message)
end
def build_http
http = Net::HTTP::Proxy(self.proxy_host,
self.proxy_port,
self.proxy_user,
self.proxy_pass).new(url.host, url.port)
http.read_timeout = self.http_read_timeout
http.open_timeout = self.http_open_timeout
http.use_ssl = !!self.secure
http.ssl_version = self.http_ssl_version if self.http_ssl_version && http.respond_to?(:ssl_version=)
http
end
end
end
|