post "/upload" do |env|
parse_multipart(env) do |f|
file_path = File.join Dir.current, "filesaved"
File.open(file_path, "w") do |file|
IO.copy(f.data, file)
end
"Upload complete"
end
end
But when I upload something using curl, from and to my local machine the upload speed is not higher than 10 Mb/s. Is it related to kemal or am I missing something ?
curl -X POST -F "image1=@/tmp/file4" http://localhost:3000/upload -o test
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4096M 0 0 100 4096M 0 8723k 0:08:00 0:08:00 --:--:-- 8386k
require "kemal"
require "json"
Kemal.config.public_folder = "/home/x"
post "/upload" do |env|
parse_multipart(env) do |f|
file_path = File.join Dir.current, "filesaved"
File.open(file_path, "w") do |file|
IO.copy(f.data, file)
end
"Upload complete"
end
end
Kemal.run
It is precisely this, I just checked. With this code:
require "http"
http = HTTP::Server.new do |context|
MIME::Multipart.parse context.request do |headers, io|
file_path = "public"
File.open(file_path, "w") do |f|
IO.copy(io, f)
end
end
end
http.listen 3000
Using the latest release of Crystal, I uploaded a ~2GB file to it, and it transfers at 162MB/sec, taking about 11 seconds:
➜ upload_demo git:(main) curl -X POST -F "image1=@file" http://localhost:3000/upload -o test
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
56 1839M 0 0 56 1034M 0 162M 0:00:11 0:00:06 0:00:05 162M
With your patch, it transfers at 1.7GB/sec in barely over a second, over 10x as fast:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1839M 0 0 100 1839M 0 1678M 0:00:01 0:00:01 --:--:-- 1685M
EDIT: I’d forgotten to compile the app in release mode.
Wired, why no one mention, those code never work for latest version kemal + crystal? no parse_multipart method exists at all.
Following code come from kemal guide works, and speed is not slow than the questioner.
require "kemal"
post "/upload" do |env|
HTTP::FormData.parse(env.request) do |upload|
filename = upload.filename
# Be sure to check if file.filename is not empty otherwise it'll raise a compile time error
if !filename.is_a?(String)
puts "No filename included in upload"
else
file_path = ::File.join [Kemal.config.public_folder, "uploads/", filename]
File.open(file_path, "w") do |f|
IO.copy(upload.body, f)
end
puts "Upload ok"
end
end
env.redirect "/index.html"
end
Kemal.run
It’s easy to overlook small details like that when trying to reduce your reproduction of a problem. And when I looked at the Kemal docs for uploading files and it looked nearly identical, I figured that’s what Paulo was getting at and used that code in my original benchmark before peeling back layers down to MIME::Multipart.
It only added about 30 seconds to my investigation. It would’ve taken more time to come to the forum to ask for clarification.
I have no idea whether the request completes successfully with that code (I didn’t wait for it to finish), but we don’t need a successful request to take note of the upload speed. It can be observed before env.params.files completes.
Yes, you are right, the patch is really impressive for the upload speed improve.
but, for the original question, d is below 10 Mb/s on local machine i thought the issue is come from different things, e.g. use old version kemal/crystal ?