Skip to content

Instantly share code, notes, and snippets.

@decors
Last active September 10, 2021 11:13
Show Gist options
  • Save decors/cc28fead645895ee08d402f7a8306914 to your computer and use it in GitHub Desktop.
Save decors/cc28fead645895ee08d402f7a8306914 to your computer and use it in GitHub Desktop.
Crystal-lang HTTP Multipart/form-data POST
require "http/client"
class MultiPartFormData
property io : IO::Memory
property size : Int32
def initialize(name, filename, file, boundary=nil)
@boundary = boundary || "boundary"
first = [boundary_line, content_disposition(name, filename), "", ""].join("\r\n")
last = ["", boundary_last, ""].join("\r\n")
@io = IO::Memory.new
@io << IO::Memory.new(first)
IO.copy(file, @io)
@io << IO::Memory.new(last)
@size = @io.size
end
def content_type
"multipart/form-data; boundary=#{@boundary}"
end
def boundary_line
"--#{@boundary}"
end
def boundary_last
"--#{@boundary}--"
end
def content_disposition(name, filename)
"content-disposition: form-data; name=\"#{name}\"; filename=\"#{filename}\""
end
def size
@size
end
end
path = "./image.png"
url = URI.parse("http://httpbin.org")
HTTP::Client.new(url) do |client|
req = HTTP::Request.new("POST", "/post")
File.open(path, "rb") do |f|
form_data = MultiPartFormData.new("file", File.basename(path), f)
req.body = form_data.io.to_slice
req.content_length = form_data.size
req.headers = HTTP::Headers{
"Host" => "#{url.host}",
"Content-Length" => form_data.size.to_s,
"Content-Type" => form_data.content_type
}
client.exec(req) do |response|
puts response.body_io.gets_to_end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment