webserver
About webserver
|
News/Changelog1.0-0o webstart() accepts connections on one or more listeners specified by listen=, each a port number (local HTTP), "http://<host>:<port>", "https://<host>:<port>" or "unix:<path>" (local socket, unix only). <host> can be "localhost" (local connections only), "*" (all IPv4 interfaces), a numeric IPv4 address or an IPv6 address in [] (e.g., "[::1]" or "[::]"). IPv6 listeners only accept IPv6 connections on all systems, so "https://*" and "https://[::]" together serve both. simple() passes further arguments (such as threads) on to webstart(). o TLS/SSL (HTTPS) support. Listeners using "https://" require a server certificate and its private key (PEM format) specified with tls.cert and tls.key. The key defaults to tls.cert, so a single file with both is sufficient. The minimal configuration is webstart("https://*:8443", tls.cert="server.crt", tls.key="server.key") If the certificate was issued by an intermediate CA, its certificate(s) must be sent along with the server certificate: either append them to the tls.cert file (after the server certificate) or specify a separate file with tls.ca. HTTP and HTTPS listeners can be combined, e.g., to serve local clients without encryption: webstart(c(8080, "https://*:8443"), tls.cert="server.pem") The tls.* arguments apply to all HTTPS listeners, but can also have one value per HTTPS listener, e.g., to use different certificates on different ports. Clients can be required to authenticate with a certificate: tls.client.ca specifies the CA certificate(s) the client certificates must be issued by, connections without a valid certificate are rejected. tls.client.cn further restricts the allowed common names of the client certificates, a name can start or end with * to match a suffix or a prefix: webstart("https://*:8443", tls.cert="server.pem", tls.client.ca="corp-ca.pem", tls.client.cn=c("alice", "*.corp.example.com")) The client CA should be dedicated to issuing client certificates (e.g., the organisation's own CA), since every certificate it issued is accepted unless tls.client.cn is used. TLS 1.2 or higher is used, encrypted private keys are not supported. TLS requires OpenSSL 1.1.0 or higher at build time, hasTLS() reports whether TLS is supported. o R handlers receive the headers Request-Proto (http or https, depending on the listener) and, if the client presented a valid certificate, Request-Client-CN with its common name, so handlers can identify clients. Header names starting with Request- are reserved for the server, such headers sent by the client (including the already present Request-Method) are dropped. o R handlers can decode the request body: addHandler("rfun", ...) has a parse.body argument which is either FALSE (default, raw body), TRUE (use defaultBodyParsers()) or a named list of parsers function(body, content.type) where the names are media types, optionally starting or ending with * to match a suffix or prefix (e.g., "*+json" or "text/*"). The default parsers decode URL encoded forms into a named character vector (like the query) and JSON (using jsonlite). If the body cannot be parsed, the request is answered with 400 Bad Request without calling the handler, e.g., addHandler("rfun", "/api", FUN, parse.body=TRUE) simple() uses parse.body=TRUE by default, so its R handler receives decoded form and JSON bodies (parse.body=FALSE passes the raw body). o folded header lines (obsolete since HTTP/1.1) are rejected with 400 Bad Request. o TLS support was never enabled on Windows (wrong macro in the Windows configuration) and configure enabled it even when no OpenSSL was found. o if a listener cannot be started, the error now includes the reason (e.g., address already in use). o an existing file at the path of a unix socket is no longer removed unless it is a socket. o forked children (fork=TRUE) no longer try to re-seed the system RNG (the code was never active). They inherit the R RNG state of the parent, see ?webstart for how to get independent random streams. o forked children now exit with _exit() and stdio is flushed before fork(). Previously a child could emit output buffered by the parent again or, when run by Rscript, make the parent continue reading its script from the wrong position. o use withVisible() instead of the non-API R_Visible in R >= 4.6.0. o support chunked request bodies (Transfer-Encoding: chunked). The chunks are collected into the request body, so handlers see the same as with Content-Length. Other transfer codings are still answered with 501, Transfer-Encoding together with Content-Length, in HTTP/1.0 or with GET/HEAD with 400. o reject header fields with whitespace between the name and the colon with 400 (RFC 9112, 5.1). Previously such Content-Length or Transfer-Encoding fields were ignored, so the body was parsed as the next request (request smuggling). o 1xx, 204 and 304 responses no longer include a body or Content-Length, which broke the framing of keep-alive connections. o reject requests with more than one Host: header with 400 (RFC 9112, 3.2). o Connection: is parsed as a list of tokens, so e.g. "Connection: keep-alive, close" closes the connection. o HTTP/1.1 responses include Connection: close if the server will close the connection (RFC 9112, 9.6). o fix a crash when the header buffer cannot be allocated. o R handlers can close the connection by including Connection: close in their headers. o R handlers evaluated on processing threads (threads > 0) now have working C stack checks using the stack of the thread. Previously the checks were disabled, so runaway recursion could crash the server instead of raising an R error. o fix compilation with the UCRT headers of Rtools 4.x (redefinition of timespec_get()). o Windows: fix a possible crash when creating the internal socket pair fails (bad format string in the error message). o fix compilation on Linux with gcc 15 (implicit declaration of pthread_setname_np()). o Windows: fix a possible crash with threads > 0 where the server loop checked for user interrupts while a processing thread was evaluating R. |