Wonder why they wouldn't pass in the whole request on stdin? That would also mean that instances could be pre-started in anticipation of a request and not just when one is already waiting.
On passing environment variables instead of the full request, probably to make it more accessible to get started with the existing popular languages (C, Perl, Tcl, Shell Scripts, mostly) without having to write all the request parsing. There was also less "stuff" in the request than today. No cookies, no file uploads, and so on. They also passed things in that weren't in the request itself, like REMOTE_ADDR, REMOTE_HOST, SERVER_PORT, PATH_INFO and so on. So it seemed natural to just put everything in environment variables, other than the $CONTENT_LENGTH bytes that followed the header.
As for the fork() per request, I believe mostly because they were starting with requirements where avoiding fork() wasn't important. Conserving memory was probably more important, given the timeframe. CGI programs that leaked memory would have been common if they were daemons. For most web servers, there also probably weren't that many requests.
It was also a common existing pattern. Many of the services on unix boxes worked the same way...one daemon (inetd) would start instances of daemons per request and they would serve only one request.
That said, NSAPI appeared pretty quickly after CGI, then FastCGI, etc. Still pushing environment variables for headers, but stopping the request->fork->exit pattern and allowing persistent daemons.
To allow processing of large request and response bodies. Imagine a 1Gb PUT or GET. You don’t want to spend 1Gb RAM for handling those. And you also don’t want to wait multiple minutes to hours to have the body buffered and can actually present it to application logic.
Not sure I follow. A reasonable framework would stream both the incoming request as well as the response. If the WASM module wants to read the whole thing into memory, it's free to do so, but you could have it process the request piecemeal. It's just reading the request from a file descriptor and writing the response to another one. Not that different when those fds are actually sockets.
Oh sorry. I misread it and thought you are asking why the request isn’t passed in complete form as an environment variable too. I guess you are asking why the request headers are not transferred via stdin too? My guess it’s just because that’s how CGI works. It prevents from having apps do the parsing work. Plus what could be passed wouldn’t be the original request anyway. If the Webserver handles http2 or http3 headers would always need to be repacked into a format that the script understands.
As for the fork() per request, I believe mostly because they were starting with requirements where avoiding fork() wasn't important. Conserving memory was probably more important, given the timeframe. CGI programs that leaked memory would have been common if they were daemons. For most web servers, there also probably weren't that many requests.
It was also a common existing pattern. Many of the services on unix boxes worked the same way...one daemon (inetd) would start instances of daemons per request and they would serve only one request.
That said, NSAPI appeared pretty quickly after CGI, then FastCGI, etc. Still pushing environment variables for headers, but stopping the request->fork->exit pattern and allowing persistent daemons.