Search code examples
windowsbatch-filewebservernamed-pipesnetcat

How to respond conditionally based on the request when using netcat


I am trying to set up a web server using only windows batch scripting.

I have already come up with the following script:

@echo off
@setlocal  enabledelayedexpansion

for /l %%a in (1,0,2) do (
  type tempfile.txt | nc -w 1 -l -p 80  | findstr mystring
  if !ERRORLEVEL! == 0 (
    echo found > tempfile.txt
  ) else (
    echo not-found > tempfile.txt
  )
)

However, the response is always one request behind, I mean, if I type something like this into the browser:

REQUEST: localhost/mystring

I will get the following response:

RESPONSE: not-found

Only in the next request I will receive the correct answer for the request presented above.

This is happening because as soon as netcat receives a request it responds with the current content of the tempfile.txt which has not been updated yet based on the request.

Is there any way to block the response until the tempfile.txt is updated or any other method which accomplish the expected result?


Solution

  • The problem is, as far as I can tell, nc can't perform a callback to tailor its output based on client input. Once you have...

    stdout generation | nc -l
    

    ... blocking and waiting for a connection, its output is already determined. That output is static at that point.

    The only workaround which occurs to me is rather inefficient. It basically involves the following logic:

    1. Listen for a connection prepared to make the client perform a reload
    2. Scrape the GET address from the previous request's headers.
    3. Serve relevant content on client's second connection

    Example code:

    @echo off & setlocal
    
    rem // macro for netcat command line and args
    set "nc=\cygwin64\bin\nc.exe -w 1 -l 80"
    
    rem // macro for sending refresh header
    set "refresh=^(echo HTTP/1.1 200 OK^&echo Refresh:0;^)^| %nc%"
    
    for /L %%# in (1,0,2) do (
        rem // run refresh macro and capture client's requested URL
        for /f "tokens=2" %%I in ('%refresh% ^| findstr "^GET"') do set "URL=%%I"
    
        rem // serve content to the client
        setlocal enabledelayedexpansion
        echo URL: !URL! | %nc%
        endlocal
    )
    

    As a side note, delayed expansion can mutilate variable values set with exclamation marks if it's enabled at the time of setting. Best to wait to enable delayed expansion until retrieval.

    Also, when performing a boolean check on %ERRORLEVEL% it's more graceful to employ conditional execution. But that has nothing to do with my solution. :)

    And finally, instead of doing type filename.html | nc -l, consider using <filename.html nc -l (or nc -l <filename.html) to avoid the useless use of type.