lib/atom/http.rb in atom-tools-0.9.2 vs lib/atom/http.rb in atom-tools-0.9.3
- old
+ new
@@ -12,11 +12,11 @@
class String # :nodoc:
def to_uri; URI.parse(self); end
end
module Atom
- UA = "atom-tools 0.9.2"
+ UA = "atom-tools 0.9.3"
module DigestAuth
CNONCE = Digest::MD5.new("%x" % (Time.now.to_i + rand(65535))).hexdigest
@@nonce_count = -1
@@ -170,43 +170,42 @@
# 401 Unauthorized, so that your application can prompt for
# authentication details.
#
# the default is to use the values of @user and @pass.
#
- # your block will be called with two parameters
+ # your block will be called with two parameters:
# abs_url:: the base URL of the request URL
- # realm:: the realm used in the WWW-Authenticate header
- # (will be nil if there is no WWW-Authenticate header)
- #
- # it should return a value of the form [username, password]
+ # realm:: the realm used in the WWW-Authenticate header (maybe nil)
+ #
+ # your block should return [username, password], or nil
def when_auth &block # :yields: abs_url, realm
@get_auth_details = block
end
# GET a URL and turn it into an Atom::Entry
def get_atom_entry(url)
res = get(url, "Accept" => "application/atom+xml")
- # be picky for atom:entrys
- res.validate_content_type( [ "application/atom+xml" ] )
-
# XXX handle other HTTP codes
if res.code != "200"
- raise Atom::HTTPException, "expected Atom::Entry, didn't get it"
+ raise Atom::HTTPException, "failed to fetch entry: expected 200 OK, got #{res.code}"
end
+ # be picky for atom:entrys
+ res.validate_content_type( [ "application/atom+xml" ] )
+
Atom::Entry.parse(res.body, url)
end
# PUT an Atom::Entry to a URL
def put_atom_entry(entry, url = entry.edit_url)
raise "Cowardly refusing to PUT a non-Atom::Entry (#{entry.class})" unless entry.is_a? Atom::Entry
headers = {"Content-Type" => "application/atom+xml" }
-
+
put(url, entry.to_s, headers)
end
-
+
private
# parses plain quoted-strings
def parse_quoted_wwwauth param_string
params = {}
@@ -227,17 +226,17 @@
# WSSE authentication
# <http://www.xml.com/pub/a/2003/12/17/dive.html>
def wsse_authenticate(req, url, params = {})
user, pass = username_and_password_for_realm(url, params["realm"])
- nonce = Array.new(10){ rand(0x100000000) }.pack('I*')
- nonce_b64 = [nonce].pack("m").chomp
+ # thanks to Sam Ruby
+ nonce = rand(16**32).to_s(16)
+ now = Time.now.gmtime.iso8601
- now = Time.now.iso8601
digest = [Digest::SHA1.digest(nonce + now + pass)].pack("m").chomp
- req['X-WSSE'] = %Q<UsernameToken Username="#{user}", PasswordDigest="#{digest}", Nonce="#{nonce_b64}", Created="#{now}">
+ req['X-WSSE'] = %Q<UsernameToken Username="#{user}", PasswordDigest="#{digest}", Nonce="#{nonce}", Created="#{now}">
req["Authorization"] = 'WSSE profile="UsernameToken"'
end
def authsub_authenticate req, url
req["Authorization"] = %{AuthSub token="#{@token}"}
@@ -262,12 +261,17 @@
if @always_auth
self.send("#{@always_auth}_authenticate", req, url)
elsif www_authenticate
# XXX multiple challenges, multiple headers
param_string = www_authenticate.sub!(/^(\w+) /, "")
- auth_type = $~[1]
- self.send("#{auth_type.downcase}_authenticate", req, url, param_string)
+ auth_method = ($~[1].downcase + "_authenticate").to_sym
+
+ if self.respond_to? auth_method, true # includes private methods
+ self.send(auth_method, req, url, param_string)
+ else
+ raise "No support for #{$~[1]} authentication"
+ end
end
http_obj = Net::HTTP.new(url.host, url.port)
http_obj.use_ssl = true if url.scheme == "https"
@@ -315,10 +319,10 @@
end
module HTTPResponse
# this should probably support ranges (eg. text/*)
def validate_content_type( valid )
- raise Atom::HTTPException, "HTTP response contains no Content-Type!" unless self.content_type
+ raise Atom::HTTPException, "HTTP response contains no Content-Type!" if not self.content_type or self.content_type.empty?
media_type = self.content_type.split(";").first
unless valid.member? media_type.downcase
raise Atom::WrongMimetype, "unexpected response Content-Type: #{media_type.inspect}. should be one of: #{valid.inspect}"