socketio/engine.io

Make sendErrorMessage response available on server

mrazf opened this issue · 5 comments

mrazf commented

Note: for support questions, please use one of these channels: stackoverflow or slack

You want to:

  • [] report a bug
  • request a feature

Current behaviour

Apologies if this is my misunderstanding of NodeJS streams.

The HTTP body of sendErrorMessage is readable on the client but does not appear to be accessible server side.

I'm currently investigating a number of 400 errors produced here but it looks like this could be 1 of 4 Server.errorMessages.

Are the response bodies available server side or would it be possible to add some debug logging that includes the body before sending the response?

Steps to reproduce (if the current behaviour is a bug)

Expected behaviour

Setup

  • OS:
  • browser:
  • engine.io version:

Other information (e.g. stacktraces, related issues, suggestions how to fix)

Khez commented

We've noticed a very similar issue in production as well and came to the same conclusions.

We believe the root cause is a faulty proxy between a client and our socket.io implementation. But unfortunately we can't confirm it.

Flow

Delving through the logs, we found the same code in engine.io v3.x being the culprit:

Problem

This entire scenario is completely hidden from the underlying server.

Checking the code it seems there are a number of different errors that can cause this:

So together there are 8 separate problems that lead to either 400 or 403 status code, the only difference being the json output, which itself has 5 distinct results

Solution

Since we're already using emit for connection, we could add an emit for these scenarios as well.

If there's no problem with a similar solution I can help with a PR (maybe on both 3.x and 4.x branches)

@Khez Thanks for the detailed explanation. Do you have a suggestion for the API?

Related: socketio/socket.io#3819

Khez commented

It feels like emitting an event is the way to go, as it was proposed socketio/socket.io#3819 as well :)

To be honest, it kind of depends on what people need. Is it a hook that can change things or just a means to logging ?

@darrachequesne I'm going to try to make a PR over the weekend on the 3.4.x branch then we could port it to 3.5.x and master. It will give me more insight into how to properly tackle this issue. Unless you believe in a different approach.

Hooking into the error page

There might be a need to hook into and possibly even change the error page.

It doesn't seem that engine.io-client looks at what the underlying content of the error page is.
Meaning changes to the page should be backwards compatible with the client implementation.

I'd vote for this to be a separate issue / PR, since probably many users don't even know this scenario occurs.

Note on error pages

It seems there are two separate ways of causing an error page and they are different:

Feels like it should always be application/json. Uncertain why it is not.

Hooking into the error codes

It seems @andrejleitner, @mrazf and myself just need a way to log this scenario.

With an update to make error codes unique, we could simply emit from sendErrorMessage:

Path of least resistance

We already have an error list, some of which are unique with regard to the underlying issue.

We'd need to cover non-unique codes that are currently BAD_REQUEST:

With a change to the error codes, we could simply emit from sendErrorMessage:

  • Server.errorMessages[code] would represent all engine.io scenarios
  • Server.errors.FORBIDDEN remains the result of allowRequest

This method would forces us to "skip" Server.errorMessages[5] which is used in branch 4.x by UNSUPPORTED_PROTOCOL_VERSION
Still wondering if a different parameter or a mild refactor of sendErrorMessage would be more beneficial.

Khez commented

@darrachequesne any chance you can take a look through the PR so we can move this issue forward ?

I'm open to any and all suggestions :)

Closed by 7096e98, included in engine.io@5.1.0.

Syntax:

server.on("connection_error", (err) => {
  console.log(err.req);		// the request object
  console.log(err.code);	// the error code, for example 1
  console.log(err.message);	// the error message, for example "Session ID unknown"
  console.log(err.context);     // some additional error context
});