PsychicHttp icon indicating copy to clipboard operation
PsychicHttp copied to clipboard

Problems converting from ESPAsyncWebserver

Open designer-systems-ltd opened this issue 10 months ago • 47 comments

Hello

I am having some issues converting from ESPAsyncWebserver and what calls to use to send files on the file system using the request->reply().

Currently I setup the server for root as follows:

server->on("/", HTTP_GET, handle_root);
server->begin();

which handles the root file as follows:

void handle_root(AsyncWebServerRequest *request)
{
	// Redirect to index.html
	request->send(SPIFFS, "/index.html", "text/html");
}

For Psychic I have changed this to:

server.config.max_uri_handlers = 20;
server.listen(80);
server.on("/", HTTP_GET, [](PsychicRequest *request) {
	request->reply(200);
}, handle_root);

but I cannot find an example for sending a file using request->reply(), only a pre-configured file using the server.serveStatic(). As I would like to use this call to send differnet files and file types how can this be done ?

Regards David

designer-systems-ltd avatar Mar 13 '25 16:03 designer-systems-ltd

What version of ESPAsnycWebserver are you migrating from? Because it just got a massive rework from @mathieucarbou and @me_no_dev and it is better than ever. I recommend to not migrate to Psychic because it has some bugs and @hoeken is pretty far away now to maintain this repo.

Check it out: https://github.com/ESP32Async/ESPAsyncWebServer/releases/tag/v3.7.2

zekageri avatar Mar 13 '25 17:03 zekageri

What version of ESPAsnycWebserver are you migrating from? Because it just got a massive rework from @mathieucarbou and @me_no_dev and it is better than ever. I recommend to not migrate to Psychic because it has some bugs and @hoeken is pretty far away now to maintain this repo.

My understanding is that he needs SSL ;-)

mathieucarbou avatar Mar 13 '25 17:03 mathieucarbou

My understanding is that he needs SSL ;-)

SSL is the ultimate goal, and ESPAsyncWebserver does not support that functionality, hence the need to move to Psychic.

What version of ESPAsnycWebserver are you migrating from? Because it just got a massive rework from @mathieucarbou and @me_no_dev and it is better than ever. I recommend to not migrate to Psychic because it has some bugs and @hoeken is pretty far away now to maintain this repo.

We are using the latest repros of ESPAsyncWebserver, which is great for HTTP, but HTTPS still seems a long way off.

If anyone can help with the above it would be appreciated.

designer-systems-ltd avatar Mar 13 '25 17:03 designer-systems-ltd

I have implemented https and I do not recommend it. It is slow and unreliable but yes I can help you with that. As soon as iam at my desk i will write the solution

zekageri avatar Mar 13 '25 18:03 zekageri

This is for Psychic V2

server.on("/", HTTP_GET, [](PsychicRequest *req, PsychicResponse *res) {
   PsychicFileResponse response(
        res, // The PsychicResponse object
        LittleFS, // Preferred FS like SPIFFS or LitleFS
        "pathToYourFile",
        "text/html", // content type of the file
        false // set it to true to make the client download the file and not render it
   );
   return response.send();
});

zekageri avatar Mar 13 '25 19:03 zekageri

Hi @zekageri I will give that a try, thank you for your help so far.

designer-systems-ltd avatar Mar 17 '25 14:03 designer-systems-ltd

@zekageri started with just your example code but cannot get that to compile:

no instance of constructor "PsychicFileResponse::PsychicFileResponse" matches the argument listC/C++(289)

Does not like the 'res' object:

Image

designer-systems-ltd avatar Mar 17 '25 16:03 designer-systems-ltd

Are you on V2?

zekageri avatar Mar 17 '25 17:03 zekageri

V2 of what, latest version of PsychicWebserver is V1.2.1.

ESP packages:

PACKAGES:

  • framework-arduinoespressif32 @ 3.1.3
  • framework-arduinoespressif32-libs @ 5.3.0+sha.489d7a2b3a
  • tool-esptoolpy @ 4.8.6
  • tool-mklittlefs @ 3.2.0
  • tool-riscv32-esp-elf-gdb @ 14.2.0+20240403
  • tool-xtensa-esp-elf-gdb @ 14.2.0+20240403
  • toolchain-xtensa-esp-elf @ 13.2.0+20240530

designer-systems-ltd avatar Mar 17 '25 17:03 designer-systems-ltd

Sorry, there is a V2 branch which is not published. https://github.com/hoeken/PsychicHttp/tree/v2-dev

zekageri avatar Mar 17 '25 20:03 zekageri

I have cloned the v2-dev branch using https://github.com/hoeken/PsychicHttp.git#v2-dev and everything is now compiling and I am able to see a very basic indelx.html page, thank you for the help.

Also, tried the SSL and although there are a number of errors being returned at the moment its definately somthing to builld on.

designer-systems-ltd avatar Mar 21 '25 13:03 designer-systems-ltd

You can optimise it but it will be slow and the errors will not go away. :D i have tried optimising the hell out of it but eventually dropped the ssl thing

zekageri avatar Mar 21 '25 13:03 zekageri

Glad it works hovewer!

zekageri avatar Mar 21 '25 13:03 zekageri

I have added in the other file parser ie. css, js, jpg, xml etc. and most of the page is working now apart from the CSS stylesheet.

I am getting a few of the following errors on each page load:

[xxxx][E][PsychicResponse.cpp:114] send(): [psychic] Send response failed (ESP_ERR_HTTPD_RESP_SEND)

My load_file() process is modified from the original ESPAsyncWebserver and looks like this:

bool load_file(PsychicRequest *request, PsychicResponse *response)
{
	String dataType = "text/plain";
	String path = request->url();

	// Process file type requested and set data type
	if(path.endsWith("/")) path += "index.htm";
	if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
	else if(path.endsWith(".html")) dataType = "text/html";
	else if(path.endsWith(".htm")) dataType = "text/html";
	else if(path.endsWith(".css")) dataType = "text/css";
	else if(path.endsWith(".js")) dataType = "application/javascript";
	else if(path.endsWith(".png")) dataType = "image/png";
	else if(path.endsWith(".gif")) dataType = "image/gif";
	else if(path.endsWith(".jpg")) dataType = "image/jpeg";
	else if(path.endsWith(".ico")) dataType = "image/x-icon";
	else if(path.endsWith(".xml")) dataType = "text/xml";
	else if(path.endsWith(".pdf")) dataType = "application/pdf";
	else if(path.endsWith(".zip")) dataType = "application/zip";

	// Open file and transfer to server
	PsychicFileResponse response_send(
		response,
		SPIFFS,
		path,
		dataType,
		false
	);
	response_send.send();
	return true;
}

So not sure why the style sheet is not being used as the files are loading:

Image

designer-systems-ltd avatar Mar 21 '25 14:03 designer-systems-ltd

Loading the individual CSS files it looks like its the 'style.css' that is causing the error, I think because its being delivered to the page as 'chunked', whereas the other files just show a the content length.

designer-systems-ltd avatar Mar 21 '25 15:03 designer-systems-ltd

I'm on an early development of something that are currently using ESP32AsyncWebServer and as I also need SSL (primary for websocket), does it work really well ? I read some comment above and still have no idea if they're working stable

b4iterdev avatar Mar 25 '25 10:03 b4iterdev

It works up to a point. If you are serving small HTML files then it will work but very slowly and with lots of errors.

designer-systems-ltd avatar Mar 25 '25 11:03 designer-systems-ltd

Even with psram enabled, mbedtls needs internal ram for some things so the browser will repeat a couple of requests on each page load because the esp fails to allocate memory for the tls handshake process. Also it is slow to serve pages anyway, again because of the tls allocations.

zekageri avatar Mar 25 '25 11:03 zekageri

And it is not implementation or library problem. It's just too much for the esp to use it in prod. Ram is limited in both space and speed. If you manage to use the psram for most things, it is even slower especially if you use the flash meanwhile. Psram and flash shares the same spi bus so they slow each other down.

zekageri avatar Mar 25 '25 11:03 zekageri

In an internal network, even webservers written for a raspberry pi will use regular http.

zekageri avatar Mar 25 '25 11:03 zekageri

what if the esp does not have to serve site but only handing secure websocket, with esp32webserver I can archive that with quite low latency

b4iterdev avatar Mar 25 '25 11:03 b4iterdev

Wss is working. Iam doing that with the official esp websocket client implementation. As wss server, i dont know. In theory it would be more lightweight since it have to do the handshake only once on initial connection/client

zekageri avatar Mar 25 '25 12:03 zekageri

Also a dump question, in websocketHandler.onFrame, is there a way to not having return anything to the client at all ?

b4iterdev avatar Mar 25 '25 13:03 b4iterdev

Well, idk. I think it requires you to return an esp_err type. Don't remember the cb. Will check it.

zekageri avatar Mar 25 '25 17:03 zekageri

@designer-systems-ltd : (little off-topic): by the way, what use case do you have that really required to setup an SSL server certificate on a MCU, which will highly probably be self-signed and not recognised by any browser, and which will then prevent anyone from browsing ? Besides causing many issus (slowdown, memory and flash space, etc).

If this is to protect creds, client web UI could use a MCU public key to encrypt them, then pass them to the MCU which will be able to decrypt them with its private key. Could be done as JWT token.

mathieucarbou avatar Mar 25 '25 18:03 mathieucarbou

on my case specifically, I'm trying to develop a web application which is PWA that allow controlling robot with gamepad,... (a.k.a FtcRobotController but for ESP32). To make them "installable", it's required that the site must be served via https, which lead to websocket connection must also be secure. atm I have to make a workaround that to install public cert into device and trust it, but as long as I only need to do it once, it's worth the trade-off.

b4iterdev avatar Mar 26 '25 07:03 b4iterdev

Ok! You are in total control of who connects and with which device.

mathieucarbou avatar Mar 26 '25 07:03 mathieucarbou

on my case specifically, I'm trying to develop a web application which is PWA that allow controlling robot with gamepad,... (a.k.a FtcRobotController but for ESP32). To make them "installable", it's required that the site must be served via https, which lead to websocket connection must also be secure. atm I have to make a workaround that to install public cert into device and trust it, but as long as I only need to do it once, it's worth the trade-off.

I went to hell and back with this. You can't automate the cert install. I have tried a dozen different ways to make it understandable to the user and convinient but it's just not possible. Every possible platform and os implements it differently. It sucks. I also wanted to install PWA which the esp serves. It can work but really complicated for the user.

zekageri avatar Mar 26 '25 08:03 zekageri

Yes it's a pity that there is no easy way to automate those, I even tried to find a way for websocket client to "skip cert validation" but apparently there is none

b4iterdev avatar Mar 26 '25 08:03 b4iterdev

beside if you managed to use PWA, then I believe there's no point serving site via ESP32, just reduce huge load on esp and make the app as large as you want it to

b4iterdev avatar Mar 26 '25 08:03 b4iterdev