url-http: synchronous post and 302 error response not handled properly. This is seen with Oddmuse wikis. GNU Emacs is from today's master branch. ---------------------------------------------------------------- Prerequisites: You need an oddmuse wiki that you have write access to. ---------------------------------------------------------------- The snippet below posts the "Hello Everywhere" (the "text") on to "TemporaryPage" (the "title"). (let* ((wiki-base-url "http://localhost/cgi-bin/wiki.pl/") (values `(("pwd" . "xxxx") ("recent_edit" . "off") ("summary" . "Some updates") ("text" . "Hello Everywhere") ("title" . "TemporaryPage") ("username" . "Anonymous")))) (let ((url-request-method "POST") (url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded"))) (url-request-data (mm-url-encode-www-form-urlencoded values))) (url-retrieve-synchronously wiki-base-url) (message "Done"))) 1. Get hold of an oddmuse wiki that you have edit access to 2. Customize `url-debug' to t 3. C-x C-e the above snippet 4. See that the "Done" message gets never printed. 5. C-g your way out. 6. Verify that Oddmuse wiki page has been updated. ---------------------------------------------------------------- The HTTP process buffer says: HTTP/1.1 302 Found Status: 302 Found Location: http://localhost/cgi-bin/wiki.pl/TemporaryPage Transfer-Encoding: chunked Date: Thu, 09 Jul 2015 07:32:42 GMT Server: lighttpd/1.4.31 ---------------------------------------------------------------- The *URL-DEBUG* buffer says infinite "spinning" for headers. http -> Contacting host: localhost:80 http -> Marking connection as busy: localhost:80 # retrieval -> Spinning in url-retrieve-synchronously: nil (#) http -> Request is: POST /cgi-bin/wiki.pl/ HTTP/1.1 MIME-Version: 1.0 Connection: keep-alive Extension: Security/Digest Security/SSL Host: localhost Accept-encoding: gzip Accept-charset: utf-8;q=1, gb2312;q=0.5, iso-8859-1;q=0.5, big5;q=0.5, iso-2022-jp;q=0.5, shift_jis;q=0.5, euc-tw;q=0.5, euc-jp;q=0.5, euc-jis-2004;q=0.5, euc-kr;q=0.5, us-ascii;q=0.5, utf-7;q=0.5, hz-gb-2312;q=0.5, big5-hkscs;q=0.5, gbk;q=0.5, gb18030;q=0.5, iso-8859-5;q=0.5, koi8-r;q=0.5, koi8-u;q=0.5, cp866;q=0.5, koi8-t;q=0.5, windows-1251;q=0.5, cp855;q=0.5, iso-8859-2;q=0.5, iso-8859-3;q=0.5, iso-8859-4;q=0.5, iso-8859-9;q=0.5, iso-8859-10;q=0.5, iso-8859-13;q=0.5, iso-8859-14;q=0.5, iso-8859-15;q=0.5, windows-1250;q=0.5, windows-1252;q=0.5, windows-1254;q=0.5, windows-1257;q=0.5, cp775;q=0.5, cp850;q=0.5, cp852;q=0.5, cp857;q=0.5, cp858;q=0.5, cp860;q=0.5, cp861;q=0.5, cp863;q=0.5, cp865;q=0.5, cp437;q=0.5, macintosh;q=0.5, next;q=0.5, hp-roman8;q=0.5, adobe-standard-encoding;q=0.5, iso-8859-16;q=0.5, iso-8859-7;q=0.5, windows-1253;q=0.5, cp737;q=0.5, cp851;q=0.5, cp869;q=0.5, iso-8859-8;q=0.5, windows-1255;q=0.5, cp862;q=0.5, iso-2022-jp-2004;q=0.5, cp874;q=0.5, iso-8859-11;q=0.5, viscii;q=0.5, windows-1258;q=0.5, iso-8859-6;q=0.5, windows-1256;q=0.5, iso-2022-cn;q=0.5, iso-2022-cn-ext;q=0.5, iso-2022-jp-2;q=0.5, iso-2022-kr;q=0.5, utf-16le;q=0.5, utf-16be;q=0.5, utf-16;q=0.5, x-ctext;q=0.5 Accept: */* User-Agent: URL/Emacs Cookie: Wiki=pwd%251exxxx%251eusername%251eAnonymous Content-Type: application/x-www-form-urlencoded Content-length: 101 pwd=xxxx&recent_edit=off&summary=Some+updates&text=Hello+World&title=TemporaryPage&username=Anonymous http -> Calling after change function `url-http-wait-for-headers-change-function' for `#' http -> url-http-wait-for-headers-change-function ( *http localhost:80*) http -> Saw end of headers... ( *http localhost:80*) http -> url-http-parse-response called in ( *http localhost:80*) http -> Saw chunked encoding. http -> Calling initial chunked-encoding for extra data at end of headers http -> Reading chunk 0 (182 183 1) http -> Did not see start of chunk @ 183! http -> Spinning waiting for headers... retrieval -> Spinning in url-retrieve-synchronously: nil (#) http -> Calling after change function `url-http-chunked-encoding-after-change-function' for `#' http -> Reading chunk 0 (183 188 5) http -> Saw start of chunk 1 (length=0, start=183 http -> Saw end of stream chunk! http -> Removing terminator of last chunk http -> Saw end of trailers... http -> Marking connection as free: localhost:80 # http -> url-http-parse-headers called in ( *http localhost:80*) http -> url-http-parse-response called in ( *http localhost:80*) http -> Parsed HTTP headers: class=3 status=302 http -> Finished parsing HTTP headers: nil retrieval -> Spinning in url-retrieve-synchronously: nil (#) retrieval -> Spinning in url-retrieve-synchronously: nil (#) ---------------------------------------------------------------- Hint for quick isolation: If I comment out the `unless' part below (cf. url-http.el @ line 602) thereabouts, the spinning stops altogether. ((or `moved-permanently `found `temporary-redirect) ; 301 302 307 ;; If the 301|302 status code is received in response to a ;; request other than GET or HEAD, the user agent MUST NOT ;; automatically redirect the request unless it can be ;; confirmed by the user, since this might change the ;; conditions under which the request was issued. (unless (member url-http-method '("HEAD" "GET")) (setq redirect-uri nil))) ---------------------------------------------------------------- Expected behaviour: I am attaching an edit transaction done via firefox + emacswiki (captured with "follow TCP stream" option of wireshark) I see a 302 response followed by a fetch of the edited page. Whatever be the right behaviour, I expect that synchronous fetch doesn't loop infinitely and make emacs unusable.