Dear all,
I want to do a small server using Julia. This service implies to receive POST parameters and returns a file. Because I want to include it inside my package, I have chosen HTTP.jl (instead of Genie) to reduce the dependencies.
Using HTTP, after many errors, I could send the file. The problem is how to receive the POST parameters from a HTML form using a handle.
I have check the documentation but I have not found any clue. I have try the request.headers and request.body but without any success.
function handle(req::HTTP.Request)
# Get the POST parameters?
end
Any suggestion?
Thanks in advance.
Daniel
I can’t help you directly, since I’ve done something similar for images, but with Genie:
route("/getpic", method = POST) do
#read payload
raw = filespayload()
img = ImageMagick.readblob(raw["file_name"].data)
end
Genie.startup(port,ip,async = false)
Maybe if you look inside the Genie.filespayload() function?
Hi Daniel,
I have studied the HTTP.jl library extensively.
You would need to do:
HTTP.Handlers.serve(server_host, server_port) do request::HTTP.Request
request_payload=String(take!(IOBuffer(request.body))))
end
request_payload is JSON string format
As side note I recently created a lighter Julia web library (only renders JSON API and HTTP Get) doing all this for you. Might want to check Dance.jl
Cheers
2 Likes
Did you see this example from the HTTP.jl documentation where the payload is obtained using IOBuffer(HTTP.payload(req)). This object can then be parsed with one of the julia json readers.
Thank you for all your suggestions!
Finally, I have done:
function handle(req::HTTP.Request)
data = String(req.body)
params = Dict(split.(split(data, "&"), Ref("=")))
# Process params
end
The String(req.body) is enough when your form is simple (in my case all where input, select, and textarea), if there is a file the option suggested by @yoh-meyers is the best one. That sentence concatenate the values as: "data = “penalty_options=0.25&penalty_boolean=0&text=…”
So, the next line divide the different form values using the & and the = symbol, and create a Dictionary with the parameters. (if there is a conflictive symbol as ‘&’ or ‘=’ as the values of the variables, they are encoded).
@uwechsler thank you, but the payload function did not work for me.
Thanks again all for your ideas!
1 Like
To answer myself, I have develop a (not so) simple function to read parameters. It is not working with files, but it is working with “application/x-www-form-urlencoded” and “multipart/form-data” content-types:
function get_params(req::HTTP.Request)
data = String(req.body)
params = Dict{String,String}()
headers = filter(x->x[1] == "Content-Type", req.headers)
# Check there is content-type
if (isempty(headers))
content_type = ""
else
content_type = only(headers)[2]
end
if (content_type == "application/x-www-form-urlencoded")
pairs = split.(split(data, "&"), Ref("="))
params = Dict(name => HTTP.URIs.unescapeuri(value) for (name, value) in pairs)
elseif (startswith(content_type, "multipart/form-data"))
body = IOBuffer(data)
# First line is the stopping line
stopping_line = replace(readline(body), "-" => "")
while(!eof(body))
line = readline(body)
text_head = r"Content-Disposition: form-data; name=\"(.*)\""
m = match(text_head, line)
if !isnothing(m)
name = m.captures[1]
_ = readline(body)
line = readline(body)
value = ""
if (!occursin(stopping_line, line))
value = "$(line)"
end
while (!eof(body) && !occursin(stopping_line, line))
line = readline(body)
if (!occursin(stopping_line, line))
value *= "\n$(line)"
end
end
params[name] = value
end
end
end
return params
end
I have put the code if it could help anyone.
1 Like