Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

website doesn't show up with core 2.4.2, neither 2.4.1 ... - but correctly with 2.3.0 and 2.4.0 though #5021

Closed
5 of 6 tasks
dsyleixa opened this issue Aug 9, 2018 · 36 comments
Assignees
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.
Milestone

Comments

@dsyleixa
Copy link

dsyleixa commented Aug 9, 2018

Basic Infos

  • This issue complies with the issue POLICY doc.
  • I have read the documentation at readthedocs and the issue is not addressed there.
  • I have tested that the issue is present in current master branch (aka latest git).
  • I have searched the issue tracker for a similar issue.
  • If there is a stack dump, I have decoded it.
  • I have filled out all fields below.

Platform

  • Hardware: [ESP-12E]
  • Core Version: [Board Manager 2.4.2]
  • Development Env: [Arduino IDE|]
  • Operating System: [Windows|

Settings in IDE

  • Module: [Nodemcu 1.0]
  • Flash Mode: [qio|dio|other]
  • Flash Size: [4MB]
  • lwip Variant: [v1.4|v2 Lower Memory|Higher Bandwidth]
  • Reset Method: [ck|nodemcu]
  • Flash Frequency: [40Mhz]
  • CPU Frequency: [80Mh
  • Upload Using: SERIAL]
  • Upload Speed: [115200|] (serial upload only)

Problem Description

the following function provides a website to login (username, password). It is called if the website url is loaded and a global variable "authorized" is still "false".
If login is correct, the global variable "authorized" is set to true, and the full website is displayed,
Admittedly surely not perfect, it actually works fine with core 2.3.0,
but now as I have changed to core 2.4.2 this website does not appear any more,
instead an error html website appears claiming the server is unreachable
("Error: Connection interrupted
The connection to the server was reset while the page was loading.")

Switching back to core 2.3.0 and recompiling, it's fine again.

What do I miss about the new core or the required new coding?

MCVE Sketch

// latest version: still faulty for 2.4.2, still fine with 2.4.0

void handleNotAuthorized() {
  String readString = "";
  char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;
  
  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // debug
  // authorized=true;

  strcpy(strinput, "");
  strcpy(strupwd, "");
  strcpy(struname, "");

  while ( client.connected() ) {
    if (authorized) return;

    if ( client.available() ) {
      char c = client.read();

      //read char by request
      readString = "";
      while ( (readString.length() < TOKLEN) && (c != '\n') ) {
          readString += c;
          c = client.read();
      }

    readString.toCharArray(strinput, MAXLEN);
    // cstringarg( char* haystack, char* vname, char* sarg )
    // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
    cstringarg(strinput, "uname", struname);  // uname
    cstringarg(strinput, "upwd", strupwd);   // upwd

    // debug
    Serial.print("strupwd     >>>"); Serial.print(strupwd); Serial.println("<<<");
    Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");
    Serial.print("readString>>>");Serial.println(readString);

    if ( (strlen(strupwd) == strlen(website_upwd)) && (strcmp(website_upwd, strupwd) == 0) )
    {
      authorized = true;
      //debug
      //Serial.print("check: authorized="); Serial.println(authorized);
      readString = "";
      return;
    }   
      
      //if HTTP request has ended
      if (c == '\n') {
         client.flush();  // <-- useless here, this empties the output buffer, not the input 

        //now output html data header
        String script = "";

        script += ("HTTP/1.1 401 Log-In Required");
        script += ("Content-Type: text/html \n");
        script += ("\n");  //  do not forget this one //????
        script += ("<!DOCTYPE html> \n");
        script += ("<html> \n");
        script += ("<head> \n");

        // utf-8 für "°" Zeichen
        script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
        script +=  "<title>" ;
        script +=  website_title ;
        script +=  "</title> \n" ;
        script +=  "</head> \n" ;
        script +=  "<body> \n" ;

        script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
        script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
        script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

        script += ("<FORM ACTION='/' method=GET > \n");
        script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
        script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

        script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

        script += ("</FORM> \n");
        script += ("<BR> \n");
        script += ("</body> \n");
        script += ("</html> \n");

        client.print(script);

        //stopping client
        client.stop();
        delay(1);
      }
    }
    delay(1);
  }
}

Debug Messages

 core 2.4.2 error: 
 this website does not appear any more at all, 
instead an error html website appears claiming the server is unreachable
("Error: Connection interrupted
The connection to the server was reset while the page was loading.")

Switching back to core 2.3.0 and recompiling, it's fine again.
@dsyleixa dsyleixa changed the title website doesn't show up with core 2.4.2, but correctly with 2.3.0 though website doesn't show up with core 2.4.2, neither 2.4.1 ... - but correctly with 2.3.0 and 2.4.0 though Aug 9, 2018
@dsyleixa
Copy link
Author

dsyleixa commented Aug 9, 2018

update:
core 2.4.1 works neither,
but nevertheless also 2.4.0 does work fine, like 2.3.0 before

@devyte
Copy link
Collaborator

devyte commented Aug 9, 2018

The sketch is incomplete:
-What is cstringarg?
-How are you doing the startup setup?
-how/when is this function handleNotAuthorized() called?

The requirement is for a Minimal Complete Verifiable Example MCVE sketch.

On a personal note: I don't understand why so many users insist on implementing their own webservers with WiFiServer. In this case, there is even an #include <ESP8266WebServer.h>, but then the webserver is not used.

@devyte devyte added the waiting for feedback Waiting on additional info. If it's not received, the issue may be closed. label Aug 9, 2018
@dsyleixa
Copy link
Author

dsyleixa commented Aug 10, 2018

I actually don't see how to do it all without both #include <ESP8266WiFi.h> and #include <ESP8266WebServer.h>.
cstringarg() works somehow like ESP8266WebServer.arg()
startup is done this way:

WiFiServer   wifiserver(http_port);
ESP8266WebServer lanserver(8081);

/* SNIP */
void setup() {
  Serial.println("Connecting to Router: ");
  Serial.println( WiFi.gatewayIP().toString() );

  WiFi.begin(ssid, password);
  WiFi.config(this_ip, gateway, subnet);   // feste IP

  while (WiFi.status() != WL_CONNECTED) {
 
    delay(500);
    Serial.print(".");

    display.clearDisplay();
    display.setCursor( 0, 20);  display.print("WiFi connecting...");
    drawHorizontalBargraph( 0, 30, (int16_t) display.width(), 9, 1, progress);
    display.setCursor( 0, 40);  display.print((String)progress + "%");
    if (progress >= 98) {
      progress = 80;
      Serial.println();
    }
    display.display();

    if (progress < 10) progress += 5;
    else if (progress < 50) progress += 2;
    else if (progress < 90) progress += 1;
  }
  display.clearDisplay();
  progress = 100;
  display.setCursor( 0, 20);  display.print("WiFi connecting...");
  drawHorizontalBargraph( 0, 30, (int16_t) display.width(), 9, 1, progress);
  display.setCursor( 0, 40);  display.print((String)progress + "%");
  display.display();
  delay(300);

  Serial.println("");
  Serial.print("WiFi connected: ");
  Serial.println(WiFi.gatewayIP());


  //----------------------------------------
  // Start the WiFi server (-> www)
  wifiserver.begin();
  Serial.println("WiFi Server started");

  //----------------------------------------
  // Start the ESP LAN server (-> ESP client)
  lanserver.on("/",handleRoot) ;
  lanserver.on("/client/client0/", handleClients);
  delay(10);
  lanserver.on("/client/client1/", handleClients);
  delay(10);
  lanserver.on("/client/client2/", handleClients);
  delay(10);
  lanserver.on("/client/client3/", handleClients);
  delay(10);
  lanserver.begin();
  Serial.println("ESP Server started");

  // Print the IP address
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.print(":");
  Serial.print(http_port);
  Serial.println("/");
  Serial.print((String)website_url + ":" + http_port + "/");


  //----------------------------------------
  // Start UDP
  Serial.println("Starting UdpTime");
  UdpTime.begin(localTimePort);
  Serial.print("Local Time port: ");
  Serial.println(UdpTime.localPort());
  Serial.println("waiting for sync");
  delay(250);
  setSyncProvider(getNtpTime);
  delay(100);

handleNotAuthorized() is called in loop():

  if (!authorized) {
    handleNotAuthorized();
    delay(100);    
  }
  if (authorized) {
    handleWebsite();
    delay(10);
  }
  lanserver.handleClient();

so here we go....

//----------------------------------------------------------------------------
//  board: ESP8266 NodeMCU 1.0 (ESP12-E module)
//  Arduino IDE 1.8.5
//  esp8266 core 2.4.0  
//----------------------------------------------------------------------------


// Wifi + website data 

extern const char* ssid ="";              // WIFI network name
extern const char* password ="";          // WIFI network password

// define 
char  website_uname[20] ="" ; //  website user name log in  "MyWebsiteLoginName"
char  website_upwd[20] ="";  //  website user pwd log in   "MyWebsiteLoginPwd"
char* website_title ="";     //  website caption           "MySiteCaption"
char* website_url ="";       //  website url               "http:\\mysite.com"



//----------------------------------------------------------------------------
// OLED SSD1306

#include <ESP_SSD1306.h>        // Modification of Adafruit_SSD1306 for ESP8266 compatibility
#include <Adafruit_GFX.h>       // Needs a little change in original Adafruit library (See README.txt file)
#include <Fonts/FreeSansBold12pt7b.h>        // 
#include <Fonts/FreeSans9pt7b.h>            //
//#include <Fonts/FreeMono12pt7b.h>          //

// i2c Wire
#include <Wire.h>

#define SCL         D1      // SCL
#define SDA         D2      // SDA    

#define D12         10      // GPIO intern  
#define OLED_RESET  10      // GPIO10=D12 Pin RESET signal  

ESP_SSD1306    display(OLED_RESET);



//----------------------------------------------------------------------------
// IO pins  
//----------------------------------------------------------------------------

#define PIN_BTND3   D3      // Btn 0=D3 reset Alarm
// #define PIN_IN4     D4      //  N/A
 
#define PIN_OUT1    D5      //  out 
#define PIN_OUT2    D7      //  out
// #define PIN_OUT3    D8      //  N/A



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


#define  ORANGE       255,102,0


// WiFi Router

#define     this_iph     200      // <<< local host ip  
#define     http_port     80


IPAddress    this_ip(192, 168, 2, this_iph); // <<< Feste lokale IP dieses ESP8266-Servers
IPAddress    gateway(192, 168, 2, 1);       // <<< LAN Gateway IP
IPAddress    subnet(255, 255, 255, 0);      // <<< LAN Subnet Mask

WiFiServer   wifiserver(http_port);

ESP8266WebServer lanserver(8081);

bool      authorized = false;




//----------------------------------------------------------------------------
// Tools


//----------------------------------------------------------------------------

int16_t  strstrpos(char * haystack,  char * needle)   // find 1st occurance of substr in str
{
   char *p = strstr(haystack, needle);
   if (p) return p - haystack;
   return -1;   // Not found = -1.
}

//----------------------------------------------------------------------------
const int  MAXLEN = 1024;
const int  TOKLEN = 64;

char * cstringarg( char* haystack, char* vname, char* sarg ) {  // <~~~~~~~ updated version
   int i=0, pos=-1;
   unsigned char  ch=0xff;
   char  kini[3] = "&";       // start of varname: '&': 
   char  kequ[3] = "=";       // end of varname, start of argument: '='
   char  needle[TOKLEN]="";   // complete pattern:  &varname=abc1234

   strcpy(sarg,"");
   strcpy(needle, kini);
   strcat(needle, vname);
   strcat(needle, kequ);
   pos = strstrpos(haystack, needle); 
   if(pos==-1) {
      needle[0]='?';
      pos = strstrpos(haystack, needle);
      if(pos==-1) return sarg;
   }
   pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ   
   while( (ch!='&')&&(ch!='\0') ) {
      ch=haystack[pos+i];    
      if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
        ||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
           sarg[i]='\0';
           return sarg;
      }       
      if( (ch!='&') ) {
          sarg[i]=ch;          
          i++;       
      }      
   } 
   return sarg;
}


//----------------------------------------------------------------------------
// OLED dashboard
//----------------------------------------------------------------------------
void dashboard(int mode) {  
  display.clearDisplay();

  if (mode >= 0) {
    display.setCursor( 0, 0);   
    display.print(this_ip);
    display.setCursor (0, 16);       
    display.print(gateway);
    display.display();

    
  }   
  
  display.setFont();
}


//----------------------------------------------------------------------------
// SETUP
//----------------------------------------------------------------------------


void setup() {

  int IORes;

  //STR_DEGREE[0] = CHR_DEGREE; // ° symbol as ANSI C string

  int progress = 0;


  //----------------------------------------
  Serial.begin(115200);
  delay(1000);





  //----------------------------------------
  // i2c: init

  Wire.pins(SDA, SCL);        // SDA, SCL
  Wire.begin();
  delay(1);

 
  //----------------------------------------
  // OLED

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)

  display.setFont();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.clearDisplay();
  display.setCursor( 0, 0);  display.print("OLED TEST OK");
  display.display();
  delay(1);
  Serial.println("OLED sensor init...");
 

  //----------------------------------------
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.println("Connecting to Router: ");
  Serial.println( WiFi.gatewayIP().toString() );

  WiFi.begin(ssid, password);
  WiFi.config(this_ip, gateway, subnet);   // feste IP

  while (WiFi.status() != WL_CONNECTED) {
 
    delay(500);
    Serial.print(".");

    display.clearDisplay();
    display.setCursor( 0, 20);  display.print("WiFi connecting...");

    display.setCursor( 0, 40);  display.print((String)progress + "%");
    if (progress >= 98) {
      progress = 80;
      Serial.println();
    }
    display.display();

    if (progress < 10) progress += 5;
    else if (progress < 50) progress += 2;
    else if (progress < 90) progress += 1;
  }
  display.clearDisplay();
  progress = 100;
  display.setCursor( 0, 20);  display.print("WiFi connecting...");
  display.setCursor( 0, 40);  display.print((String)progress + "%");
  display.display();
  delay(300);

  Serial.println("");
  Serial.print("WiFi connected: ");
  Serial.println(WiFi.gatewayIP());


  //----------------------------------------
  // Start the WiFi server (-> www)
  wifiserver.begin();
  Serial.println("WiFi Server started");

  //----------------------------------------
  // Start the ESP LAN server (-> ESP client)
  lanserver.on("/",handleRoot) ;
  lanserver.on("/client/client0/", handleClients);
  delay(10);
  lanserver.on("/client/client1/", handleClients);
  delay(10);
  lanserver.on("/client/client2/", handleClients);
  delay(10);
  lanserver.on("/client/client3/", handleClients);
  delay(10);
  lanserver.begin();
  Serial.println("ESP Server started");

  // Print the IP address
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.print(":");
  Serial.print(http_port);
  Serial.println("/");
  Serial.print((String)website_url + ":" + http_port + "/");

  delay(1);

 

  //----------------------------------------
  // setup done

  dashboard(1);
  Serial.println("setup done \n");

}



//----------------------------------------------------------------------------
// LOOP
//----------------------------------------------------------------------------

void loop() {

  static double ftmp;
  static unsigned long tsec=millis(), tms = millis();
  static int8_t  LEDmode=0;
 

    
  //---------------------------------------
  // Check log-in
 
   if (!authorized) {
    handleNotAuthorized();
    delay(100);    
  }

  if (authorized) {
    handleWebsite();
    delay(10);
  }

  lanserver.handleClient();
  delay(10);


  
  //---------------------------------------
  // Read local + Udp data  
  if ( millis() - tms >= 100 ) {    // refresh data rate
    tms = millis();   

    
    //---------------------------------------
    // display on OLED
    if ( millis() - tsec >= 4000 ) {
      tsec=millis();
      LEDmode++;
      if(LEDmode>8) LEDmode=0;
    }
    dashboard(LEDmode);
    delay(1);
  }


}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

// Moppi's Fix
void handleNotAuthorized() {
  String readString = "";
  char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;
  
  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // debug
  // authorized=true;

  strcpy(strinput, "");
  strcpy(strupwd, "");
  strcpy(struname, "");

  while ( client.connected() ) {
    if (authorized) return;

    if ( client.available() ) {
      char c = client.read();

      //read char by request
      readString = "";
      while ( (readString.length() < TOKLEN) && (c != '\n') ) {
          readString += c;
          c = client.read();
      }

    readString.toCharArray(strinput, MAXLEN);
    // cstringarg( char* haystack, char* vname, char* sarg )
    // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE 
    cstringarg(strinput, "uname", struname);  // uname
    cstringarg(strinput, "upwd", strupwd);   // upwd

    // debug
    Serial.print("strupwd     >>>"); Serial.print(strupwd); Serial.println("<<<");
    Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");
    Serial.print("readString>>>");Serial.println(readString);

    if ( (strlen(strupwd) == strlen(website_upwd)) && (strcmp(website_upwd, strupwd) == 0) )
    {
      authorized = true;
      //debug
      //Serial.print("check: authorized="); Serial.println(authorized);
      readString = "";
      return;
    }   
      
      //if HTTP request has ended
      if (c == '\n') {
         client.flush();  // <-- useless here, this empties the output buffer, not the input 

        //now output html data header
        String script = "";

        script += ("HTTP/1.1 401 Log-In Required");
        script += ("Content-Type: text/html \n");
        script += ("\n");  //  do not forget this one //????
        script += ("<!DOCTYPE html> \n");
        script += ("<html> \n");
        script += ("<head> \n");

        // utf-8 für "°" Zeichen
        script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
        script +=  "<title>" ;
        script +=  website_title ;
        script +=  "</title> \n" ;
        script +=  "</head> \n" ;
        script +=  "<body> \n" ;

        script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
        script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
        script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

        script += ("<FORM ACTION='/' method=GET > \n");
        script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
        script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

        script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

        script += ("</FORM> \n");
        script += ("<BR> \n");
        script += ("</body> \n");
        script += ("</html> \n");

        client.print(script);

        //stopping client
        client.stop();
        delay(1);
      }
    }
    delay(1);
  }
}

//----------------------------------------------------------------------------

void handleWebsite() {

  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // Check if a client has connected


  // Read the first line of the request
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();



  //---------------------------------------
  // LogOut
  if (request.indexOf("/logout") != -1)  {
    authorized = false;
    return;
  }


  delay(1);

  //---------------------------------------
  // Return the response

  String script = "";

  // init website

  script += ("HTTP/1.1 200 OK \n");
  script += ("Content-Type: text/html \n");
  script += ("\n"); //  do not forget this one
  script += ("<!DOCTYPE html> \n");
  script += ("<html> \n");

  // head + title
  script += ("<head> \n");
  // autom. Aktualisierung alle 20 sec.

  script += "<meta http-equiv=\"refresh\" content=\"20; URL=";
  script += (String)website_url + ":" + (String)http_port + "\"> \n" ;


  // utf-8 für "°" Zeichen
  script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
  script += ("<title>");
  script += (website_title);
  script += ("</title> \n");
  script += ("</head> \n");

  // body + caption
  script += ("<body> \n");
  script += ("<h1> <p> ");
  script += ("<font style=\"color:rgb(255,0,204);\"> HELLO WORLD! ");
  script += ("&nbsp; <wbr> <wbr> ");
  script += ("<font style=\"color:rgb(0,205,102);\"> Welcome to " + (String)website_url );
  script += ("! </p> </h1>  "); // script+= ("! </p> </h1> \n");

  
  delay(1);

  
  //---------------------------------------
  script +=  "<h2> <br> \n  HEIMSERVER  <br> \n </h2>";
  //---------------------------------------
  // remote buttons Server
  // <input type="button" value="submit" style="height: 100px; width: 100px; left: 250; top: 250;">
  // <button style=\"height:200px;width:200px\"> </button>

 
  
  client.print(script);
  script = "";


  //---------------------------------------
  // sensors  Server
  // chart table
  //---------------------------------------
  // text font Courier, color black
  script += ("<p> <font face=\"courier\"> "); // <<< Courier
  script += "<h2> ";
  script += "<p style=\"color:rgb(0,0,0);\" > </p>  " ;
  script += ("<br> \n");  
  script += "</h2>";

  client.print(script);
  script = "";


  script += ("<br> \n");


  // log out
  script += ("<h3>Log Out: ");
  script += ("<a href=\" /logout\"\"> <button style=\"height:70px;width:140px\" > Log Out </button></a> </h3> ");

  script += WiFi.localIP().toString() +" "+ (String)ssid + " <br>" ;
  script += "</font> </p> \n";

  script += "</body> \n";
  script += "</html> \n";

  client.print(script);

  delay(1);

}

//----------------------------------------------------------------------------
// handle root +clients
//----------------------------------------------------------------------------

void handleRoot() {
   handleClients();
}


//----------------------------------------------------------------------------

void handleClients() {
  double ftmp;
  String msgtok;

 
 
  //------------------------------------------

  //client-Werte auch bei Url-Aufruf zurückgeben
 
  String message = "*** ";
  // re CLIENT 0
  /*
  message += (String)"&c0t1=" + c0t1.sact + "&c0h1=" + c0h1.sact;
  message += (String)"&c0t2=" + c0t2.sact + "&c0h2=" + c0h2.sact;
  message += "&c0out1=" + (String)c0out1 + "&c0out2=" + (String)c0out2 + "&c0out3=" + (String)c0out3 ;
  */
  message += " ###";
  //Serial.println(message);
  lanserver.send(200, "text/plain", message);

}



// END OF FILE
 

@dsyleixa dsyleixa reopened this Aug 10, 2018
@devyte
Copy link
Collaborator

devyte commented Aug 10, 2018

@dsyleixa your first sketch did not comply with the "C" in MCVE. The last one does not comply with the "M".
It is unlikely that any maintainer will look at either of them. Please post a Minimal Complete Verifiable Example sketch. To be explicit, take your sketch and strip it down to as tiny a piece of code as you can that can still reproduce the issue you're reporting and that still runs.

@dsyleixa
Copy link
Author

dsyleixa commented Aug 10, 2018

I reported that issue just to let you know about a bug in those cores/libs.
it compiles and runs fine with 2.4.0 and 2.3.0, just copy and paste.
so it must be a 2.4.1 and/or 2.4.2 bug.
Developers can strip that down far better than I am able to, because they have far more skills to focus on the really suspicious parts or interferences or side effects.

@devyte
Copy link
Collaborator

devyte commented Aug 10, 2018

@dsyleixa there are currently 3 active developers, and there are 455 open issues and 134 pending PRs at the time of this writing. Expecting a developer to handle your code is not realistic.
I will remind you that the developers are volunteers who work on this core as a hobby during our free time, and that this repo is a community effort and not a service provided to users. You are therefore expected to do your homework with regard to issues that affect you, the best case of which is an issue you report that is accompanied by a PR that fixes it.

I am not convinced that the problem you see is really in the core, which is one of the reasons behind the requirement of an MCVE sketch. It is very common that a user thinks it's the core, then while reducing the sketch the issue can no longer be reproduced, which then leads to finding a bug in the user's own code or a 3rd party lib.

@dsyleixa
Copy link
Author

dsyleixa commented Aug 11, 2018

ok, I didn't suppose it to be so complicated for a developer to see through this issue already at the 1st glance. I'll see if I can strip it down and report then, until then I'll try to stay with the 2.4.0 core.

(edit, it's already a whole lot smaller now)

@devyte
Copy link
Collaborator

devyte commented Aug 14, 2018

Not complicated, just very very time consuming. A reduction and reproduction of a reported bug can easily take upwards of an hour. Multiply times a whole lot of issues, and there aren't enough hours in a day, let alone our free time each day, to look at all the reported issues. The issue count is now up from 455 in my previous comment to 463 now, and that's after I closed some.

I still see the original sketch as incomplete, and the second sketch as huge. As a guideline, the size of the code in your original post is manageable. It's just not complete, as in I can't copy-paste it into an IDE, flash it, and see the bug.

@Scippi
Copy link

Scippi commented Aug 17, 2018

Hello,

i've had the same behaviour.
It seem's that the client.stop() has been changed.

With Server example from https://arduino-esp8266.readthedocs.io/en/2.4.2/esp8266wifi/server-examples.html it is reproducible:

#include <ESP8266WiFi.h>

const char* ssid = "********";
const char* password = "********";


WiFiServer server(80);


void setup()
{
  Serial.begin(115200);
  Serial.println();

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");

  server.begin();
  Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}

// prepare a web page to be send to a client (web browser)
String prepareHtmlPage()
{
  String htmlPage =
     String("HTTP/1.1 200 OK\r\n") +
            "Content-Type: text/html\r\n" +
            "Connection: close\r\n" +  // the connection will be closed after completion of the response
            "Refresh: 5\r\n" +  // refresh the page automatically every 5 sec
            "\r\n" +
            "<!DOCTYPE HTML>" +
            "<html>" +
            "Analog input:  " + String(analogRead(A0)) +
            "</html>" +
            "\r\n";
  return htmlPage;
}


void loop()
{
  WiFiClient client = server.available();
  // wait for a client (web browser) to connect
  if (client)
  {
    Serial.println("\n[Client connected]");
    while (client.connected())
    {
      // read line by line what the client (web browser) is requesting
      if (client.available())
      {
        String line = client.readStringUntil('\r');
        Serial.print(line);
        // wait for end of client's request, that is marked with an empty line
        if (line.length() == 1 && line[0] == '\n')
        {
          client.println(prepareHtmlPage());
          break;
        }
      }
    }
    delay(1); // give the web browser time to receive the data

    // close the connection:
    client.stop();
    Serial.println("[Client disonnected]");
  }
}

This example procudes: Failed to load resource: net::ERR_CONNECTION_RESET in Chrome
Within Edge/IExplorer : INET_E_DOWNLOAD_FAILURE

If i remove the last client.stop(), the example work as expected.

@dsyleixa
Copy link
Author

dsyleixa commented Aug 17, 2018

@ Scippi : for core 2.4.2 I removed the last client.stop() in void handleNotAuthorized() but still the same error message

Fehler: Verbindung unterbrochen
Die Verbindung zum Server wurde zurückgesetzt, während die Seite geladen wurde.

still everything works like a charm with 2.4.0. though, just like before.
(edit: complete source code meanwhile stripped down even more)

@TheNitek
Copy link
Contributor

I can confirm that client.stop(); seems to break things in 2.4.2.

@dsyleixa
Copy link
Author

dsyleixa commented Aug 18, 2018

again code stripped down a lot - now it's almost the absolute minimum code IMO.
(see above)
#5021 (comment)

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 18, 2018

Tnhkas for the effrots put in the MVCE !

@d-a-v d-a-v self-assigned this Aug 18, 2018
@dsyleixa
Copy link
Author

a pleasure! 8-)

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 18, 2018

Bug reproduced. Working with 2.4.0, not with 2.4.2.

simplified MCVE (dhcp mode, no i2c screen)

Tnhkas, now we can wrok :)

//----------------------------------------------------------------------------
//  board: ESP8266 NodeMCU 1.0 (ESP12-E module)
//  Arduino IDE 1.8.5
//  esp8266 core 2.4.0
//----------------------------------------------------------------------------


// Wifi + website data

const char* ssid = "SSID";             // WIFI network name
const char* password = "PSK";         // WIFI network password

// define
char  website_uname[20] = "xx" ; //  website user name log in  "MyWebsiteLoginName"
char  website_upwd[20] = "yy"; //  website user pwd log in   "MyWebsiteLoginPwd"
const char* website_title = "#5021";    //  website caption           "MySiteCaption"
const char* website_url = "http://givemeluck";      //  website url               "http:\\mysite.com"
int http_port = 80;

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

WiFiServer   wifiserver(http_port);
ESP8266WebServer lanserver(8081);
bool      authorized = false;

//----------------------------------------------------------------------------
// handle root +clients
//----------------------------------------------------------------------------

void handleRoot() {
  handleClients();
}


//----------------------------------------------------------------------------

void handleClients() {
  String msgtok;
  //------------------------------------------

  //client-Werte auch bei Url-Aufruf zurückgeben

  String message = "*** ";
  // re CLIENT 0
  /*
    message += (String)"&c0t1=" + c0t1.sact + "&c0h1=" + c0h1.sact;
    message += (String)"&c0t2=" + c0t2.sact + "&c0h2=" + c0h2.sact;
    message += "&c0out1=" + (String)c0out1 + "&c0out2=" + (String)c0out2 + "&c0out3=" + (String)c0out3 ;
  */
  message += " ###";
  //Serial.println(message);
  lanserver.send(200, "text/plain", message);

}

//----------------------------------------------------------------------------
// Tools
//----------------------------------------------------------------------------

int16_t  strstrpos(char * haystack,  char * needle)   // find 1st occurance of substr in str
{
  char *p = strstr(haystack, needle);
  if (p) return p - haystack;
  return -1;   // Not found = -1.
}

//----------------------------------------------------------------------------
const int  MAXLEN = 1024;
const int  TOKLEN = 64;

char * cstringarg( char* haystack, char* vname, char* sarg ) {
  int i = 0, pos = -1;
  unsigned char  ch = 0xff;
  char  kini[3] = "&";       // start of varname: '&':
  char  kequ[3] = "=";       // end of varname, start of argument: '='
  char  needle[TOKLEN] = ""; // complete pattern:  &varname=abc1234

  //kequ[0] = '=';  // customize
  strcpy(sarg, "");
  strcpy(needle, kini);
  strcat(needle, vname);
  strcat(needle, kequ);
  pos = strstrpos(haystack, needle);
  if (pos == -1) return sarg;
  pos = pos + strlen(vname) + 2; // start of value = kini+vname+kequ
  while ( (ch != '&') && (ch != '\0') ) {
    ch = haystack[pos + i];
    if ( (ch == '&') || (ch == ';') || (ch == ' ') || (ch == '\0') || (ch == '\n')
         || (i + pos >= strlen(haystack)) || (i > TOKLEN - 1) ) {
      sarg[i] = '\0';
      return sarg;
    }
    if ( (ch != '&') ) {
      sarg[i] = ch;
      i++;
    }
  }
  return sarg;
}


//----------------------------------------------------------------------------
// SETUP
//----------------------------------------------------------------------------


void setup() {

  //STR_DEGREE[0] = CHR_DEGREE; // ° symbol as ANSI C string


  //----------------------------------------
  Serial.begin(115200);
  delay(1000);

  //----------------------------------------
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.println("Connecting to Router: ");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected: ");
  Serial.println(WiFi.gatewayIP());


  //----------------------------------------
  // Start the WiFi server (-> www)
  wifiserver.begin();
  Serial.println("WiFi Server started");

  //----------------------------------------
  // Start the ESP LAN server (-> ESP client)
  lanserver.on("/", handleRoot) ;
  lanserver.on("/client/client0/", handleClients);
  delay(10);
  lanserver.on("/client/client1/", handleClients);
  delay(10);
  lanserver.on("/client/client2/", handleClients);
  delay(10);
  lanserver.on("/client/client3/", handleClients);
  delay(10);
  lanserver.begin();
  Serial.println("ESP Server started");

  // Print the IP address
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.print(":");
  Serial.print(http_port);
  Serial.println("/");
  Serial.print((String)website_url + ":" + http_port + "/");

  delay(1);

  //----------------------------------------
  // setup done
  Serial.println("setup done \n");
}

//----------------------------------------------------------------------------
// LOOP
//----------------------------------------------------------------------------

void loop() {

  //---------------------------------------
  // Check log-in

  if (!authorized) {
    handleNotAuthorized();
    delay(100);
  }

  if (authorized) {
    handleWebsite();
    delay(10);
  }

  lanserver.handleClient();
  delay(10);
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

void handleNotAuthorized() {
  String readString = "";
  char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // debug
  // authorized=true;

  strcpy(strinput, "");
  strcpy(strupwd, "");
  strcpy(struname, "");

  while ( client.connected() ) {
    if (authorized) return;


    readString.toCharArray(strinput, MAXLEN);
    // cstringarg( char* haystack, char* vname, char* sarg )
    // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
    cstringarg(strinput, "uname", struname);  // uname
    cstringarg(strinput, "upwd", strupwd);   // upwd

    // debug
    Serial.print("strupwd     >>>"); Serial.print(strupwd); Serial.println("<<<");
    Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");


    if ( (strlen(strupwd) == strlen(website_upwd) )
         && (strcmp(website_upwd, strupwd ) == 0)
       )
    {
      authorized = true;
      //debug
      //Serial.print("check: authorized="); Serial.println(authorized);
      readString = "";
      return;
    }

    if ( client.available() ) {
      char c = client.read();

      //read char by request
      if (readString.length() < TOKLEN) {

        //store characters to string
        readString += c;
        Serial.println(c);
      }

      //if HTTP request has ended
      if (c == '\n') {
        client.flush();


        //now output html data header

        String script = "";

        script += ("HTTP/1.1 401 Log-In Required");
        script += ("Content-Type: text/html \n");
        script += ("\n");  //  do not forget this one //????
        script += ("<!DOCTYPE html> \n");
        script += ("<html> \n");
        script += ("<head> \n");


        // utf-8 für "°" Zeichen
        script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
        script +=  "<title>" ;
        script +=  website_title ;
        script +=  "</title> \n" ;
        script +=  "</head> \n" ;
        script +=  "<body> \n" ;

        script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
        script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
        script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

        script += ("<FORM ACTION='/' method=GET > \n");
        script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
        script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

        script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

        script += ("</FORM> \n");
        script += ("<BR> \n");
        script += ("</body> \n");
        script += ("</html> \n");

        client.print(script);

        //stopping client
        client.stop();

        delay(1);

        //clearing string for next read
        readString = "";
      }
    }
    delay(1);
  }
}


//----------------------------------------------------------------------------

void handleWebsite() {

  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // Check if a client has connected


  // Read the first line of the request
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();

  //---------------------------------------
  // LogOut
  if (request.indexOf("/logout") != -1)  {
    authorized = false;
    return;
  }
  
  delay(1);

  //---------------------------------------
  // Return the response

  String script = "";

  // init website

  script += ("HTTP/1.1 200 OK \n");
  script += ("Content-Type: text/html \n");
  script += ("\n"); //  do not forget this one
  script += ("<!DOCTYPE html> \n");
  script += ("<html> \n");

  // head + title
  script += ("<head> \n");
  // autom. Aktualisierung alle 20 sec.

  script += "<meta http-equiv=\"refresh\" content=\"20; URL=";
  script += (String)website_url + ":" + (String)http_port + "\"> \n" ;


  // utf-8 für "°" Zeichen
  script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
  script += ("<title>");
  script += (website_title);
  script += ("</title> \n");
  script += ("</head> \n");

  // body + caption
  script += ("<body> \n");
  script += ("<h1> <p> ");
  script += ("<font style=\"color:rgb(255,0,204);\"> HELLO WORLD! ");
  script += ("&nbsp; <wbr> <wbr> ");
  script += ("<font style=\"color:rgb(0,205,102);\"> Welcome to " + (String)website_url );
  script += ("! </p> </h1>  "); // script+= ("! </p> </h1> \n");


  delay(1);


  //---------------------------------------
  script +=  "<h2> <br> \n  HEIMSERVER  <br> \n </h2>";
  //---------------------------------------
  // remote buttons Server
  // <input type="button" value="submit" style="height: 100px; width: 100px; left: 250; top: 250;">
  // <button style=\"height:200px;width:200px\"> </button>



  client.print(script);
  script = "";


  //---------------------------------------
  // sensors  Server
  // chart table
  //---------------------------------------
  // text font Courier, color black
  script += ("<p> <font face=\"courier\"> "); // <<< Courier
  script += "<h2> ";
  script += "<p style=\"color:rgb(0,0,0);\" > </p>  " ;
  script += ("<br> \n");
  script += "</h2>";

  client.print(script);
  script = "";


  script += ("<br> \n");


  // log out
  script += ("<h3>Log Out: ");
  script += ("<a href=\" /logout\"\"> <button style=\"height:70px;width:140px\" > Log Out </button></a> </h3> ");

  script += WiFi.localIP().toString() + " " + (String)ssid + " <br>" ;
  script += "</font> </p> \n";

  script += "</body> \n";
  script += "</html> \n";

  client.print(script);

  delay(1);

}

@dsyleixa
Copy link
Author

re: "Tnhkas, now we can wrok :)"
gaain, a leapsure, gald I colud phel :P

@dsyleixa
Copy link
Author

dsyleixa commented Aug 19, 2018

new cstringarg version, accepting also
'?varname='
besides
'&varname='
as to 'needles' in the 'haystack':

char * cstringarg( char* haystack, char* vname, char* sarg ) {
   int i=0, pos=-1;
   unsigned char  ch=0xff;
   const char*  kini = "&";       // start of varname: '&':
   const char*  kequ = "=";       // end of varname, start of argument: '='
   char  needle[TOKLEN] = "";     // complete pattern:  &varname=abc1234


   strcpy(sarg,"");
   strcpy(needle, kini);
   strcat(needle, vname);
   strcat(needle, kequ);
   pos = strstrpos(haystack, needle); 
   if(pos==-1) {
      needle[0]='?';
      pos = strstrpos(haystack, needle);
      if(pos==-1) return sarg;
   }
   pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ   
   while( (ch!='&')&&(ch!='\0') ) {
      ch=haystack[pos+i];    
      if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
        ||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
           sarg[i]='\0';
           return sarg;
      }       
      if( (ch!='&') ) {
          sarg[i]=ch;          
          i++;       
      }      
   } 
   return sarg;
}

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 20, 2018

Here's my thoughts:

  • http protocol is not handled correctly. At the first received \n, all web data is sent then the connection is closed. The http client / browser realizes that its header is not fully read when the connection is closed (no ack received from the esp, because only the first line is read), hence the error. When modifying the sketch to read at least the full header (two consecutive \n), then things work.
  • I don't know why this sketch was working with some previous version of the core. Unless forced to, I will not try to find out why. With proper proper protocol handling, things are working well.

To (quickl&dirty) fix the above sketch:

      static char oldc = 0;
      if (c == '\n' && oldc == '\n') {
        client.flush(); // <-- useless here, this empties the output buffer, not the input buffer
        ... // write data, flush() and stop()
      }
      oldc = c;

Using Stream::readBytesUntil() would allow to have a lighter code in the sketch.

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 20, 2018

My quick&dirty fixes above are not sufficient. HTTP header ends with 13/10/13/10 (\r\n\r\n)
Also, filling readString is useless and must not be limited by TOKLEN which stops reading.
it's

      //if HTTP request has ended
      static char oldc = 0;
      //Serial.println("readstring=" + readString);
      if (oldc == 10 && c == 13) {
        client.read(); // consume last 10
        //client.flush(); // <-- useless here, this empties the output buffer, not the input buffer
        Serial.println("header received");

@dsyleixa
Copy link
Author

dsyleixa commented Aug 21, 2018

I meanwhile changed handleNotAuthorized() checking also TOKLEN, additionally fixing a different issue, still working fine with 2.4.0, but still not working with 2.4.2. (changes courtesy of "Moppi")

  • unfortunately I don't understand how the entire code should look like to match your proposals, and I also don't find working "golden standard" source code examples how to check for login data by name and password correctly:
// Moppi's Fix

void handleNotAuthorized() {
  String readString = "";
  char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;
  
  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // debug
  // authorized=true;

  strcpy(strinput, "");
  strcpy(strupwd, "");
  strcpy(struname, "");

  while ( client.connected() ) {
    if (authorized) return;

    if ( client.available() ) {
      char c = client.read();

      //read char by request
      readString = "";
      while ( (readString.length() < TOKLEN) && (c != '\n') ) {
          readString += c;
          c = client.read();
      }

    readString.toCharArray(strinput, MAXLEN);
    // cstringarg( char* haystack, char* vname, char* sarg )
    // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
    cstringarg(strinput, "uname", struname);  // uname
    cstringarg(strinput, "upwd", strupwd);   // upwd

    // debug
    Serial.print("strupwd     >>>"); Serial.print(strupwd); Serial.println("<<<");
    Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");
    Serial.print("readString>>>");Serial.println(readString);

    if ( (strlen(strupwd) == strlen(website_upwd)) && (strcmp(website_upwd, strupwd) == 0) )
    {
      authorized = true;
      //debug
      //Serial.print("check: authorized="); Serial.println(authorized);
      readString = "";
      return;
    }   
      
      //if HTTP request has ended
      if (c == '\n') {
         client.flush();  // <-- useless here, this empties the output buffer, not the input 

        //now output html data header
        String script = "";

        script += ("HTTP/1.1 401 Log-In Required");
        script += ("Content-Type: text/html \n");
        script += ("\n");  //  do not forget this one //????
        script += ("<!DOCTYPE html> \n");
        script += ("<html> \n");
        script += ("<head> \n");

        // utf-8 für "°" Zeichen
        script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
        script +=  "<title>" ;
        script +=  website_title ;
        script +=  "</title> \n" ;
        script +=  "</head> \n" ;
        script +=  "<body> \n" ;

        script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
        script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
        script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

        script += ("<FORM ACTION='/' method=GET > \n");
        script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
        script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

        script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

        script += ("</FORM> \n");
        script += ("<BR> \n");
        script += ("</body> \n");
        script += ("</html> \n");

        client.print(script);

        //stopping client
        client.stop();
        delay(1);
      }
    }
    delay(1);
  }
}

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 21, 2018

You should restart from adapting the WebServer example.

FWIW, here's your modified working sketch. Apart from removing external stuff, only handleNotAuthorized is modified. I'm afraid I/we can't help you more here.

//----------------------------------------------------------------------------
//  board: ESP8266 NodeMCU 1.0 (ESP12-E module)
//  Arduino IDE 1.8.5
//  esp8266 core 2.4.0
//----------------------------------------------------------------------------


// Wifi + website data

const char* ssid = "SSID";             // WIFI network name
const char* password = "PSK";         // WIFI network password

// define
char  website_uname[20] = "xx" ; //  website user name log in  "MyWebsiteLoginName"
char  website_upwd[20] = "yy"; //  website user pwd log in   "MyWebsiteLoginPwd"
const char* website_title = "#5021";    //  website caption           "MySiteCaption"
const char* website_url = "http://givemeluck";      //  website url               "http:\\mysite.com"
int http_port = 80;

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

WiFiServer   wifiserver(http_port);
ESP8266WebServer lanserver(8081);
bool      authorized = false;

//----------------------------------------------------------------------------
// handle root +clients
//----------------------------------------------------------------------------

void handleRoot() {
  handleClients();
}


//----------------------------------------------------------------------------

void handleClients() {
  String msgtok;
  //------------------------------------------

  //client-Werte auch bei Url-Aufruf zurückgeben

  String message = "*** ";
  // re CLIENT 0
  /*
    message += (String)"&c0t1=" + c0t1.sact + "&c0h1=" + c0h1.sact;
    message += (String)"&c0t2=" + c0t2.sact + "&c0h2=" + c0h2.sact;
    message += "&c0out1=" + (String)c0out1 + "&c0out2=" + (String)c0out2 + "&c0out3=" + (String)c0out3 ;
  */
  message += " ###";
  //Serial.println(message);
  lanserver.send(200, "text/plain", message);

}

//----------------------------------------------------------------------------
// Tools
//----------------------------------------------------------------------------

int16_t  strstrpos(char * haystack,  char * needle)   // find 1st occurance of substr in str
{
  char *p = strstr(haystack, needle);
  if (p) return p - haystack;
  return -1;   // Not found = -1.
}

//----------------------------------------------------------------------------
const int  MAXLEN = 1024;
const int  TOKLEN = 64;

char * cstringarg( char* haystack, const char* vname, char* sarg ) {
  int i = 0, pos = -1;
  unsigned char  ch = 0xff;
  char  kini[3] = "&";       // start of varname: '&':
  char  kequ[3] = "=";       // end of varname, start of argument: '='
  char  needle[TOKLEN] = ""; // complete pattern:  &varname=abc1234

  //kequ[0] = '=';  // customize
  strcpy(sarg, "");
  strcpy(needle, kini);
  strcat(needle, vname);
  strcat(needle, kequ);
  pos = strstrpos(haystack, needle);
  if (pos == -1) return sarg;
  pos = pos + strlen(vname) + 2; // start of value = kini+vname+kequ
  while ( (ch != '&') && (ch != '\0') ) {
    ch = haystack[pos + i];
    if ( (ch == '&') || (ch == ';') || (ch == ' ') || (ch == '\0') || (ch == '\n')
         || (i + pos >= (int)strlen(haystack)) || (i > TOKLEN - 1) ) {
      sarg[i] = '\0';
      return sarg;
    }
    if ( (ch != '&') ) {
      sarg[i] = ch;
      i++;
    }
  }
  return sarg;
}


//----------------------------------------------------------------------------
// SETUP
//----------------------------------------------------------------------------


void setup() {

  //STR_DEGREE[0] = CHR_DEGREE; // ° symbol as ANSI C string


  //----------------------------------------
  Serial.begin(115200);
  delay(1000);

  //----------------------------------------
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.println("Connecting to Router: ");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected: ");
  Serial.println(WiFi.gatewayIP());


  //----------------------------------------
  // Start the WiFi server (-> www)
  wifiserver.begin();
  Serial.println("WiFi Server started");

  //----------------------------------------
  // Start the ESP LAN server (-> ESP client)
  lanserver.on("/", handleRoot) ;
  lanserver.on("/client/client0/", handleClients);
  delay(10);
  lanserver.on("/client/client1/", handleClients);
  delay(10);
  lanserver.on("/client/client2/", handleClients);
  delay(10);
  lanserver.on("/client/client3/", handleClients);
  delay(10);
  lanserver.begin();
  Serial.println("ESP Server started");

  // Print the IP address
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.print(":");
  Serial.print(http_port);
  Serial.println("/");
  Serial.print((String)website_url + ":" + http_port + "/");

  delay(1);

  //----------------------------------------
  // setup done
  Serial.println("setup done \n");
}

//----------------------------------------------------------------------------
// LOOP
//----------------------------------------------------------------------------

void loop() {

  //---------------------------------------
  // Check log-in

  if (!authorized) {
    handleNotAuthorized();
    delay(100);
  }

  if (authorized) {
    handleWebsite();
    delay(10);
  }

  lanserver.handleClient();
  delay(10);
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

void handleNotAuthorized() {
  String readString = "";
  char   strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // debug
  // authorized=true;

  strcpy(strinput, "");
  strcpy(strupwd, "");
  strcpy(struname, "");

  while ( client.connected() ) {
    if (authorized) return;


    readString.toCharArray(strinput, MAXLEN);
    // cstringarg( char* haystack, char* vname, char* sarg )
    // haystack pattern: &varname=1234abc,  delimiters &, \n, \0, SPACE, EOF
    cstringarg(strinput, "uname", struname);  // uname
    cstringarg(strinput, "upwd", strupwd);   // upwd

    // debug
    //Serial.print("strupwd     >>>"); Serial.print(strupwd); Serial.println("<<<");
    //Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");


    if ( (strlen(strupwd) == strlen(website_upwd) )
         && (strcmp(website_upwd, strupwd ) == 0)
       )
    {
      authorized = true;
      //debug
      //Serial.print("check: authorized="); Serial.println(authorized);
      readString = "";
      return;
    }

    if ( client.available() ) {
      char c = client.read();
      static char oldc = 0;
      //read char by request
      //if (readString.length() < TOKLEN)
      {

        //store characters to string
        readString += c;
        Serial.printf("read '%c'(%i)\n", c, c);
      }

      //if HTTP request has ended
      //Serial.println("readstring=" + readString);
      if (c == 13 && oldc == 10) {
        client.read(); // consume last 10
        //client.flush();
        Serial.println("header received");


        //now output html data header

        String script = "";

        script += ("HTTP/1.1 401 Log-In Required");
        script += ("Content-Type: text/html \n");
        script += ("\n");  //  do not forget this one //????
        script += ("<!DOCTYPE html> \n");
        script += ("<html> \n");
        script += ("<head> \n");


        // utf-8 für "°" Zeichen
        script +=  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
        script +=  "<title>" ;
        script +=  website_title ;
        script +=  "</title> \n" ;
        script +=  "</head> \n" ;
        script +=  "<body> \n" ;

        script += "<h1><p style=\"color:rgb(255,0,191);\"> " + (String)website_url ;
        script += (String)": &nbsp; <wbr> <wbr> " + "Not authorized !</p> </h1> \n" ;
        script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

        script += ("<FORM ACTION='/' method=GET > \n");
        script += ("<h2>user name:  <INPUT TYPE=text NAME='uname' VALUE=''  MAXLENGTH='50'> </h2> \n");
        script += ("<h2>password :  <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

        script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

        script += ("</FORM> \n");
        script += ("<BR> \n");
        script += ("</body> \n");
        script += ("</html> \n");

        Serial.printf("len=%d\n", script.length());
        client.print(script);

        client.flush();
        Serial.println("stop");
        client.stop();
        Serial.println("stopped");

        delay(1);

        //clearing string for next read
        readString = "";
      }

      oldc = c;
    }
    delay(1);
  }
}


//----------------------------------------------------------------------------

void handleWebsite() {

  WiFiClient client = wifiserver.available();

  //---------------------------------------
  // Check if a client has connected


  // Read the first line of the request
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();

  //---------------------------------------
  // LogOut
  if (request.indexOf("/logout") != -1)  {
    authorized = false;
    return;
  }

  delay(1);

  //---------------------------------------
  // Return the response

  String script = "";

  // init website

  script += ("HTTP/1.1 200 OK \n");
  script += ("Content-Type: text/html \n");
  script += ("\n"); //  do not forget this one
  script += ("<!DOCTYPE html> \n");
  script += ("<html> \n");

  // head + title
  script += ("<head> \n");
  // autom. Aktualisierung alle 20 sec.

  script += "<meta http-equiv=\"refresh\" content=\"20; URL=";
  script += (String)website_url + ":" + (String)http_port + "\"> \n" ;


  // utf-8 für "°" Zeichen
  script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
  script += ("<title>");
  script += (website_title);
  script += ("</title> \n");
  script += ("</head> \n");

  // body + caption
  script += ("<body> \n");
  script += ("<h1> <p> ");
  script += ("<font style=\"color:rgb(255,0,204);\"> HELLO WORLD! ");
  script += ("&nbsp; <wbr> <wbr> ");
  script += ("<font style=\"color:rgb(0,205,102);\"> Welcome to " + (String)website_url );
  script += ("! </p> </h1>  "); // script+= ("! </p> </h1> \n");


  delay(1);


  //---------------------------------------
  script +=  "<h2> <br> \n  HEIMSERVER  <br> \n </h2>";
  //---------------------------------------
  // remote buttons Server
  // <input type="button" value="submit" style="height: 100px; width: 100px; left: 250; top: 250;">
  // <button style=\"height:200px;width:200px\"> </button>



  client.print(script);
  script = "";


  //---------------------------------------
  // sensors  Server
  // chart table
  //---------------------------------------
  // text font Courier, color black
  script += ("<p> <font face=\"courier\"> "); // <<< Courier
  script += "<h2> ";
  script += "<p style=\"color:rgb(0,0,0);\" > </p>  " ;
  script += ("<br> \n");
  script += "</h2>";

  client.print(script);
  script = "";


  script += ("<br> \n");


  // log out
  script += ("<h3>Log Out: ");
  script += ("<a href=\" /logout\"\"> <button style=\"height:70px;width:140px\" > Log Out </button></a> </h3> ");

  script += WiFi.localIP().toString() + " " + (String)ssid + " <br>" ;
  script += "</font> </p> \n";

  script += "</body> \n";
  script += "</html> \n";

  client.print(script);

  delay(1);

}

@dsyleixa
Copy link
Author

dsyleixa commented Aug 21, 2018

thanks for your reply!
Unfortunately, the last version of yours doesn't work correctly after once having logged out on the main website (LogIn-Website does not reload always reliably), and besides "yy" also "yynnnnn" (n=arbitrary) is accepted too as a valid pwd (opposite to the last source code version I had posted above).

OTOH, I know the example https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino but that didn't help me to implement a log-in Website accurately though (as shown).

I have to admit that I don't have the skills to understand how to change the code and fix all those issues in a reasonable way, so I'm afraid I'll have to stay with my own last version (feat. Moppi's fix) and the 2.4.0 core, at least it's working there as expected.
Nonetheless, thank you very much for your help and for your efforts!

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 21, 2018

This why arduino libraries are here, they do part of the job for you.
Please post a new request issue asking for a webserver example with credential,
maybe someone (not excluding me) will take time to do it well for the core's examples.

@dsyleixa
Copy link
Author

thanks for your advice, I did so!

@wongnam
Copy link

wongnam commented Aug 24, 2018

Web site doesn't show up if i use VPN with core 2.4.0 till 2.4.2.
Core 2.3.0 is fine in VPN.

@d-a-v
Copy link
Collaborator

d-a-v commented Aug 24, 2018

@wongnam please open a new issue with your details.

@dsyleixa
Copy link
Author

2.4.2 still does not work as shown in #5021 (comment) .
2.4.0 instead works.
Which is the reason why? What is faulty?

@5chufti
Copy link
Contributor

5chufti commented Dec 20, 2018

@wongnam
this might be caused by lwip v2 lower memory, try with v2 higher bandwidth

@dsyleixa
Copy link
Author

dsyleixa commented Dec 20, 2018

@schufti

@wongnam
this might be caused by lwip v2 lower memory, try with v2 higher bandwidth

what do you mean? Is it a cross-post? Here is no user wongnam posting!
please describe more detailed please!

@earlephilhower
Copy link
Collaborator

This bug seems to have meandered around the last 6 months and ended up morphing into a much simpler one asking for a specific example, which is still open. Don't see anything to do here, closing.

@dsyleixa
Copy link
Author

dsyleixa commented Jan 31, 2019

This bug seems to have meandered around the last 6 months and ended up morphing into a much simpler one asking for a specific example, which is still open. Don't see anything to do here, closing.

So please kindly reopen this topic as it is still unresolved!

@earlephilhower
Copy link
Collaborator

Howdy, @dsyleixa, A suggestion: There really are multiple things going on in this issue and it's unclear to me. It's got quite a few sketches inline, too. The example issue is still open, sure, and being tracked in another spot, which makes it more likely to get attention as it's focused on one thing.

The code in the first entry here is not an MCVE, it needs to be able to be compiled and run as-is and be as short as possible, so that the very few maintainers don't need to scrape together a new application/etc. to see what's going on.

You'd be best served to post a new issue with a single MCVE that fails under 2.5.0-rc3 (2.4.2 is quite old now), a brief summary of where you think it got with this issue, and a link to #5021 at the end of the report.

@dsyleixa
Copy link
Author

dsyleixa commented Jan 31, 2019

the code is cut-down here:

#5021 (comment)

this is probably your MCVE, bug reproduced by d-a-v

@earlephilhower
Copy link
Collaborator

Cool. I'm sure it would never be found otherwise. I'll reopen this one, but can you please edit the initial post here to point to that comment and the title to be more direct?

@earlephilhower earlephilhower added this to the 2.6.0 milestone Jan 31, 2019
@d-a-v
Copy link
Collaborator

d-a-v commented Jan 31, 2019

@dsyleixa There's also this #5021 (comment) just after the one you reference.
From what I understand you want to stick with a malfunctioning sketch because you have issues with adapting a working sketch to your needs.

From advices given to you, you opened a new issue, in which you received help from others, and you clearly state you don't have enough skills to achieve your goals, in #5067 (comment).

We, maintainers, spend a lot of our spare time to fix bugs and improve performances. I'm sorry to tell you we just cannot write sketches for you. There are support forum for this, and 99% of the time you can find a suitable example somebody kindly shared, by just googling. We will be delighted when you come back with a meaning and working example that you will propose in a pull-request to add in our example repository.

@d-a-v d-a-v closed this as completed Jan 31, 2019
@dsyleixa
Copy link
Author

dsyleixa commented Feb 1, 2019

my request of the "other" topic was about a working code example in html for the nodeMCU core examples, to be used out of the Arduino IDE. Currently the provided examples don't help very much for common Arduino users who are no computer professionals but pupils, artists, craftsmen, and hobbyists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.
Projects
None yet
Development

No branches or pull requests

8 participants