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}"