openfaas / of-watchdog

Reverse proxy for STDIO and HTTP microservices
MIT License
259 stars 115 forks source link

of-watchdog always uses Transfer-Encoding: chunked despite having a valid and accurate Content-Length available #116

Closed OfWatchdogMissingContentLength closed 1 year ago

OfWatchdogMissingContentLength commented 3 years ago

I'm trying to set up a Nim HTTP function using of-watchdog. I've managed to configure of-watchdog in HTTP mode where GET and POST (with no data) work as expected. However, upon trying to send a POST with data, I get a Content-Length required. response from Nim.

Expected Behaviour

I would expect the setup to work for POST with data, ie. the entire set of headers should be forwarded, including Content-Length. I've tried using of-watchdog versions 0.7.2, 0.7.7, and 0.8.1 and none of them worked as expected.

I would like to see the Content-Length header in my final HTTP server.

Current Behaviour

Neither the headers being passed to the upstream url nor the headers made available in cgi_headers include the content length.

Possible Solution

I believe that Go treats the Content-Length header specially, and for some reason it doesn't seem to get passed on.

A possible solution would be to manually include the Content-Length header, and set it to Request.ContentLength (per https://golang.org/pkg/net/http/#Request).

Steps to Reproduce (for bugs)

A live example is available at http://159.89.118.201:8080/function/nim-sudoku-faas - start at step 5 below.

To reproduce, the full source code can be used with the following steps:

  1. git clone https://gitlab.com/vabresto/nim-sudoku-faas/-/tree/master nim-sudoku-faas
  2. cd nim-sudoku-faas
  3. vim stack.yml and change the image from registry.gitlab.com/vabresto/nim-sudoku-faas to an appropriate image name you can push to
  4. faas-cli deploy
  5. Navigate to your function via a web browser, should see a sudoku board
  6. Click the "Solve" button at the bottom (optionally after filling out any values on the board)
  7. Get Content-Length required. as the reply, instead of the completed board.

If you run just the nim code (ex. cd nim-sudoku-faas/nim-sudoku && nimble run then connect to 127.0.0.1:8888), clicking the "Solve" button will correctly return a solved sudoku board.

Note that the "Reset" button works because that is just refreshing the page.

This is the line in the Nim server where the failure occurs: https://github.com/nim-lang/Nim/blob/devel/lib/pure/asynchttpserver.nim#L250 Note that I've included a version of this file with some debug print statements in my source code, called instr_asynchttpserver.nim, which is how the logs below were produced.

I believe this might be a good starting point for debugging the Go code: https://github.com/openfaas/of-watchdog/blob/master/executor/http_runner.go#L100

Current debug output:

2021-01-04T03:15:56Z Forking - nim-sudoku []
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Started logging stderr from function.
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Started logging stdout from function.
2021-01-04T03:15:56Z 2021/01/04 03:15:56 OperationalMode: http
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Timeouts: read: 10s, write: 10s hard: 10s.
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Listening on port: 8080
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Writing lock-file to: /tmp/.lock
2021-01-04T03:15:56Z 2021/01/04 03:15:56 stdout: Starting ...
2021-01-04T03:15:56Z 2021/01/04 03:15:56 Metrics listening on port: 8081
2021-01-04T03:16:09Z 2021/01/04 03:16:09 GET / - 200 OK - ContentLength: 9614
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: Nim server check: {"accept": @["text/html", "application/xhtml+xml", "application/xml;q=0.9", "image/webp", "*/*;q=0.8"], "x-forwarded-host": @["159.89.118.201:8080"], "accept-language": @["en-CA", "en-US;q=0.7", "en;q=0.3"], "pragma": @["no-cache"], "dnt": @["1"], "x-forwarded-for": @["10.62.0.1:60246"], "host": @["10.62.0.72:8080"], "upgrade-insecure-requests": @["1"], "user-agent": @["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0"], "accept-encoding": @["gzip", "deflate"], "cache-control": @["no-cache"]}
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: Nim env:
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> PATH : /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> mode : http
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> upstream_url : http://127.0.0.1:8888
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> fprocess : nim-sudoku
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> cgi_headers : true
2021-01-04T03:16:09Z 2021/01/04 03:16:09 stdout: -> HOME : /root
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: Nim server check: {"transfer-encoding": @["chunked"], "accept": @["text/html", "application/xhtml+xml", "application/xml;q=0.9", "image/webp", "*/*;q=0.8"], "x-forwarded-host": @["159.89.118.201:8080"], "origin": @["http://159.89.118.201:8080"], "accept-language": @["en-CA", "en-US;q=0.7", "en;q=0.3"], "content-type": @["application/x-www-form-urlencoded"], "pragma": @["no-cache"], "dnt": @["1"], "x-forwarded-for": @["10.62.0.1:60246"], "host": @["10.62.0.72:8080"], "upgrade-insecure-requests": @["1"], "referer": @["http://159.89.118.201:8080/function/nim-sudoku-faas"], "user-agent": @["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0"], "accept-encoding": @["gzip", "deflate"], "cache-control": @["no-cache"]}
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: Nim env:
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> PATH : /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> mode : http
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> upstream_url : http://127.0.0.1:8888
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> fprocess : nim-sudoku
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> cgi_headers : true
2021-01-04T03:16:11Z 2021/01/04 03:16:11 stdout: -> HOME : /root
2021-01-04T03:16:11Z 2021/01/04 03:16:11 Unsolicited response received on idle HTTP channel starting with "HTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\n400 Bad RequestHTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\n400 Bad RequestHTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\n400 Bad Request"; err=<nil>
2021-01-04T03:16:11Z 2021/01/04 03:16:11 POST / - 411 Length Required - ContentLength: 24

I think the bad request at the end is due to trying to fetch a favicon, but I'm not sure. I'd like to get rid of that error if possible.

Context

I'm trying to build a proof of concept Nim function-as-a-service. I don't want to use the classic watchdog because having control over incoming and outgoing HTTP headers is valuable, and it allows for testing the function outside of the container for dev purposes more easily.

I can't work around this (ex. by changing the stdlib Nim HTTP server implementation to fetch the values from the environment) because the env isn't correctly populated either.

Your Environment

> docker version
Client: Docker Engine - Community
 Version:           20.10.1
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        831ebea
 Built:             Tue Dec 15 04:34:58 2020
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.1
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       f001486
  Built:            Tue Dec 15 04:32:52 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc92
  GitCommit:        ff819c7e9184c13b7c2607fe6c30ae19403a7aff
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

I'm using faasd with --lang=dockerfile

Ubuntu 20.04

Code: https://gitlab.com/vabresto/nim-sudoku-faas/-/tree/master Live: http://159.89.118.201:8080/function/nim-sudoku-faas

Note there is also a Python endpoint I tried using available at http://159.89.118.201:8080/function/pls that does manage to include the Content-Length, which uses the python3-http template available from the store, with handler.py set to

def handle(event, context):
    return {
        "statusCode": 200,
        "body": f"Hello from OpenFaaS! Body: {event.body} Headers: {event.headers} Method: {event.method}",
    }

Includes the full function setup, running faas-cli up should set everything up (may need to change image prefix).

OfWatchdogMissingContentLength commented 3 years ago

I've done some more digging and debugging, and it seems the issue is that although a Content-Length is known, of-watchdog instead sends an HTTP request with Transfer-Encoding: chunked, which is not yet supported by my Nim server.

I claim this is still a bug/unexpected behaviour, but it wasn't obvious to me if this is something done by of-watchdog or the go standard library.

See logs:

2021/01/06 05:00:23 map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8] Accept-Encoding:[gzip, deflate] Accept-Language:[en-CA,en-US;q=0.7,en;q=0.3] Cache-Control:[no-cache] Connection:[keep-alive] Content-Length:[11] Dnt:[1] Origin:[http://159.89.118.201:9999] Pragma:[no-cache] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0]]
POST / HTTP/1.1
Host: 159.89.118.201:9999
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 11
Dnt: 1
Origin: http://159.89.118.201:9999
Pragma: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0

hello=world
2021/01/06 05:00:23 stderr: Got raw line: Host: 159.89.118.201:9999
2021/01/06 05:00:23 stderr: Got raw line: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0
2021/01/06 05:00:23 stderr: Got raw line: Transfer-Encoding: chunked
2021/01/06 05:00:23 stderr: Got raw line: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
2021/01/06 05:00:23 stderr: Got raw line: Accept-Encoding: gzip, deflate
2021/01/06 05:00:23 stderr: Got raw line: Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
2021/01/06 05:00:23 stderr: Got raw line: Cache-Control: no-cache
2021/01/06 05:00:23 stderr: Got raw line: Connection: keep-alive
2021/01/06 05:00:23 stderr: Got raw line: Dnt: 1
2021/01/06 05:00:23 stderr: Got raw line: Origin: http://159.89.118.201:9999
2021/01/06 05:00:23 stderr: Got raw line: Pragma: no-cache
2021/01/06 05:00:23 stderr: Got raw line: Upgrade-Insecure-Requests: 1
alexellis commented 3 years ago

Hi there,

For us to see whether it's the watchdog or some other component, you should run the watchdog on your host and show us that output.

Alex

alexellis commented 3 years ago

/msg: enduser

derek[bot] commented 3 years ago

Thank you for your interest in OpenFaaS. This project is maintained and made available for hobbyists and commercial users alike, so we need to balance our time across everyone's needs. Whilst we are excited in your interest in using OpenFaaS, we would also ask you to take a look at our contribution guide on Setting expectations, support and SLAs.

Commercial users can purchase support in order to get dedicated help from OpenFaaS Ltd, or they can book ad-hoc consulting hours to get an engineer to dedicate time to helping them.

If that is not a good fit for you at this time, please check out the OpenFaaS GitHub Sponsors options which are priced for practitioners like yourself. Organisations can also sponsor through their GitHub billing relationship.

When you become a sponsor as an indvidual, it will show this on your issues and PRs, so that the community can see that you are supporting our work, and can prioritise your needs.

If you are receiving this message after having received hands-on support from the OpenFaaS community, please join GitHub Sponsors to say thank you for our time.

Thank you for supporting OpenFaaS.

alexellis commented 3 years ago

/add label: support, question

alexellis commented 1 year ago

/lock: not enough information