Problem with WiFiWebServer HTTP Requests Handling on Portenta Machine Control

Hello,

I am working on a use case which utilizes a WiFiWebServer HTTP server running on my Portenta Machine Control which exposes some APIs for use by a mobile application over a WiFi AP (which the app connects to)

One of the APIs ("/check_wifi_parameters") takes a POST request from the app containing a payload of a WiFi SSID and Password and verifies it and stores it for connecting to it later. The board also sends a 200 OK HTTP code to the app.

The POST request payload looks like this:

{"ssid":"SSID","password":"PASSWORD"}

The code uses the server.arg("plain") function to extract the above payload and converts it to a JSON for easier parsing.

However, on the Portenta Machine Control, the server.arg("plain") call returns blank. Cross-checking using the server.args() call also returns 0 indicating that either the payload is blank or the request wasn't parsed correctly.

This exact same code is working perfectly on an ESP32 running the ESP32WebServer library (of which this library is a port) and returns the above mentioned request payload through the server.arg("plain") call and 1 using the server.args() call.

I've also tested multiple possibilities of the request payload via Postman with the same results i.e. working correctly for the ESP32 but not for the Portenta Machine Control.

Would appreciate any help or suggestions about how to narrow this down to being either:
(1) a problem with the library OR
(2) a problem with my code on the Portenta Machine Control OR
(3) a problem with the incoming HTTP POST request that is somehow only happening on the Portenta Machine Control

Here is the code (I've used the AdvancedWebServer.ino example to create an MRE since I can't share the entire code due to confidentiality reasons)

#include "defines.h"

#define  MAX_REST_MESSAGE_SIZE 1450
#define HTTP_CODE_OK  200
#define HTTP_CODE_BAD_REQUEST 400

#define WIFI_CHECK_STATUS_NEED_TO_CHECK 0
#define WIFI_CHECK_STATUS_IN_PROGRESS 1
#define WIFI_CHECK_STATUS_SUCCESSFULLY 2
#define WIFI_CHECK_STATUS_FAILED 3

#define WIFI_AP_MODE 1
#define WIFI_CLIENT_MODE 2
#define TRY_CONNECT_TO_WIFI_TIMEOUT 5000 //5374 +/- 500 on real test

int check_wifi_status = WIFI_CHECK_STATUS_IN_PROGRESS;

bool _check_wifi = false;

String wifiSSIDToCheck;
String wifiPasswordToCheck;

int status = WL_IDLE_STATUS;     // the Wifi radio's status
int reqCount = 0;                // number of requests received

WiFiWebServer server(80);

#if defined(LED_BUILTIN)
  const int led =  LED_BUILTIN;
#else
  #if (ESP32)
    // Using pin 13 will crash ESP32_C3
    const int led =  2;
  #else
    const int led =  13;
  #endif
#endif

void SendJsonMessage(String json, int httpCode) {
    server.sendHeader(F("Access-Control-Allow-Origin"), F("*"));
    server.send(httpCode, "text/json", json);
}

void SendJsonStatus(int httpCode) {
    String status = httpCode == HTTP_CODE_OK ? "OK" : "Error";

    String json = String();
    json = "{";
    json += String("\"status\":\"") + status + "\"";
    json += "}";

    SendJsonMessage(json, httpCode);
}



bool IsWiFiConnectionSettingCorrect() {
    Serial.println("IsWiFiConnectionSettingCorrect() - start");

    unsigned long stopAt = millis() + TRY_CONNECT_TO_WIFI_TIMEOUT;

    WiFi.begin(wifiSSIDToCheck.c_str(), wifiPasswordToCheck.c_str());

    while ((WiFi.status() != WL_CONNECTED)) {
        delay(200);

        if (millis() > stopAt) {
            break;
        }
    }

    Serial.print("WiFi.status() == WL_CONNECTED: ");
    Serial.println((WiFi.status() == WL_CONNECTED));

    return (WiFi.status() == WL_CONNECTED);
}

void handleRoot()
{
#define BUFFER_SIZE     512

  digitalWrite(led, 1);
  char temp[BUFFER_SIZE];
  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;
  int day = hr / 24;

  hr = hr % 24;

  snprintf(temp, BUFFER_SIZE - 1,
           "<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>%s</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1>Hello from %s</h1>\
<h3>running WiFiWebServer</h3>\
<h3>on %s</h3>\
<p>Uptime: %d d %02d:%02d:%02d</p>\
<img src=\"/test.svg\" />\
</body>\
</html>", BOARD_NAME, BOARD_NAME, SHIELD_TYPE, day, hr, min % 60, sec % 60);

  server.send(200, F("text/html"), temp);
  digitalWrite(led, 0);
}

void handleNotFound()
{
  digitalWrite(led, 1);

  String message = F("File Not Found\n\n");

  message += F("URI: ");
  message += server.uri();
  message += F("\nMethod: ");
  message += (server.method() == HTTP_GET) ? F("GET") : F("POST");
  message += F("\nArguments: ");
  message += server.args();
  message += F("\n");

  for (uint8_t i = 0; i < server.args(); i++)
  {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }

  server.send(404, F("text/plain"), message);

  digitalWrite(led, 0);
}

void WiFiCheckStart_Handler() {
  Serial.println("WiFiCheckStart_Handler() - start");

    String postRequest = server.arg("plain");

    Serial.print("Arguments: ");
    Serial.println(server.args());

    Serial.print("Argument Name: ");
    Serial.println(server.argName(0));

    // Log the entire POST request
    Serial.print("POST Request:");
    Serial.println(postRequest);

    String msg = String("POST request to '/check_wifi_parameters': ") + postRequest;
    Serial.println(msg);
    Serial.flush();

    DynamicJsonBuffer jsonBuffer(MAX_REST_MESSAGE_SIZE);
    JsonObject &root = jsonBuffer.parseObject(postRequest);

    if (!root.success()) {

        SendJsonStatus(HTTP_CODE_BAD_REQUEST);

        return;
    }

    String ssid = root[F("ssid")];

    String password = root[F("password")];

    SendJsonStatus(HTTP_CODE_OK);

    wifiSSIDToCheck = ssid;
    wifiPasswordToCheck = password;

    // _check_wifi = true;
    // check_wifi_status = WIFI_CHECK_STATUS_IN_PROGRESS;
    // __startAt = millis() + TRY_CONNECT_TO_WIFI_TIMEOUT;

    // WiFi.begin(wifiSSIDToCheck.c_str(), wifiPasswordToCheck.c_str());

    check_wifi_status = WIFI_CHECK_STATUS_NEED_TO_CHECK;
}

void WiFiCheckStatus_Handler() {
  Serial.println("WiFiCheckStatus_Handler() - start");

    String msg = String("POST request to '/get_wifi_check_status'");
    Serial.println(msg);
    Serial.flush();

    String json = String();
    json = "{";

    // #define WIFI_CHECK_STATUS_NEED_TO_CHECK 0
    // #define WIFI_CHECK_STATUS_IN_PROGRESS 1
    // #define WIFI_CHECK_STATUS_SUCCESSFULLY 2
    // #define WIFI_CHECK_STATUS_FAILED 3
    json += String("\"check_wifi_status\":") + check_wifi_status;
    json += "}";

    msg = String("POST response: ") + json;
    Serial.println(msg);
    Serial.flush();

    SendJsonMessage(json, HTTP_CODE_OK);
}


void handle_WiFiPasswordValidator() {
  Serial.println("handle_WiFiPasswordValidator() - start");
  
    if (check_wifi_status == WIFI_CHECK_STATUS_NEED_TO_CHECK) {
        check_wifi_status = WIFI_CHECK_STATUS_IN_PROGRESS;

        if (IsWiFiConnectionSettingCorrect())
            check_wifi_status = WIFI_CHECK_STATUS_SUCCESSFULLY;
        else
            check_wifi_status = WIFI_CHECK_STATUS_FAILED;
    }
}


#define ORIGINAL_STR_LEN        (2048 * MULTIPLY_FACTOR)

//String out;

void drawGraph()
{
  static String out;
  static uint16_t previousStrLen = ORIGINAL_STR_LEN;

  if (out.length() == 0)
  {
    WS_LOGWARN1(F("String Len = 0, extend to"), ORIGINAL_STR_LEN);
    out.reserve(ORIGINAL_STR_LEN);
  }

#if (MULTIPLY_FACTOR == 1)

  out = F( "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"310\" height=\"150\">\n" \
           "<rect width=\"310\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"3\" stroke=\"rgb(0, 0, 0)\" />\n" \
           "<g stroke=\"blue\">\n");

#elif (MULTIPLY_FACTOR == 2)

  out = F( "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"610\" height=\"150\">\n" \
           "<rect width=\"610\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"3\" stroke=\"rgb(0, 0, 0)\" />\n" \
           "<g stroke=\"blue\">\n");

#elif (MULTIPLY_FACTOR == 4)

  out = F( "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1210\" height=\"150\">\n" \
           "<rect width=\"1210\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"3\" stroke=\"rgb(0, 0, 0)\" />\n" \
           "<g stroke=\"blue\">\n");

#endif

  char temp[70];

  int y = rand() % 130;

  for (int x = 10; x < (300 * MULTIPLY_FACTOR); x += 10)
  {
    int y2 = rand() % 130;
    sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"2\" />\n", x, 140 - y, x + 10, 140 - y2);
    out += temp;
    y = y2;
  }

  out += F("</g>\n</svg>\n");

  WS_LOGDEBUG1(F("String Len = "), out.length());

  if (out.length() > previousStrLen)
  {
    WS_LOGERROR3(F("String Len > "), previousStrLen, F(", extend to"), out.length() + 48);

    previousStrLen = out.length() + 48;

    out.reserve(previousStrLen);
  }
  else
  {
    server.send(200, "image/svg+xml", out);
  }
}



void WiFiScan_Handler() {

    int n = WiFi.scanNetworks();

    DynamicJsonBuffer jsonBuffer(MAX_REST_MESSAGE_SIZE);

    JsonObject &root = jsonBuffer.createObject();

    root[F("number_of_networks")] = n;

    JsonArray &networks = root.createNestedArray("networks");

    for (uint8_t i = 0; i < n; i++) {
        String name = WiFi.SSID(i);
        networks.add(name);
    }

    String json = String();
    json = "";
    root.printTo(json);

    SendJsonMessage(json, HTTP_CODE_OK);
}

void setup()
{
  //out.reserve(ORIGINAL_STR_LEN);

  pinMode(led, OUTPUT);
  digitalWrite(led, 0);

  Serial.begin(115200);

  while (!Serial && millis() < 5000);

  delay(200);

  Serial.print(F("\nStarting AdvancedWebServer on "));
  Serial.print(BOARD_NAME);
  Serial.print(F(" with "));
  Serial.println(SHIELD_TYPE);
  Serial.println(WIFI_WEBSERVER_VERSION);

#if WIFI_USING_ESP_AT

  // initialize serial for ESP module
  EspSerial.begin(115200);
  // initialize ESP module
  WiFi.init(&EspSerial);

  Serial.println(F("WiFi shield init done"));

#endif

#if ! (ESP32 || ESP8266)
  // check for the presence of the shield
#if USE_WIFI_NINA

  if (WiFi.status() == WL_NO_MODULE)
#else
  if (WiFi.status() == WL_NO_SHIELD)
#endif
  {
    Serial.println(F("WiFi shield not present"));

    // don't continue
    while (true);
  }

#endif

#if USE_WIFI_NINA
  String fv = WiFi.firmwareVersion();

  if (fv < WIFI_FIRMWARE_LATEST_VERSION)
  {
    Serial.println(F("Please upgrade the firmware"));
  }

#endif

#if (ESP32 || ESP8266)
  WiFi.mode(WIFI_STA);

  Serial.print(F("Connecting to WPA SSID: "));
  Serial.println(ssid);

  if (WiFi.status() != WL_CONNECTED)
  {
    if (strlen(pass) >= 8)
    {
      WiFi.begin(ssid, pass);
    }
    else
    {
      WiFi.begin(ssid);
    }
  }

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
  }

#else

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED)
  {
    //delay(500);
    Serial.print(F("Connecting to WPA SSID: "));
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

#endif

  server.on(F("/"), handleRoot);
  server.on(F("/test.svg"), drawGraph);
  server.on(F("/inline"), []()
  {
    server.send(200, F("text/plain"), F("This works as well"));
  });
  server.on(F("/get_wifi_scan_parameters"), HTTP_GET, WiFiScan_Handler);
  server.on(F("/check_wifi_parameters"), HTTP_POST, WiFiCheckStart_Handler);
  server.on(F("/get_wifi_check_status"), HTTP_GET, WiFiCheckStatus_Handler);

  server.onNotFound(handleNotFound);

  server.begin();

  Serial.print(F("HTTP server started @ "));
  Serial.println(WiFi.localIP());
}

void heartBeatPrint()
{
  static int num = 1;

  Serial.print(F("H"));

  if (num == 80)
  {
    Serial.println();
    num = 1;
  }
  else if (num++ % 10 == 0)
  {
    Serial.print(F(" "));
  }
}

void check_status()
{
  static unsigned long checkstatus_timeout = 0;

#define STATUS_CHECK_INTERVAL     60000L

  // Send status report every STATUS_REPORT_INTERVAL (60) seconds: we don't need to send updates frequently if there is no status change.
  if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0))
  {
    heartBeatPrint();
    checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL;
  }
}

void loop()
{
  server.handleClient();
  check_status();
  handle_WiFiPasswordValidator();
}