You're exactly right that you need to turn the request body into a readable stream. Specifically, S3 expects a Ruby IO class (in that it wants a #read method and a #eof? method). Rack request bodies don't have #eof? defined, however, so you have to make a little wrapper class:
class RackS3Wrapper
def initialize(body)
@body = body
@eof = false
end
def read(*args)
ret = @body.read(*args)
if ret == nil or ret == ""
@eof = true
end
ret
end
def eof?
@eof
end
end
Then you can use this wrapper to stream the request to S3 directly:
s3.buckets['com.mydomain.mybucket'].objects['filename'].write(
:data => RackS3Wrapper.new(request.body),
:content_length => request.env['CONTENT_LENGTH'].to_i)
This hasn't been tested in production or anything, but it should work fine.