Get POST parameters using a HTTP server

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