From 806d1bd84609eff73f8c16e0b0b4ce7f9c2d6752 Mon Sep 17 00:00:00 2001 From: Marco Kellershoff Date: Tue, 10 Sep 2024 19:01:56 +0200 Subject: [PATCH] fix(form): fix binary multipart-form-data --- docs/docs/usage/sending-form-data.md | 33 ++++++++++++++++++++++++++++ lua/kulala/parser/init.lua | 10 +++++++-- lua/kulala/utils/fs.lua | 32 +++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/docs/docs/usage/sending-form-data.md b/docs/docs/usage/sending-form-data.md index 187c085..f4a7f4a 100644 --- a/docs/docs/usage/sending-form-data.md +++ b/docs/docs/usage/sending-form-data.md @@ -16,3 +16,36 @@ name={{name}}& age={{age}} ``` +## Sending multipart form data + +You can send multipart form data in Kulala by using the `multipart/form-data` content type. + +```http title="multipart.http" +# @file-to-variable LOGO_FILE_VAR ./../../logo.png +POST https://httpbin.org/post HTTP/1.1 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundary{{$timestamp}} + +------WebKitFormBoundary{{$timestamp}} +Content-Disposition: form-data; name="logo"; filename="logo.png" +Content-Type: image/jpeg + +{{LOGO_FILE_VAR}} + +------WebKitFormBoundary{{$timestamp}} +Content-Disposition: form-data; name="x" + +0 +------WebKitFormBoundary{{$timestamp}} +Content-Disposition: form-data; name="y" + +1.4333333333333333 +------WebKitFormBoundary{{$timestamp}} +Content-Disposition: form-data; name="w" + +514.5666666666667 +------WebKitFormBoundary{{$timestamp}} +Content-Disposition: form-data; name="h" + +514.5666666666667 +------WebKitFormBoundary{{$timestamp}}-- +``` diff --git a/lua/kulala/parser/init.lua b/lua/kulala/parser/init.lua index 495a293..c5d7227 100644 --- a/lua/kulala/parser/init.lua +++ b/lua/kulala/parser/init.lua @@ -413,6 +413,7 @@ local function extend_document_variables(document_variables, request) local kv = vim.split(metadata.value, " ") local variable_name = kv[1] local file_path = kv[2] + file_path = FS.get_file_path(file_path) local file_contents = FS.read_file(file_path) if file_contents then document_variables[variable_name] = file_contents @@ -574,8 +575,13 @@ function M.parse(start_request_linenr) res.headers["content-type"] = "application/json" end elseif res.headers["content-type"]:find("^multipart/form%-data") then - table.insert(res.cmd, "--data-binary") - table.insert(res.cmd, res.body) + local tmp_file = FS.get_binary_temp_file(res.body) + if tmp_file ~= nil then + table.insert(res.cmd, "--data-binary") + table.insert(res.cmd, "@" .. tmp_file) + else + Logger.error("Failed to create a temporary file for the binary request body") + end else table.insert(res.cmd, "--data") table.insert(res.cmd, res.body) diff --git a/lua/kulala/utils/fs.lua b/lua/kulala/utils/fs.lua index 9c7ad49..20cdef4 100644 --- a/lua/kulala/utils/fs.lua +++ b/lua/kulala/utils/fs.lua @@ -10,6 +10,27 @@ M.join_paths = function(...) return table.concat({ ... }, M.ps) end +---Returns true if the path is absolute, false otherwise +M.is_absolute_path = function(path) + if path:match("^/") or path:match("^%a:\\") then + return true + end + return false +end + +---Either returns the absolute path if the path is already absolute or +---joins the path with the current buffer directory +M.get_file_path = function(path) + if M.is_absolute_path(path) then + return path + end + local buffer_dir = vim.fn.expand("%:p:h") + if path:sub(1, 2) == "./" or path:sub(1, 2) == ".\\" then + path = path:sub(3) + end + return M.join_paths(buffer_dir, path) +end + -- This is mainly used for determining if the current buffer is a non-http file -- and therefore maybe we need to parse a fenced code block M.is_non_http_file = function() @@ -232,6 +253,17 @@ M.read_file = function(filename) return content end +M.get_binary_temp_file = function(content) + local tmp_file = vim.fn.tempname() + local f = io.open(tmp_file, "wb") + if f == nil then + return nil + end + f:write(content) + f:close() + return tmp_file +end + ---Read file lines ---@param filename string ---@return string[]