Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attaching an unlinked Tempfile fails #563

Closed
jonasoberschweiber opened this issue Jan 4, 2022 · 2 comments
Closed

Attaching an unlinked Tempfile fails #563

jonasoberschweiber opened this issue Jan 4, 2022 · 2 comments

Comments

@jonasoberschweiber
Copy link

Brief Description

Attaching an unlinked Tempfile using Attacher#attach fails with a TypeError.

Expected behavior

attach should attach the Tempfile.

Actual behavior

In extract_filename, Shrine passes the Tempfile's path, which is nil, to File::basename. basename fails because it doesn't expect nil.

When a Tempfile is unlinked, its path is set to nil, but its contents remain accessible. This is valid on POSIX systems and it's what Puma does for request bodies beyond a certain size. We're trying to attach request.body in an API handler.

For now, I've monkeypatched extract_filename like this. It seems to work, but I'm not sure if it's the optimal solution.

def extract_filename(io)
  if io.respond_to?(:original_filename)
    io.original_filename
  elsif io.respond_to?(:path) && !io.path.nil?
    File.basename(io.path)
  end
end

Simplest self-contained example code to demonstrate issue

require "sequel"
require "shrine"
require "shrine/storage/memory"
require "down"

require "bundler/setup" # if you want to debug shrine locally
require 'minitest/autorun' # if you wanna use minitest

# require 'byebug'  ## if you're using byebug
# byebug


Shrine.storages = {
  cache: Shrine::Storage::Memory.new,
  store: Shrine::Storage::Memory.new,
}

Shrine.plugin :sequel

class MyUploader < Shrine
  # plugins and uploading logic
end

DB = Sequel.sqlite # SQLite memory database
DB.create_table :posts do
  primary_key :id
  String :image_data
end

class Post < Sequel::Model
  include MyUploader::Attachment(:image)
end


class PostTest < Minitest::Test
  def test_linked_tempfile
    # This works.
    t = Tempfile.new
    attacher = MyUploader::Attacher.new
    attacher.attach(t)
  end

  def test_unlinked_tempfile
    # This fails.
    t = Tempfile.new
    t.unlink
    attacher = MyUploader::Attacher.new
    attacher.attach(t)
  end
end
PostTest#test_unlinked_tempfile:
TypeError: no implicit conversion of nil into String
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:256:in `basename'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:256:in `extract_filename'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:230:in `extract_metadata'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:288:in `get_metadata'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:207:in `upload'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine.rb:108:in `upload'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine/attacher.rb:182:in `upload'
    /Users/jobe/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/shrine-3.4.0/lib/shrine/attacher.rb:117:in `attach'
    sequel_template.rb:46:in `test_unlinked_tempfile'

System configuration

Ruby version: Reproduced on 2.7.5

Shrine version: 3.4.0

@benkoshy
Copy link
Contributor

benkoshy commented Jan 6, 2022

  • I can confirm that I reproduced the issue, with the report submitted (a superb report by the way - made it super easy to reproduce etc.)
  • As far as optimal solution for this: i cannot really comment.

@jrochkind
Copy link
Contributor

That solution makes sense to me as a PR to shrine ... I think shrine can handle having no extracted filename already? @janko , good PR? @jonasoberschweiber , if the maintainers like it, are you interested in making a PR with a test?

@janko janko closed this as completed in d21556f Feb 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants