Web Page Templates Icons, Clipart, Logos

Blog

Hot Topics

Post Archive

Tags

Feb 18, 2010 04:37 AM EDT

Ruby S3 Gem - Bug in temporary_url

All in all, the Ruby S3 gem is pretty good.  The main advantage of using this gem instead of AWS::S3 is that you can connect to all 3 Amazon S3 data centers: Europe, US East, & US West.  Jakub, the author, seems pretty responsive to bug fixes, and for the most part, life is good.

I found a bug tonight on version 0.2.6 that I've submitted to Jakub, so hopefully it makes it to the core soon.  The bug relates to generating a temporary URL for private keys (i.e. not publically accessible). Basically, what it boils down to is that the different strings aren't handled right... what should be escaped isn't, and what is shouldn't.  No biggie... here's the broken code

 

def temporary_url(expires_at = Time.now + 3600)
  signature = Signature.generate_temporary_url_signature(
                :bucket => name,
                :resource => key,
                :expires_on => expires_at,
                :secret_access_key => secret_access_key)

  "#{url}?Signature=#{URI.escape(signature)}
    &Expires=#{URI.escape(expires_at.to_i)}"
end

Here's the working code:

### Fixed by Brian Broderick
def temporary_url(expires_at = Time.now + 3600)
  ckey = CGI.escape(key.to_s)
  signature = Signature.generate_temporary_url_signature(
                :bucket => name,
                :resource => ckey,
                :expires_on => expires_at.to_i,
                :secret_access_key => secret_access_key)

  str =  "#{protocol}#{host}/#{path_prefix}#{ckey}"
  str << "?Signature=#{signature}&Expires=#{expires_at.to_i.to_s}"
end

Basically, I'm escaping the key (as a string) and passing it to another variable because otherwise, it returns a blank string.  Then I'm converting the expires_at to an integer because normally it passes the date spelled out. I'm not using his url function because it doesn't know to escape the key, and I don't escape the signature and expires_at values because they are already taken care of from the generate_temporary_url_signature method - well signature is anyway and expires_at is just a number so it doesn't need to be escaped.  Also, you can combine the 2 str lines into 1.  I did it this way so it'll fit correctly on the webpage.

One thing to note is that you also need to pass the AWSAccessKeyId in your URL, which isn't handled in this function. 

Here's the function again, though this time, It's sitting in my own object rather than inside the gem. This way, we don't have to modify the gem directly and can get by until it gets fixed:

### Written by Brian Broderick
def self.temporary_url(key, name=S3_BUCKET, expires_at=Time.now + 3600)
  key = CGI.escape(key)
  access_key_id, secret_access_key = get_keys     
  signature = S3::Signature.generate_temporary_url_signature(
                :bucket => name,
                :resource => key,
                :expires_on => expires_at.to_i,
                :secret_access_key => secret_access_key)
          
  str =  "http://#{name}/#{key}?Signature=#{signature}"
  str << "&Expires=#{expires_at.to_i.to_s}&AWSAccessKeyId=#{access_key_id}"
end

In this case, there are a couple of minor differences.  First, I've written a function that gets my secret key and access key to keep it DRY.  The variable "name" is set to S3_BUCKET by default, which is a constant for the main bucket that I use, and key is expected to be passed in as a string rather than an S3 Object. Since I'm getting both S3 keys, I'm able to pass the access key into the return URL.  Again, go ahead and combine the two "str" lines into 1.  I did this to make it fit on the page.

Hopefully this will be of help to somebody.

Brian ruby | amazon s3 | rails

Ruby S3 Gem - Bug in temporary_url

Title:
Your Name:
Your Comment:
Please enter the text from the image in the box below:


 

 

 

 

Resource Links