mistweaverco / kulala.nvim

A minimal 🤏 HTTP-client 🐼 interface 🖥️ for Neovim ❤️.
https://kulala.mwco.app
MIT License
687 stars 34 forks source link

Unable to send multipart form data #274

Closed joninvski closed 1 month ago

joninvski commented 1 month ago

When trying this small example:

# @file-to-variable LOGO_FILE_VAR ./sample_image.png
POST https://httpbin.org/post
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}}--

I get this error:

Error  17:10:33 msg_show.lua_error Error executing vim.schedule lua callback: Vim:E976: Using a Blob as a String
stack traceback:
    [C]: in function 'strlen'
    ...de/.local/share/nvim/lazy/nui.nvim/lua/nui/text/init.lua:31: in function 'set'
    ...de/.local/share/nvim/lazy/nui.nvim/lua/nui/text/init.lua:18: in function 'init'
    .../.local/share/nvim/lazy/nui.nvim/lua/nui/object/init.lua:132: in function 'NuiText'
    ...de/.local/share/nvim/lazy/nui.nvim/lua/nui/line/init.lua:20: in function '_append'
    ...ocal/share/nvim/lazy/noice.nvim/lua/noice/text/block.lua:186: in function 'append'
    ...ocal/share/nvim/lazy/noice.nvim/lua/noice/text/block.lua:21: in function 'init'
    ...al/share/nvim/lazy/noice.nvim/lua/noice/message/init.lua:46: in function 'init'
    .../.local/share/nvim/lazy/nui.nvim/lua/nui/object/init.lua:132: in function 'Message'
    ...l/share/nvim/lazy/noice.nvim/lua/noice/source/notify.lua:53: in function 'notify'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/logger/init.lua:14: in function 'info'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:37: in function <...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:20>
    [C]: in function 'gsub'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:46: in function 'parse_string_variables'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:29: in function <...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:20>
    [C]: in function 'gsub'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:46: in function 'parse_body'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:539: in function 'replace_variables_in_url_headers_body'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:573: in function 'parse'
    ...ocal/share/nvim/lazy/kulala.nvim/lua/kulala/cmd/init.lua:87: in function 'run_parser'
    ...local/share/nvim/lazy/kulala.nvim/lua/kulala/ui/init.lua:204: in function <...local/share/nvim/lazy/kulala.nvim/lua/kulala/ui/init.lua:193>

I am running on neovim 0.10.2 and installing kulala via lazyvim rest extra.

Thanks

gorillamoe commented 1 month ago

Can confirm this. The example is right, but that's a regression in the code. If you lower-case the content-type header it will work. But as said, it's a regression, will fix it later, when I'm back at home.

joninvski commented 1 month ago

I have just discovered that this problem does not occur if file size is small. It happened when image was 500kb but once i reduced it to 20k problem stopped.

gorillamoe commented 1 month ago

Currently in main. It works this way with binary files (like images):

# @file-to-variable LOGO_FILE_VAR ./sample_image.png binary
POST https://httpbin.org/post
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}}--

Note the binary keyword at the end of the metatag directive.

This tells kulala to read it as binary, instead of just a raw string.

For text files like json or txt or what not, you can completely ignore that and just read them as before:

# @file-to-variable SOME_JSON_VAR ./some.json

[!WARNING] neovim might get really laggy when you read big files. I tested it with files around 1-2 Megabytes which worked fine; when testing it with files around 5-10 Megabytes it freezes for some seconds :see_no_evil:

willheryanto commented 3 weeks ago

Hi @gorillamoe , letting you know I face this issue also on 4.4.0. I'm using nightly, but the error logs pretty much the same like the issue author. Thanks!


# @file-to-variable LOGO_FILE_VAR ./sample_image.png binary
POST https://httpbin.org/post
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}}--

Error:

   Error  13:30:25 msg_show.lua_error Error executing vim.schedule lua callback: Vim:E976: Using a Blob as a String
stack traceback:
    [C]: in function 'strlen'
    ...an/.local/share/nvim/lazy/nui.nvim/lua/nui/text/init.lua:31: in function 'set'
    ...an/.local/share/nvim/lazy/nui.nvim/lua/nui/text/init.lua:18: in function 'init'
    .../.local/share/nvim/lazy/nui.nvim/lua/nui/object/init.lua:132: in function 'NuiText'
    ...an/.local/share/nvim/lazy/nui.nvim/lua/nui/line/init.lua:20: in function '_append'
    ...ocal/share/nvim/lazy/noice.nvim/lua/noice/text/block.lua:186: in function 'append'
    ...ocal/share/nvim/lazy/noice.nvim/lua/noice/text/block.lua:21: in function 'init'
    ...al/share/nvim/lazy/noice.nvim/lua/noice/message/init.lua:46: in function 'init'
    .../.local/share/nvim/lazy/nui.nvim/lua/nui/object/init.lua:132: in function 'Message'
    ...l/share/nvim/lazy/noice.nvim/lua/noice/source/notify.lua:53: in function 'notify'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/logger/init.lua:14: in function 'info'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:42: in function <...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:25>
    [C]: in function 'gsub'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:51: in function 'parse_string_variables'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:34: in function <...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:25>
    [C]: in function 'gsub'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:51: in function 'parse_body'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:577: in function 'replace_variables_in_url_headers_body'
    ...l/share/nvim/lazy/kulala.nvim/lua/kulala/parser/init.lua:612: in function 'parse'
    ...ocal/share/nvim/lazy/kulala.nvim/lua/kulala/cmd/init.lua:87: in function 'run_parser'
    ...local/share/nvim/lazy/kulala.nvim/lua/kulala/ui/init.lua:230: in function <...local/share/nvim/lazy/kulala.nvim/lua/kulala/ui/init.lua:219>

NVIM version:

NVIM v0.11.0-dev-1106+gf7e32fb6e6
Build type: RelWithDebInfo
LuaJIT 2.1.1727870382
willheryanto commented 3 weeks ago

Just giving update, with redirection syntax it actually works 👍

POST https://httpbin.org/post
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary{{$timestamp}}

------WebKitFormBoundary{{$timestamp}}
Content-Disposition: form-data; name="logo"; filename="logo.png"
Content-Type: image/jpeg

< ./sample_image.png

------WebKitFormBoundary{{$timestamp}}--
gorillamoe commented 3 weeks ago

Perfect, thanks for the report!

Grueslayer commented 3 weeks ago

@gorillamoe The latest error from @willheryanto in https://github.com/mistweaverco/kulala.nvim/issues/274#issuecomment-2461437420 comes from noice / nui BUT its origin is the Logger.info() line:

local function parse_string_variables(str, variables, env, silent)
  local function replace_placeholder(variable_name)
    local value
    -- If the variable name contains a `$` symbol then try to parse it as a dynamic variable
    if variable_name:find("^%$") then
      local variable_value = DYNAMIC_VARS.read(variable_name)
      if variable_value then
        value = variable_value
      end
    elseif variables[variable_name] then
      value = parse_string_variables(variables[variable_name], variables, env)
    elseif env[variable_name] then
      value = env[variable_name]
    elseif REQUEST_VARIABLES.parse(variable_name) then
      value = REQUEST_VARIABLES.parse(variable_name)
    else
      value = "{{" .. variable_name .. "}}"
      if not silent then
        Logger.info(
          "The variable '"
            .. variable_name
            .. "' was not found in the document or in the environment. Returning the string as received ..."
        )
      end
    end
    return value
  end

So it seems the binary content @willheryanto read from its file in the LOGO_FILE_VAR contains {{ and }} which kulala interprets as variable and tries to replace that. As the content is some ramdom binary stuff kulala writes the info abut the missing variable and that is killing nui.

I think binary content should not be parsed for variables or processed in any way,

gorillamoe commented 3 weeks ago

I think binary content should not be parsed for variables or processed in any way,

Sure, but I need to figure out a better way to filter that out. The < filename part is excluded from the variable processing, but everything else could be a variable referencing a variable referencing a variable and so on :dizzy_face:

I had this "filter blobs" approach, but that caused issues with chinese characters :see_no_evil: