Quick FTP server
The ftpd gem supports TLS, and comes with a file system driver. Like em-ftpd, you supply a driver, but that driver doesn't need to do much. Here's a bare-minimum FTP server that accepts any username/password, and serves files out of a temporary directory:
require 'ftpd'
require 'tmpdir'
class Driver
def initialize(temp_dir)
@temp_dir = temp_dir
end
def authenticate(user, password)
true
end
def file_system(user)
Ftpd::DiskFileSystem.new(@temp_dir)
end
end
Dir.mktmpdir do |temp_dir|
driver = Driver.new(temp_dir)
server = Ftpd::FtpServer.new(driver)
server.start
puts "Server listening on port #{server.bound_port}"
gets
end
NOTE: This example allows an FTP client to upload, delete, rename, etc.
To enable TLS:
include Ftpd::InsecureCertificate
...
server.certfile_path = insecure_certfile_path
server.tls = :explicit
server.start
Disclosure: I am ftpd's author and current maintainer
Ruby Net::FTP - Downloading files from a server
The error message comes from the FTP server. The problem is that the FTP server cannot interpret these unicode filenames. Please check if UTF8 feature is enabled for the connection.
From an existing answer on stackoverflow:
It is not enough for you just to encode your string as UTF8 and send it as filename to FTP server. In the past all FTP servers understood ASCII only and nowadays to maintain backward compatibility - even if they are Unicode aware - when they start they treat all filenemes as ASCII too.
To make it all work you (your program) must first check what your server is capable of. Servers send their features after client connects - in your case you must check for FEAT UTF8. If your server sends that - it means it understands UTF8. Nevertheless - even if it understands it - you must tell it explicitly that from now on you will send your filenames UTF8 encoded and now it is the stuff that your program lacks (as your server supports utf8 as you've stated).
Your client must send to FTP server the following OPTS UTF8 ON. After sending that you may use UTF8 or speak UTF8-ish (so to speak) to your sever.
Read here for details Internationalization of the File Transfer Protocol
Sources:
https://stackoverflow.com/a/19903611/1305200
https://wiki.filezilla-project.org/Character_Encoding
Why can't Net::FTP connect to server?
Your code works fine for me. I suspect problem could be because of Net::FTP
connection mode, which is by default active. Try connecting using passive mode, following code sample -
ftp = Net::FTP.new(server)
ftp.passive = true
ftp.login user, password
files = ftp.chdir('mydirectory/')
files = ftp.list
puts "list out of directory:"
puts files
ftp.close
And if you're curious, following is the difference (from wikipedia) between active and passive modes.
- In Active mode, the client creates a TCP control connection to the server and sends the server the client's IP address and an arbitrary client port number, and then waits until the server initiates the data connection over TCP to that client IP address and client port number. In situations where the client is behind a firewall and unable to accept incoming TCP connections, passive mode may be used.
- In Passive mode, the client uses the control connection to send a PASV command to the server and then receives a server IP address and server port number from the server which the client then uses to open a data connection from an arbitrary client port to the server IP address and server port number received.
Is it possible to transfer the contents of a whole directory using the built in Ruby Net::FTP class?
First, get all files and subdirectories in your directory:
entries = Dir.glob('my_dir/**/*').sort
(sort
is required to ensure that every directory goes before its files)
Now you can upload all files and create all subdirectories:
Net::FTP.open(ftp_server, username, password) do |ftp|
entries.each do |name|
if File::directory? name
ftp.mkdir name
else
File.open(name) { |file| ftp.putbinaryfile(file, name) }
end
end
end
I had no time to test this, so I could miss something.
How to FTP in Ruby without first saving the text file
StringIO.new provides an object that acts like an opened file. It's easy to create a method like puttextfile, by using StringIO object instead of file.
require 'net/ftp'
require 'stringio'
class Net::FTP
def puttextcontent(content, remotefile, &block)
f = StringIO.new(content)
begin
storlines("STOR " + remotefile, f, &block)
ensure
f.close
end
end
end
file_content = <<filecontent
<html>
<head><title>Hello!</title></head>
<body>Hello.</body>
</html>
filecontent
ftp = Net::FTP.new(domain)
ftp.passive = true
ftp.login(username, password)
ftp.chdir(path_on_server)
ftp.puttextcontent(file_content, path_to_web_file)
ftp.close
Related Topics
Implicit Argument Passing of Super from Method Defined by Define_Method() Is Not Supported
Phonegap and Rails 3: How to Interact with a Rails 3 App
Retrieve All Posts Where the Given User Has Commented, Ruby on Rails
How to Use Present? in Ruby Projects
Superclass Mismatch, Struct, Reloading and Spork
How to Declare a Rake Task That Depends on a Parameterized Task
How to Find Out the Starting Point for Each Match in Ruby
Ruby Imap "Changes" Since Last Check
How to Find Out Why a Gem Bundle Has Locked a Gem at a Specific Version
When to Use Self in Module's Methods
Ways to Define a Global Method in Ruby
In Depth Ruby Gem Development Resources (Book, Video, Sites)
Access Slack Files from a Slack Bot
How to Use Ruby CSV Converters
Ruby Cannot Find SQLite3 Driver on Windows
Rails 3.1 Rspec Creating Test Case Validate Field for Model
Setting the Environment in Gemfile for Bundling Install/Update Based on a Customize File