get-url of empty content fails (fixed in 10.6.4)

Started by hartrock, July 10, 2015, 07:07:28 AM

Previous topic - Next topic

hartrock

A GET resulting into a reply with Content-Length 0 should be possible: from

  http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#message.body">http://svn.tools.ietf.org/svn/wg/httpbi ... ssage.body">http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#message.body

:
Quote
The presence of a message body in a request is signaled by a Content-Length or Transfer-Encoding header field. ...



... All 1xx (Informational), 204 (No Content), and 304 (Not Modified) responses do not include a message body. All other responses do include a message body, although the body might be of zero length.

So this applies to e.g. '200 OK' and  '404 Not Found' responses, which may have a zero message body.



newLISP:

sr@mad:~$ newlisp
newLISP v.10.6.2 64-bit on Linux IPv4/6 UTF-8 libffi, options: newlisp -h

> (get-url "http://localhost/empty.txt" "debug")
GET /empty.txt HTTP/1.1
Host: localhost
User-Agent: newLISP v10602
Connection: close

HTTP/1.1 200 OK

"ERR: HTTP document empty"
> ; but:
> (get-url "file:///tmp/empty.txt" "debug")
""


curl:

sr@mad:~$ curl -v -X GET http://localhost/empty.txt
* About to connect() to localhost port 80 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 80 (#0)
> GET /empty.txt HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost
> Accept: */*
>
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Fri, 10 Jul 2015 12:49:10 GMT
< Server: Apache/2.2.22 (Debian)
< Last-Modified: Fri, 10 Jul 2015 12:10:49 GMT
< ETag: "8075b-0-51a84433bdbcf"
< Accept-Ranges: bytes
< Content-Length: 0
< Vary: Accept-Encoding
< Content-Type: text/plain
<
* Connection #0 to host localhost left intact
* Closing connection #0

(empty message body).



Ideas:

[*] (http-error) for more fine-granular checking of http responses?
  • [*] net-error '24 HTTP document empty' only (possibly with 'empty' -> 'missing'), if there is no 'Content-Length or Transfer-Encoding header' for a response with an HTTP error code needing a message body?
  • [/list]

    Lutz

    #1
    Fixed in: http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/



    > (get-url "http://localhost:8080/empty.txt" "debug")
    GET /empty.txt HTTP/1.1
    Host: localhost
    User-Agent: newLISP v10604
    Connection: close

    HTTP/1.0 200 OK

    ""
    >

    hartrock

    #2
    Hello Lutz,



    first thank you for the very fast reaction!



    Checking last (just downloaded) devel version gives problems:

    sr@mad:/tmp/newlisp-10.6.4$ make check
    ./newlisp qa-dot

    Testing built-in functions ...
    make: *** [check] Segmentation fault

    But:

    sr@mad:/tmp/newlisp-10.6.4$ ./newlisp qa-dot

    Testing built-in functions ...
    upper-case of UTF8 characters not available - not critical -
    lower-case of UTF8 characters not available - not critical -
                                 
    Testing contexts as objects and scoping rules ...

    total time: 2730

    >>>>> ALL FUNCTIONS FINISHED SUCCESSFUL: ./newlisp

    sr@mad:/tmp/newlisp-10.6.4$ make testall
    make checkall | grep '>>>'
    Segmentation fault
    >>>>> Dictionary API tested SUCCESSFUL
    >>>>> XML API tested SUCCESSFUL
    >>>>> XML callback tested SUCCESSFUL
    >>>>> JSON translation tested SUCESSFUL
    >>>>> Signal testing SUCCESSFUL
    >>>>> Network eval and network file functions IPv4 SUCCESSFUL
    >>>>> Network eval and network file functions IPv6 SUCCESSFUL
    >>>>> The Cilk API tested SUCCESSFUL
    >>>>> Reference testing SUCCESSFUL
    >>>>> Time per simple message: 8 micro seconds
    >>>>> Time per round trip : 70 micros seconds
    >>>>> Time per proxy trip: 20 micro seconds
    >>>>> Message API tested SUCCESSFUL
    >>>>> Memory allocation/deallocation SUCCESSFUL
    >>>>> Exception testing SUCCESSFUL
    >>>>> Floating point tests SUCCESSFUL
    >>>>> FOOP nested 'self' tested SUCCCESSFUL
    >>>>> FOOP symbol protection SUCCESSFUL
    >>>>> UNIX local domain sockets SUCCESSFUL
    >>>>> In-place modification passed SUCCESSFUL
    >>>>> 0.005 ms per write->read pipe/fork (0.0356 ms Mac OSX, 1.83 GHz Core 2 Duo)
    >>>>> libffi API testing SUCCESSFUL
    >>>>> callback API 1234567890 (simple callback API) SUCCESSFUL
    >>>>> callback API 1234567890 12345.6789 (extended callback API) SUCCESSFUL
    >>>>> struct tested SUCCESSFUL
    >>>>> struct ptr tested SUCCESSFUL
    >>>>> testing big ints arithmetik ...
    >>>>> abs bigint float gcd length zero? + - * / % ++ -- big ints tested SUCCESSFUL
    >>>>> parsing big integers SUCCESSFUL
    >>>>> Benchmarking all non I/O primitives ... (may take a while)
    >>>>> total time: 1503.266
    >>>>> Performance ratio: 0.62 (1.0 on MacOSX 10.9, 2.3GHz Intel Core i5, newLISP v10.6.0-64-bit)

    Digging deeper this difference in behavior is suspect:

    sr@mad:/tmp/newlisp-10.6.4$ make check | more
    ./newlisp qa-dot

    Testing built-in functions ...
      -> >>          
      -> array                
      -> begin                
      -> clean              
      -> cpymt                  
      -> def-                  
      -> div                  
      -> error              
      -> file?                
      -> gammai            
      -> inc                
      -> lambda?train          
      -> macro-case          
      -> net-close          
      -> net-receive            
      -> now                      
      -> pop-                
      -> prompt-event          
      -> read-file            
      -> replace              
      -> series            
    make: *** [check] Segmentation fault
      -> share                
    sr@mad:/tmp/newlisp-10.6.4$ ./newlisp qa-dot | more

    Testing built-in functions ...
      -> >>          
      -> array                
      -> begin                
      -> clean              
      -> cpymt                  
      -> def-                  
      -> div                  
      -> error              
      -> file?                
      -> gammai            
      -> inc                
      -> lambda?train          
      -> macro-case          
      -> net-close          
      -> net-receive            
      -> now                      
      -> pop-                
      -> prompt-event          
      -> read-file            
      -> replace              
      -> series            
      -> sort                
      -> sys-error            
      -> transpose   ght          
    upper-case of UTF8 characters not available - not critical -
    lower-case of UTF8 characters not available - not critical -
      -> xml-parse            
                                 
    Testing contexts as objects and scoping rules ...

    total time: 2753

    >>>>> ALL FUNCTIONS FINISHED SUCCESSFUL: ./newlisp


    First checks 'share', second not?



    OS:

    sr@mad:/tmp/newlisp-10.6.4$ uname -a
    Linux mad 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u2 x86_64 GNU/Linux

    Lutz

    #3
    Fixed here: http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/

    hartrock

    #4
    Thanks: OK now!



    Another thing (kind of feature request):

    What about
    Quote(http-error) for more fine-granular checking of http responses?


    Currently I have client code like (snippet):

           (setq res (get-url (append "http://localhost/ViPLab/" r))
                  net_err (net-error))
            (if (not net_err)
                (if (not (find "^ERR: server code 404:" res 0))
                    (print res)
                    (begin
                      (logg:err (0 (find "n" res) res))
                      (exit 1)))
                (begin
                  (logg:err net_err)
                  (exit 1)))

    There may be a need to extend this further for other error messages (formatting stable?)...



    It would be nice to have a unique and simple access to last HTTP status/error code (may be nil for no or (syntactically) invalid server response).

    It already will be parsed somewhere...



    Then simple error checking could be done by (htt-status is better than http-error)
    (>= (http-status) 400)
    or so (besides checking for net-error).



    (get-url) "list" mode does not help for a unique access:

    there is no HTTP status (error or not) in headers part (which I would expect there, because it is a header), but only some error messages (covering which HTTP status codes?) prepended to content from server; and if there is no error (which HTTP status codes?), there is no access to HTTP status code at all (there is more no-error status codes than just '200 OK').

    Lutz

    #5
    The main reason for having server mode in newLISP is for distributed processing with 'net-eval'. HTTP mode was added to make simple browser configuration pages for servers possible, e.g. for configuring master-nodes in distributed system and configuring embedded systems like modems. It was never meant to be full a featured web server.

    hartrock

    #6
    Let me explain my current usecase a bit (there is no use of newLISP -http mode).



    Usecase (being topic in this thread) is HTTP-server testing by newLISP scripts, being the clients of an HTTP server.

    Therefore I wanted to get rid of calling curl commands by newLISP scripts (after getting rid of curl commands as part of bash scripts). Why using curl, if there already is similar functionality built in newLISP?



    So I've started using (get|post|delete|put)-url funcs, which looked promising for this purpose.

    But for fully testing server behavior, it makes sense to have access to whole server response - headers, content (which mostly is part of a server reply) and HTTP status code in a unique way.



    Because there already is

    [*] some parsing of server responses for creating HTTP net-errors,
  • [*] "devel" mode for *-url requests, giving almost all headers;
  • [/list]

    at first sight less effort seems to be needed for a great improvement of server testing capabilities.

    But I may be wrong here, because there surely are some complications (from the manual):
    Quoteget-url handles redirection if it detects a Location: spec in the received header and automatically does a second request. get-url also understands the Transfer-Encoding: chunked format and will unpack data into an unchunked format.

    And if someone wanted to test e.g. redirection behavior of some server, then there may be further feature requests... (but not from me ;-) )



    I'm assuming, that implementing such functionality as a module - funcs possibly named http-(get|post|delete|put|head)-url - would double much stuff already there as part of built in functions (and reuse instead of doubling is a good thing).



    It was never meant to be full a featured web server.[/quote]

    Lutz

    #7
    In 'get/put/post-url' the new string option "raw" works like the "list" option but returns the server status/error code as the the last member in the returned list and also suppresses 'Location' redirection.



    http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/

    hartrock

    #8
    Thanks: this is good for my usecase (and probably some of others).



    Some feedback:

    [*]Inconsistency:

    Using additional "debug" flag, "list debug" differs from "raw debug", which does not show sent headers:

    > (get-url "http://localhost/doesNotExist.txt" "list debug")
    GET /doesNotExist.txt HTTP/1.1
    Host: localhost
    User-Agent: newLISP v10604
    Connection: close

    HTTP/1.1 404 Not Found

    ("Date: Fri, 17 Jul 2015 11:17:21 GMTrnServer: Apache/2.2.22 (Debian)rnVary: Accept-EncodingrnContent-Length: 289rnConnection: closernContent-Type: text/html; charset=iso-8859-1rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">n<html><head>n<title>404 Not Found</title>n</head><body>n<h1>Not Found</h1>n<p>The requested URL /doesNotExist.txt was not found on this server.</p>n<hr>n<address>Apache/2.2.22 (Debian) Server at localhost Port 80</address>n</body></html>n"
     404)
    > (get-url "http://localhost/doesNotExist.txt" "raw debug")
    ("Date: Fri, 17 Jul 2015 11:17:30 GMTrnServer: Apache/2.2.22 (Debian)rnVary: Accept-EncodingrnContent-Length: 289rnConnection: closernContent-Type: text/html; charset=iso-8859-1rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">n<html><head>n<title>404 Not Found</title>n</head><body>n<h1>Not Found</h1>n<p>The requested URL /doesNotExist.txt was not found on this server.</p>n<hr>n<address>Apache/2.2.22 (Debian) Server at localhost Port 80</address>n</body></html>n"
     404)

    I would expect to see sent headers for "raw debug", too.
  • [*]Docu:

    Difference in semantics between "raw" and "list" seems to be, to avoid redirection in "raw" case (not tested); because both return the HTTP status code as third element (which is good and should stay IMO):

    > (get-url "http://localhost/doesNotExist.txt" "list")
    ("Date: Fri, 17 Jul 2015 11:18:07 GMTrnServer: Apache/2.2.22 (Debian)rnVary: Accept-EncodingrnContent-Length: 289rnConnection: closernContent-Type: text/html; charset=iso-8859-1rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">n<html><head>n<title>404 Not Found</title>n</head><body>n<h1>Not Found</h1>n<p>The requested URL /doesNotExist.txt was not found on this server.</p>n<hr>n<address>Apache/2.2.22 (Debian) Server at localhost Port 80</address>n</body></html>n"
     404)
    > (get-url "http://localhost/doesNotExist.txt" "raw")
    ("Date: Fri, 17 Jul 2015 11:18:11 GMTrnServer: Apache/2.2.22 (Debian)rnVary: Accept-EncodingrnContent-Length: 289rnConnection: closernContent-Type: text/html; charset=iso-8859-1rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">n<html><head>n<title>404 Not Found</title>n</head><body>n<h1>Not Found</h1>n<p>The requested URL /doesNotExist.txt was not found on this server.</p>n<hr>n<address>Apache/2.2.22 (Debian) Server at localhost Port 80</address>n</body></html>n"
     404)
  • [/list]

    Lutz

    #9
    Thanks for the thorough analysis. Changed option handling again:



    The "raw" option only suppresses the location redirection and can be used alone or combined with other options. The status code is always included as the last list member when the "list" option is specified.



    http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/



    try:



    (get-url "http://newlisp.org")
    (get-url "http://newlisp.org" "raw")
    (get-url "http://newlisp.org" "list raw")
    (get-url "http://newlisp.org" "list raw debug")

    hartrock

    #10
    Thanks for the upgrade.



    Unfortunately there is some problem:

    > ; "OK with "list":
    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list"))
    ("Date: Fri, 17 Jul 2015 18:37:10 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > ; -> OK
    > ;
    > ; but with "list debug":
    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list debug"))
    POST /ViPLab HTTP/1.1
    Host: localhost
    User-Agent: newLISP v10604
    Connection: close
    Content-type: text/plain
    Content-length: 13

    dummy contentHTTP/1.1 404 Not Found

    ("Date: Fri, 17 Jul 2015 18:38:13 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    ian)
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > ; -> failure: see the string artefact 'ian)'
    > ;
    > ; it can be repaired by:
    > (print (0 (t 1)))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"

    This is very strange. Possibly the 'repair' by copying the string gives you an idea, where the problem may be...



    Digging deeper:

    > (set 'r1 (t 1))
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (print r1)
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    ian)
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (set 'r2 (0 r))
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (print r2)
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (list (length r1) (length r2))
    (63 63)
    > (map (lambda (ix) (= (r1 ix) (r2 ix))) (sequence 0 (-- (length r1))))
    (true true true true true true true true true true true true true true true true true true true true true
     true true true true true true true true true true true true true true true true true true true true true
     true true true true true true true true true true true true true true true true true true true true true)

    At interpreter level strings seem to be OK...

    Lutz

    #11
    If this happened on Windows or OS2, TRU64, Solaris or AIX, it may have been fixed:



    http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/



    There was an uninitialized buffer in a custom version of vasprintf() -> my_vasprintf() used by above OSs.



    Ps: doing some more changes affecting all OSs, the way varargs is used - will post those Sunday morning PST.

    hartrock

    #12
    Quote from: "Lutz"If this happened on Windows or OS2, TRU64, Solaris or AIX, it may have been fixed:



    http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/



    There was an uninitialized buffer in a custom version of vasprintf() -> my_vasprintf() used by above OSs.

    No, error has been on Debian Linux.


    Quote from: "Lutz"
    Ps: doing some more changes affecting all OSs, the way varargs is used - will post those Sunday morning PST.

    This sounds like a bigger change with many chances for errors...



    When there is a newer devel version I'll test again on Monday or other working days and give feedback again (I don't have access to corresponding system here).

    Lutz

    #13
    Another update avoiding empty argptr in variadic nl-web.c:sendf() :



    http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/

    hartrock

    #14
    Testing with
    newlisp-10.6.4.tgz      2015-07-19 23:31  1.6M bug stays (first call OK, thereafter bug):

    newLISP v.10.6.4 64-bit on Linux IPv4/6 UTF-8 libffi, options: newlisp -h

    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list"))
    ("Date: Mon, 20 Jul 2015 13:51:33 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > ; -> OK
    > ;
    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list debug"))
    POST /ViPLab HTTP/1.1
    Host: localhost
    User-Agent: newLISP v10604
    Connection: close
    Content-type: text/plain
    Content-length: 13

    dummy contentHTTP/1.1 404 Not Found

    ("Date: Mon, 20 Jul 2015 13:52:17 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    ian)
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > ; -> bug triggered
    > ;

    Another observation: if at first provoking the bug with "list debug", then it stays even with arg "list" not provoking it in former test, but - update - only once:

    sr@mad:~/newLISP/BoF$ newlisp
    newLISP v.10.6.4 64-bit on Linux IPv4/6 UTF-8 libffi, options: newlisp -h

    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list debug"))
    POST /ViPLab HTTP/1.1
    Host: localhost
    User-Agent: newLISP v10604
    Connection: close
    Content-type: text/plain
    Content-length: 13

    dummy contentHTTP/1.1 404 Not Found

    ("Date: Mon, 20 Jul 2015 14:06:13 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    ian)
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list"))
    ("Date: Mon, 20 Jul 2015 14:06:34 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    ian)
    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    > (set 't (post-url "http://localhost/ViPLab" "dummy content" "text/plain" "list"))
    ("Date: Mon, 20 Jul 2015 14:18:50 GMTrnServer: Apache/2.2.22 (Debian)rnContent-Length: 17rnConnection: closernContent-Type: text/plain; charset=utf-8rnrn"
     "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn" 404)
    > (print (t 1))
    ERR: server code 404: HTTP/1.1 404 Not Found
    404: Not Found.

    "ERR: server code 404: HTTP/1.1 404 Not Foundrn404: Not Found.nn"
    >

    Anything else I could test?



    BTW: it would be helpful, if newlisp -v (or -v -v) would contain a built timestamp (to be sure, that you are really using a just built binary (though just building/installing does not ensure, that you have built from the correct source)).