unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* url-retrieve-synchronously with binary multipart/form-data
@ 2024-03-27 15:23 Christian Barthel
  0 siblings, 0 replies; only message in thread
From: Christian Barthel @ 2024-03-27 15:23 UTC (permalink / raw)
  To: help-gnu-emacs

Hello, I’d like to send a multipart/form-data HTTP POST request with
‘url-retrieve-synchronously’ which should be equivlent to this cURL
request:

#+begin_src shell
  curl -X POST \
       -H "Content-Type: multipart/form-data" \
       --form file="@/tmp/x.png" \
       http://127.0.0.1:8898/
#+end_src

My current elisp function:

#+begin_src elisp
  (defun xtest/http-post-multipart-boundary ()
    "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")

  (defun xtest/http-post (url data extra-headers)
    (let ((url-request-method        "POST")
          (url-request-data          data)
          (url-request-extra-headers extra-headers))
      (let (header
            data
            status)
        (with-current-buffer
            (url-retrieve-synchronously url)
          (setq status url-http-response-status)
          (goto-char (point-min))
          (if (search-forward-regexp "^$" nil t)
              (setq header (buffer-substring (point-min) (point))
                    data   (buffer-substring (1+ (point)) (point-max)))
            (setq data (buffer-string))))
        (list
         (cons 'data data)
         (cons 'header header)
         (cons 'status status)))))

  (xtest/http-post
    "http://127.0.0.1:8898"
    ;; Data:
    (format "%s%s%s%s\r\n"
            "Content-Disposition: form-data; name=x; filename=x.png\r\n"
            "Content-type: image/png\r\n"
            (with-temp-buffer
                       (insert-file-contents-literally "/tmp/x.png")
                       (buffer-substring-no-properties (point-min) (point-max)))
            (format "--%s--" (xtest/http-post-multipart-boundary)))
     ;; Extra Headers:
     `(("Content-Type"
        .
        ,(format "multipart/form-data; boundary=%S" (xtest/http-post-multipart-boundary))
          )))
#+end_src

(this is a simplified version of my original code - I tried to
reconstruct the problem with a simpler version.  My original
elisp defuns are a bit larger and based on [4])

The problem:  With this code in place, I get an error message:
  "Multibyte text in HTTP request: [..]"
As far as I can see, it is generated at Line 416 in url-http.el [1].

When I remove this length check, everything works as expected and I
can POST binary data (image/png in my case) to the remote server.

My questions:  Am I doing something wrong with the encoding of the binary
data?

Is this length check in line 416 at [1] really correct when sending
binary data?

Is there a simpler way with native emacs functions to send
multipart/form-data with POST?


[1] https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/url/url-http.el#n416

[2] The bug report when the lines were introduced:
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=23750

[3] The git-commit a98aa02a5dbf079f7b4f3be5487a2f2b741d103d:
https://git.savannah.gnu.org/cgit/emacs.git/commit/lisp/url/url-http.el?id=a98aa02a5dbf079f7b4f3be5487a2f2b741d103d

[4] https://www.emacswiki.org/emacs/http-post-simple.el

-- 
Christian Barthel



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-03-27 15:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-27 15:23 url-retrieve-synchronously with binary multipart/form-data Christian Barthel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).