esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.01k stars 13.33k forks source link

server.send send unexpected argument migrating from 2.4.x to 2.5.2 #6435

Closed Sparatutto closed 2 years ago

Sparatutto commented 5 years ago

Basic Infos

Platform

Settings in IDE

attached picture setting-

Problem Description

I have updated the Arduino IDE to 1.8.9 and the core to 2.5.2 using the board manager ( not the git). Compiling my project that was working and running very stable with the core 2.4.x now I'm facing some issue related to the number of argument returned by the http communication. In particular I see an extra argument named plain received by the AP, that was not present and transferred before. So expected number of arguments (correct in the last compile with 2.4.x) in this example was 3, instead with the new core I get 4. extraarg

And this is making me crazy because I have many pages and not sure what is happening.

Maybe it is a stupid error of mine but having it in conjunction to the switch to this new core, I try to write you for a check. Thanks!

MCVE Sketch


#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>

#define BLUELED 02 

WiFiClient client;
ESP8266WebServer server(80);

void setup() 
{

    /*****************************/
    Serial.begin(115200);
    Serial.setDebugOutput(true);
    delay(10);

    Serial.println("Start! ....");

    Serial.println(F("Access point mode selected"));
    WiFi.mode(WIFI_AP);
    WiFi.softAPConfig(IPAddress(192,168,1,1),IPAddress(192,168,1,1),IPAddress(255,255,255,0));
    WiFi.softAP("MyAPN","12345678");
    Serial.println(F("Access point mode started"));
    IPAddress myIP = WiFi.softAPIP();
    Serial.print(F("AP IP address: "));
    Serial.print(myIP);
    Serial.println(F(" - PWD:12345678"));

    server.on("/", handleRoot);
    server.on("/setting",handleSetting);
    // Start the server
    server.begin(); //server.begin(sysSetting.httpPort);   //
}

void loop() 
{
    server.handleClient();
    digitalWrite(BLUELED,(digitalRead(BLUELED)?LOW:HIGH));
    delay(100);
    return;
}

/******************************************************************************
* Function: debugArgum
*
* Print to the serial the received arguments of the client/server http comm
*
* Parameters:                
*             header and argum set to 'y' means print to serial            
* Return:                 
*             none            
******************************************************************************/
void debugHeaderArgum(char header, char argu)
{
  String argum = "";
  int cnt;
  if(header =='y')
  {
    for (cnt = 0; cnt < server.headers(); cnt++) 
    {
      argum = "HeadArg: " +(String)cnt + " - " + server.headerName(cnt) + " - " + server.header(cnt);
      Serial.println(argum);
    }
  }
  if(argu =='y')
  {
    for (cnt = 0; cnt < server.args(); cnt++) 
    {
      argum = "Arg: " +(String)cnt + " - " + server.argName(cnt) + " - " + server.arg(cnt);
      Serial.println(argum);
    } 
  }
}

void handleRoot() 
{
    String argum = "";
    int cnt = 0;

    debugHeaderArgum('n','n'); //show header and argument

    Serial.println(F("APN - param page"));
    argum = F("HTTP/1.1 301 OK\r\nLocation: /setting\r\nCache-Control: no-cache\r\n\r\n");
    server.sendContent(argum);
    return;
}

/******************************************************************************
* Function: moduleInfo
*
* general module info usable in serial port and http.
*
* Parameters:                
*             httpmode: is true the {t] will be replaced with <DIV> and {-t} with </DIV> otherwise with \r\n             
* Return:                 
*             string containing the info            
******************************************************************************/
String moduleInfo(bool httpMode)
{
    byte mac[6];
    char tmpBuff[100];
    String retString = "\r\n{t}xxx Module: " +(String)ESP.getChipId() + "{-t}\r\n{t}Module ID: 10 - test {-t}\r\n";

    WiFi.macAddress(mac);
    sprintf(tmpBuff,"{t}MAC Address: %02X:%02X:%02X:%02X:%02X:%02X{-t}\r\n",mac[5],mac[4],mac[3],mac[2],mac[1],mac[0]);
    retString += (String)tmpBuff + "{t}Firmware version: x.x {-t}\r\n";

    // print the received signal strength:
    long rssi = WiFi.RSSI();
    retString += "{t}Signal strength (RSSI): " + (String)rssi + "dBm{-t}\r\n";

    uint32_t realSize = ESP.getFlashChipRealSize();
    uint32_t ideSize = ESP.getFlashChipSize();
    FlashMode_t ideMode = ESP.getFlashChipMode();
    sprintf(tmpBuff,"{t}Flash: Real size: %u - IDE Size: %u - IDE speed: %u{-t}\r\n", realSize, ideSize, ESP.getFlashChipSpeed());
    retString += (String)tmpBuff ;
    sprintf(tmpBuff,"{t}Flash IDE mode:  %s{-t}\r\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));
    retString += (String)tmpBuff ;
    if(httpMode)
    {
        retString.replace("{t}","<DIV>");
        retString.replace("{-t}","</DIV>");
    }
    else
    {
        retString.replace("{t}","");
        retString.replace("{-t}","");
    }
    return retString;   
}

/******************************************************************************
* Function: handleSetting
*
* Handle the connection to the configuration page used in APN and normal operation
*
* Parameters:                
*             none            
* Return:                 
*             none            
******************************************************************************/
void handleSetting()
{

    String decodeDst = "";
    server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server.sendHeader("Pragma", "no-cache");
    server.sendHeader("Expires", "-1");
    server.sendHeader("Host", "192.168.1.1");
    server.setContentLength(CONTENT_LENGTH_UNKNOWN);

    String webApn = F("<!DOCTYPE HTML>\r\n<html>\r\n<head>\r\n<title>Dommy</title>\r\n");                      
    webApn += F("<style type=\"text/css\">\r\n body {background: white; color: black; text-align: center} ");
    webApn += F(" form { color: blue; text-align: center}\r\n div {color: black; text-align: left}\r\n");
    webApn += F(" h1 { color: green; font: 36px Helvetica, Arial, sans-serif;}\r\n</style>\r\n</head>\r\n");

    debugHeaderArgum('n','y');

    if(server.args()== 3)
    {

        Serial.println(server.arg("ARG1"));

        Serial.println(server.arg("ARG2"));

        Serial.println(server.arg("ARG3"));

        ESP.wdtFeed(); // to ensure the wdt doesn't trigger
        webApn += F("<body><DIV></DIV><DIV>Module updated.</DIV>\r\n<DIV>It is restarting.</DIV>");
        webApn += "<DIV> <a href='http://www.xxxxxxx.yyy:8080'> Return to the main page </a> </DIV></body>\r\n</html>\r\n"; 
        //server.send(200, "text/html",webApn);
        server.send(200, "text/html", ""); 
        server.sendContent(webApn);
        server.sendContent("");
        delay(500);
        ESP.restart();
        return;
    }
    else if(server.args()> 3)
    {
        Serial.println("Wrong arg number!!");
    }
 // String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html Cache-Control: no-cache\r\n\r\n";
 //   server.sendContent(header);

  webApn += F("<body>\r\n<form name='Setting' method='POST'>\r\n");      
  webApn += F("<table width='60%' border='0' cellspacing='5' cellpadding='5'>\r\n");
  webApn += F("<tr><td width='10%' valign='center'><h1>xxx Module Config</h1></td></tr>\r\n");

  webApn += "<tr><td width='10%' valign='center'>" + moduleInfo(true) + "</td></tr></table>\r\n";
  webApn += F("<table width='60%' border='0' cellspacing='5' cellpadding='5'>\r\n"); 
  webApn += F("<tr><td valign='center'>ARG1</td></tr>\r\n");  
  webApn += F("<tr><td valign='center'><input type='text' name='ARG1' size='2' maxlength='2' value='1'></td></tr>\r\n");  
  webApn += F("<tr><td valign='center'> ARG2 (no space but '_')</td></tr>\r\n");
  webApn += F("<tr><td valign='center'> \r\n<input type='text' name='ARG2' size='20' maxlength='20' value='2'><br></td>\r\n</tr>\r\n");

  webApn += F("<tr>\r\n<td valign='center'>ARG3 - max 25\r\n</td>\r\n</tr>\r\n");
  webApn += F("<tr>\r\n<td valign='center'>\r\n<input type='text' name='ARG3' size='25' maxlength='25' value='test'><br></td>\r\n</tr>\r\n");

  webApn += F("<tr>\r\n<td valign='center'>\r\n<input type=submit value='Update'>\r\n</td>\r\n</tr>\r\n</table>\r\n</form>\r\n</body>\r\n</html>"); 
  server.send(200, "text/html",webApn);
}

Debug Messages

Debug messages go here
d-a-v commented 5 years ago

arg("plain") is the body. You can safely ignore it. It has been added to help solving a bug. The webserver logic has been rewritten (#5636) but is still wip and in the need for testing.

Sparatutto commented 5 years ago

Hi dav, thanks for the feedback. I see you are changing a lot and maybe for me at the moment is better to stay with core 2.4.2. By the way, I cannot ignore it, I have checks on the number and the names of the argument transferred to decide which server page must be loaded. I could remove the check on the number and check only the names. But unfortunately it seems to be not the only issue.

Another part of my code is transferring an argument composed by different part separated by a semicolon ";". In some manner any ";" is recognized as a different argument.

` bool manageClientUpdate(int module, int tmpZone, int btnCommand)

{

extern struct zone tmpServerZone[NUM_OF_ZONES];

char tmpBuffer[100];

int tmpPwd = random(2, 220); // 220 is the maximum because the password can be 30char max

sprintf(tmpBuffer, "&btnCmd=%01d&zcfg=%01d;%02d;%02d;%04d;%04d;%04d;%04d;%03d;%s;-", btnCommand, tmpZone, tmpServerZone[tmpZone].nonc, tmpServerZone[tmpZone].instantOnOff, tmpServerZone[tmpZone].timeOn_1 & (~USED_TODAY), tmpServerZone[tmpZone].timeOff_1 & (~USED_TODAY), tmpServerZone[tmpZone].timeOn_2 & (~USED_TODAY), tmpServerZone[tmpZone].timeOff_2 & (~USED_TODAY),tmpServerZone[tmpZone].monTimer,tmpServerZone[tmpZone].zoneName);
Serial.println("Module:" +(String)module + tmpBuffer);  

String webPage = "POST /cccc?"; //webPage = "POST /cccc?azyx=1&d=1&pippo=bene&pluto=male&paperino=1234 HTTP/1.1\r\n";

webPage+= "mid=" + (String)serverModules[module].moduleId + "&tmpp=100" + (String)tmpBuffer;

webPage += " HTTP/1.1\r\nHost: " +(String)serverModules[module].moduleIP + "\r\nCookie: TYPE=ttt;\r\nConnection: close\r\n\r\n";

client.print(webPage);
//Serial.print(webPage);
unsigned long timeout = millis();
while (client.available() == 0) 
{
  if (millis() - timeout > 5000) 
  {
    Serial.println(">>> Client Timeout !");
    client.stop();
    return false;
  }
} 
// Read all the lines of the reply from server and print them to Serial
String connResult =" ";
while(client.available())
{
  connResult+= client.readStringUntil('\n');
}
client.stop();
//Serial.print(connResult);
if(connResult.indexOf("HTTP/1.1 200 OK")>=0)
{
  Serial.println("\r\nClient updated");
  return true;
} 
else
  Serial.println("Client update failed");
//Serial.println("Server to client closed");   
return false;

}`

SO checking the returned arg I have one for any ";" and it is not correct. I hope the comment can help you.

devyte commented 4 years ago

@Sparatutto I don't understand why you can't just ignore plain. In your original post, please explain the expected output vs. the output that you get. Also, add hints to the code explaining why you can't ignore plain.

Sparatutto commented 4 years ago

Hi Devyte, yes for sure I can ignore the plain argument but it means change many of the written code so far. In the problem description you can see the picture of the current output. The expected output with the old core is ARG 0 to ARG 2 , ARG 3 is what I do not expect.

Regarding the code, I have conditional code based on the number of arguments and the content, maybe it is not the best way but it is what I have. Here below an example.

// if the read/detail button is pressed the server send the information of the selected module
  if((server.args() == 1) && (server.hasArg("Req")))
         {
                module=server.arg("Req").toInt();
                 logTime();
                 //Serial.printf("superclient: module %02d @%s:%s STATUS REQUEST ", module, serverModules[module].moduleIP,serverModules[module].modulePort);
                 Serial.printf("superclient: module %02d @%s:%d STATUS REQUEST ", module, serverModules[module].moduleIP,serverModules[module].modulePort);
                 receivedTime = manageServerToClient(module); //manageServerToClient(module, &zoneStatusClient);
                 //Serial.println("Time received from module:" + (String)receivedTime); 
                 if(receivedTime>=0)
                 {
                             addAns = true; 
                 }
            }

// if the send button of a zone is pressed the corresponding zone of the selected module is updated
            if((server.args() == 10) && (server.hasArg("Name")))
             {
                 module=server.arg("Name").toInt();
                 tmpZone = server.arg("zone").toInt();   
                 Serial.println("The module required is:" + server.arg("Name") + " ZOne: " + server.arg("zon") + " - " + (String)tmpZone);

                 tmpServerZone[tmpZone].instantOnOff = server.arg("in").toInt();
                 tmpServerZone[tmpZone].nonc = server.arg("mo").toInt();
                 if(tmpServerZone[tmpZone].instantOnOff != ZONE_INPUT)
                 {
                              tmpServerZone[tmpZone].timeOn_1=server.arg("TB").substring(0,server.arg("TB").indexOf(":")).toInt()*MINUT_CONVER+server.arg("TB").substring(server.arg("TB").indexOf(":")+1).toInt(); 
tmpServerZone[tmpZone].timeOff_1= server.arg("TE").substring(0,server.arg("TE").indexOf(":")).toInt()*MINUT_CONVER + server.arg("TE").substring(server.arg("TE").indexOf(":")+1).toInt();

tmpServerZone[tmpZone].timeOn_2 = ....

...
}
...
// Send the initial part of the HTML web page
  server.send(200, "text/html", ""); 
  server.sendContent(webPage);
  //this occours only at the first login or any time the list button is pressed
  if(server.args() == 0)
  {
...
}

thx.

d-a-v commented 4 years ago

@Sparatutto #6768 addresses your concern about arg("plain") which shouldn't be counted in the argument list.

About ; I'm afraid you'll have to escape it with %3B because it can be used as argument separator

These fixes may be available in core-2.6.1.

Sparatutto commented 2 years ago

Hello all, @d-a-v It seems you have fixed the issue in #6768 but i still see the issue: plain counted as argument. I'm using board lib 3.0.2. Am I doing some mistake ? Commented already in #6768 in August. Thanks for the feedback.

d-a-v commented 2 years ago

Commented already in #6768 in August.

You should have opened a new issue back then so it may not have been forgotten.

Am I doing some mistake ?

The first mistake I can see is to not open a new issue to track that down.

If I can't answer now, this is going to be forgotten. Please open a new issue.

d-a-v commented 2 years ago

Reopening

Sparatutto commented 2 years ago

Commented already in #6768 in August.

You should have opened a new issue back then so it may not have been forgotten.

Am I doing some mistake ?

~The first mistake I can see is to not open a new issue to track that down.~

~If I can't answer now, this is going to be forgotten. Please open a new issue.~

@d-a-v thanks. and sorry for my mistake