HTTP: Random Socket Closed Errors

I am getting this random error from HTTP calls:

code=<[string “socket”]:1540: closed>, status=<nil>

Sending the exact same simple http request to the exact same target can sometimes result in this error, and other times a normal OK 200 return. I’ve monitored things on the receiving end and can confirm the request is received and responded-to identically every time.

I began to wonder if this was somehow an Edge blocking problem, but I initiate the http calls within a function called with a device.thread:queue_event, so it is not running in the driver thread.

I can find no reason for this to be happening.

I think my next step is to monitor what’s going on with wireshark and see what’s happening at the TCP level.

Any other thoughts from the experts out there?!

Hi, @TAustin!
I already asked the team about this. I’ll let you know once I get their feedback :smiley:

@TAustin Is this by chance an https request or is it in fact plain old http?

Hi Robert. This was just a plain http request. But I think I may have found the issue - I’m not sure if it should be considered a bug or not…

I was assuming that if I passed a null body into the request parameters, that it would not be a problem and simply result in no body being sent with the request.

body, code, headers, status = http.request{
      method = req_method,
      url = req_url,
      headers = sendheaders,
      source = ltn12.source.string(sendbody),
      sink = ltn12.sink.table(responsechunks)
     }

However, I put a TCP trace on things and found that Edge was sending an extra “0\0d\0a” that was confusing the target device causing TCP errors, and then resulting in the closed socket errors back to my Edge driver.

I found that by simply changing the code to not include any source whenever my sendbody wasn’t needed, cleared it up.

My limited understanding is that the “0\0d\0a” string is used to signal an end to chunked encoding, so the library was seeing no data to send but still sending that string - confusing the TCP stack on the other end.

I may not be quite right on all of the above as I haven’t done extensive testing. But the moral of the story seems to be you can’t pass a null body string for source, or bad things can happen.

It looks like this is the default behavior for luasocket, we haven’t made any changes there:

By default if source is nil it gets replaces with ltn12.source.empty() otherwise it gets "pump"ed through the "http-chunked" sync, which has a final iteration to add this in:

so, it seems like the only wait to avoid this would be to either add a guard like sendbody and ltn12.source.string(sendbody). Another option might be to set a content-length header, which, it looks like, would avoid the chunk encoding.

1 Like

Thanks very much for investigating. Hopefully these findings will help others avoid this problem in the future.