How data is passed in the .send methods of ESPAsyncWebServer when a query is made?

Hi there, how are you?.

I just followed this tutorial to make a web server on my ESP32 but I didn’t understand fully how data is passed to the callback on the send method on any query.

for example I have this piece of code

// Route to set GPIO to HIGH
  server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, HIGH);    
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

Trying to explain my doubts in other way here I go:

I know the send method in that “configuration” for seeing it in a manner asks for

  1. the file system to use
  2. the file to look for in the SPIFFS
  3. the String() method with an empty argument
  4. a false argument.
  5. the reference to the handler

now, the handler in this case tooks only one reference to a variable like seen in this piece of code

String processor(const String& var){
  Serial.println(var);
  if(var == "STATE"){
    if(digitalRead(ledPin)){
      ledState = "ON";
    }
    else{
      ledState = "OFF";
    }
    Serial.print(ledState);
    return ledState;
  }
  return String();
}

what I don’t know is from where the send method tooks the reference to the variable that it is going to pass to the handler. by using common sense I think that what happens is the following: once I press the button the content of the href property of the button is passed as the argument of the handler processor what I don’t know is how that is done, or also how to know the send method that the variable to look for in index.html is the placeholder %STATE%.

I think I’m missing something about javascript here but well, If any person could help me or point me to the right direction I’ll be grateful.

Thanks in advance for the help.

The entire code is open source, so you can transform “I don’t know” into “I will know when I’ll open the code”. With this, let’s follow the rabbit.

When you have code open in the IDE, you can follow any function call or class when holding Ctrl and clicking on the name. (On my laptop it seems to also be the Alt key though).

The send() function has multiple overloads taking different types of arguments, this one:

with the AwsTemplateProcessor being

aka a function taking const String& and returning String.

So to make

more precise,

  • the file system to use
  • the filename within the filesystem
  • the contentType, which, when an empty string is given, will try and autodetct the content type based on the path / file extension. Otherwise it will use the given string verbatim.
  • the next argument bool download doesn’t need to be false. If you want the file to trigger the “Download File” dialog of the webbrowser, you can set this to true. This is achieved by setting the Content-Disposition header to either inline or attachment.
  • the last argument is indeed a function reference / pointer to a “processor”; taking in a constant String reference and returning a String. As the documentation says
  • Placeholders are delimited with % symbols. Like this: %TEMPLATE_PLACEHOLDER%.
  • It works by extracting placeholder name from response text and passing it to user provided function which should return actual value to be used instead of placeholder.

Again following the function reveals how this works

When the code finds the paramter name in the template file it loaded (%PARAMETER NAME%), it calls the user provided callback with the name of the template parameter. Hence it can be a reference to a constant String (because why change the parameter name). The returned String is then used as the replacement for the encountered template parameter in the response.

This explanation started halfway already in the stack, but of course everything is triggered by a browser / web client sending a HTTP GET type request to the server via TCP, e.g.

GET /on HTTP/1.1
Host: 192.168.0.123
Connection: close

The data is then parsed by the library.

See HTTP - Requests.

2 Likes

Thank you for the masterclass @maxgerhardt, including for the help clarifying by telling me that send() is a function.

now, I’ve been able to follow almost all the code with your instructions but I’m unable to find where

size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len)

is called to analize the file in search for the placeholder, another thing that I’ve noted by testing the code because I wrote another placeholder to update 2 values in the web page is that the callback is called twice (one for each placeholder) which right now works for me.

Anyway thanks a lot for your help

See

And AsyncAbstractResponse::_ack() is called from

Called from

So that’s in the base-“send()” method taking the AsyncWebServerResponse* object created by beginResponse() referenced above.

Thanks again @maxgerhardt for your pricelles help to understand how the code works.