Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP server's response fails if request body is ignored #1270

Closed
tve opened this issue Dec 14, 2023 · 3 comments
Closed

HTTP server's response fails if request body is ignored #1270

tve opened this issue Dec 14, 2023 · 3 comments

Comments

@tve
Copy link
Contributor

tve commented Dec 14, 2023

Moddable SDK version: 4.3
Target device: esp32

Description
Using the HTTP Server class, if the headersComplete callback returns false on a PUT request, a response provided by the subsequent prepareResponse callback is not sent out. The Socket is reset instead.

Steps to Reproduce

  1. Run an adaptation of the HTTP server example httpserverputfile as follows:
ver } from "http"
import { File } from "file"
import Net from "net"

new Server({}).callback = function (message, value) {
  switch (message) {
    // case Server.status:					// request status received
    // 	let path = value;				// file path is HTTP path
    // 	File.delete(path);
    // 	this.file = new File(path, true);
    // 	break;

    case Server.headersComplete: // prepare for request body
      return false // ignore request body

    // case Server.requestFragment: // request body fragment
    //   this.read(ArrayBuffer)
    //   break

    case Server.prepareResponse: // request body received
      return { status: 400, body: "I did not like this file" }
  }
}

trace(`Available on Wi-Fi "${Net.get("SSID")}"\n`)
trace(
  `curl --data-binary "@/users/[your directory path here]/test.txt"  http://${Net.get(
    "IP"
  )}/test.txt -v\n`
)

(The manifest can be used unchanged from the original example)
3. Perform a PUT request with some file, like:

> curl --data-binary @README.md  http://192.168.0.216/test.txt -v
*   Trying 192.168.0.216:80...
* Connected to 192.168.0.216 (192.168.0.216) port 80
> POST /test.txt HTTP/1.1
> Host: 192.168.0.216
> User-Agent: curl/8.4.0
> Accept: */*
> Content-Length: 1913
> Content-Type: application/x-www-form-urlencoded
> 
* Recv failure: Connection reset by peer
* Closing connection
curl: (56) Recv failure: Connection reset by peer
  1. Observe that curl is not happy...
  2. Run a tcpdump and observe that the server (esp32) indeed sends a TCP reset
22:49:13.919952 IP 192.168.0.2.44648 > 192.168.0.216.80: Flags [S], seq 3093353672, win 64240, opt
ions [mss 1460,sackOK,TS val 2898494770 ecr 0,nop,wscale 7], length 0                             
22:49:14.232456 IP 192.168.0.216.80 > 192.168.0.2.44648: Flags [S.], seq 3154734909, ack 309335367
3, win 8192, options [mss 1436], length 0                                                         
22:49:14.232483 IP 192.168.0.2.44648 > 192.168.0.216.80: Flags [.], ack 1, win 64240, length 0    
22:49:14.232574 IP 192.168.0.2.44648 > 192.168.0.216.80: Flags [P.], seq 1:2873, ack 1, win 64240,
 length 2872: HTTP: PUT /fs/ui/dist/favicon.ico HTTP/1.1                                          
22:49:14.232673 IP 192.168.0.2.44648 > 192.168.0.216.80: Flags [P.], seq 2873:4447, ack 1, win 642
40, length 1574: HTTP                                                                             
22:49:14.235268 IP 192.168.0.216.80 > 192.168.0.2.44648: Flags [.], ack 2873, win 5320, length 0  
22:49:14.236205 IP 192.168.0.216.80 > 192.168.0.2.44648: Flags [.], ack 4447, win 3746, length 0  
22:49:14.282775 IP 192.168.0.216.80 > 192.168.0.2.44648: Flags [R.], seq 1, ack 4447, win 32, leng
th 0                                                                                              
  1. Set a breakpoint at https://github.com/Moddable-OpenSource/moddable/blob/public/modules/network/http/http.js#L743 which is where the server calls this.close() to close the socket. Then re-run the curl and as soon as the breakpoint is hit press the continue button. Observe how the request/response completes correctly.
> curl --data-binary @README.md  http://192.168.0.216/test.txt -v
*   Trying 192.168.0.216:80...
* Connected to 192.168.0.216 (192.168.0.216) port 80
> POST /test.txt HTTP/1.1
> Host: 192.168.0.216
> User-Agent: curl/8.4.0
> Accept: */*
> Content-Length: 1913
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 400 Bad Request
< connection: close
< content-length: 24
< 
* Closing connection
I did not like this file⏎

Other information
As far as I can tell:

  • HTTP Server does not read the request body when the callback returns false
  • it simply sends the response and closes the socket
  • lwip gets the close holding unconsumed rx buffers and probably also an untransmitted tx buffer and instead of sorting everything out just resets the connection?
@phoddie
Copy link
Collaborator

phoddie commented Dec 14, 2023

Please try these changes:

Change

						if (false === request)
							delete this.total;				// ignore request body and just send response

to

						if (false === request)
							socket.ignore = true;			// ignore request body before sending response

And

				if (true === this.request)

to

				if (socket.ignore) {
					socket.read(null, count);
					this.total -= count;
				}
				else if (true === this.request)

That works for me on ESP32, even using an absurdly large request body (2+ MB).

@tve
Copy link
Contributor Author

tve commented Dec 14, 2023

This set of changes fixes the issue for me, thanks!

mkellner pushed a commit that referenced this issue Dec 16, 2023
@phoddie
Copy link
Collaborator

phoddie commented Dec 23, 2023

Closing (fixed).

@phoddie phoddie closed this as completed Dec 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants