void ESP8266WebServer::handleClient()
{
  WiFiClient client = _server.available();
  if (!client) {
    return;
  }

#ifdef DEBUG
  Serial.println("New client");
#endif
  // Wait for data from client to become available
  while(client.connected() && !client.available()){
    delay(1);
  }

  // Read the first line of HTTP request
  String req = client.readStringUntil('\r');
  client.readStringUntil('\n');

  HTTPMethod method = HTTP_GET;
  if (req.startsWith("POST")) {
    method = HTTP_POST;
  }

  // First line of HTTP request looks like "GET /path HTTP/1.1"
  // Retrieve the "/path" part by finding the spaces
  int addr_start = req.indexOf(' ');
  int addr_end = req.indexOf(' ', addr_start + 1);
  if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG
    Serial.print("Invalid request: ");
    Serial.println(req);
#endif
    return;
  }

  req = req.substring(addr_start + 1, addr_end);

  String formData;
  if (method == HTTP_POST) {
    int contentLength = -1;
    int headerCount = 0;
    while(headerCount < 1024) { // there shouldn't be that much really
      String line = client.readStringUntil('\r');
      client.readStringUntil('\n');

      if (line.length() > 0) {  // this is a header
        ++headerCount;
        if (contentLength < 0 && line.startsWith("Content-Length")) {
          // get content length from the header
          int valuePos = line.indexOf(' ', 14);
          if (valuePos > 0) {
            String valueStr = line.substring(valuePos+1);
            contentLength = valueStr.toInt();
#ifdef DEBUG
            Serial.print("Content-Length: ");
            Serial.println(contentLength);
#endif
          }
        }
      }
      else {
        break;
      }
    }
#ifdef DEBUG
    Serial.print("headerCount=");
    Serial.println(headerCount);
#endif
    if (contentLength >= 0) {
      formData = "";
      int n = 0;   // timeout counter
      while (formData.length() < contentLength && ++n < 3)
        formData += client.readString();
    }
    else {
      formData = client.readStringUntil('\r'); // will return after timing out once
    }
  }
  else if (method == HTTP_GET) {
    int args_start = req.indexOf('?');
    if (args_start != -1) {
      formData = req.substring(args_start + 1);
      req = req.substring(0, args_start);
    }
  }

  client.flush();

#ifdef DEBUG
  Serial.print("Request: ");
  Serial.println(req);
  Serial.print("Args: ");
  Serial.println(formData);
#endif

  _parseArguments(formData);
  _handleRequest(client, req, method);

}
Example #2
0
// Process HTTP requests -- just call it inside the loop() function
void WebConfig::ProcessHTTP()
{
	// Accept any new web connection
	WiFiClient httpClient = pHttpServer->available();
	if (!httpClient) return;

	// Read the entire request
	String req = httpClient.readString();
	httpClient.flush();

	// after some time, do not open the web interface anymore.
	//if (millis() - startMillis > 2*60000) return;

	// response header
	String s;

	if (strlen(webLogin) > 0 || strlen(webPassword) > 0)
	{
		int authPos = req.indexOf("Authorization: Basic");

		if (authPos == -1)
		{
			// request authentication
			s = "HTTP/1.0 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"" + String(apName) + "\"\r\n\r\n";
			s += "<h1><b>ACCESS DENIED</b></h1>";
			httpClient.write(s.c_str(), s.length());
			httpClient.flush();
			return;
		}

		// there is authentication info, check it
		String authInfo = req.substring(authPos + 21);
		int endLinePos = authInfo.indexOf("\r");
		if (endLinePos == -1) { httpClient.print("Malformed request."); httpClient.stop(); return; }
		authInfo = authInfo.substring(0, endLinePos);
		if (strncmp(base64Auth, authInfo.c_str(), 64))
		{
			s = "<h1><b>ACCESS DENIED</b></h1>";
			httpClient.write(s.c_str(), s.length());
			httpClient.flush();
			return;
		}
	}

	byte mac[6];
	WiFi.macAddress(mac);
	String m = String(mac[0],HEX) + ":" + String(mac[1],HEX) + ":" + String(mac[2],HEX) + ":" + String(mac[3],HEX) + ":" + String(mac[4],HEX) + ":" + String(mac[5],HEX);

	//
	// generate HTTP response
	//

	// authentication succeeded, proceed normally
	s = "HTTP/1.1 200 OK\r\n";
	s += "Content-Type: text/html\r\n\r\n";
	s += "<!DOCTYPE HTML>\r\n<html><body>\r\n";

	// If there are parms, update variables and save settings
	bool updated = ProcessParms(req);
	if (updated)
	{
		s += "Parameters have been updated and microcontroller will restart.<br><br>\r\n";
	}

	// javascript to save configuration
	s += "<script>\r\n";
	s += "function save()\r\n";
	s += "{\r\n";
	s += "var webPort = document.getElementById('web_port').value;\r\n";
	s += "var webLogin = document.getElementById('web_login').value;\r\n";
	s += "var webPassword = document.getElementById('web_pass').value;\r\n";
	s += "var webPassword2 = document.getElementById('web_pass2').value;\r\n";
	s += "var modeap = document.getElementById('modeap').checked;\r\n";
	s += "if (modeap) isAP = true; else isAP = false;\r\n";
	s += "var apName = document.getElementById('ap_ssid').value;\r\n";
	s += "var apPassword = document.getElementById('ap_pass').value;\r\n";
	s += "var apPassword2 = document.getElementById('ap_pass2').value;\r\n";
	s += "var apChannel = document.getElementById('apChannel').value;\r\n";
	s += "var ssid = document.getElementById('ssid').value;\r\n";
	s += "var password = document.getElementById('pass').value;\r\n";
	s += "var password2 = document.getElementById('pass2').value;\r\n";
	s += "var udpPort = document.getElementById('udpPort').value;\r\n";
	s += "var tcpPort = document.getElementById('tcpPort').value;\r\n";
	s += "if (webPassword != webPassword2) { alert('WEB passwords dont match'); return; }\r\n";
	s += "if (apPassword != apPassword2) { alert('AP passwords dont match'); return; }\r\n";
	s += "if (password != password2) { alert('Router passwords dont match'); return; }\r\n";
	s += "window.location.search=webPort + '&' + webLogin + '&' + webPassword + '&' + btoa(webLogin+':'+webPassword) + '&' + (isAP?'1':'0') + '&' + apName + '&' + apPassword + '&' + apChannel + '&' + ssid + '&' + password + '&' + udpPort + '&' + tcpPort;\r\n";
	s += "}\r\n";
	s += "</script>\r\n";

	// write first part of response
	httpClient.write(s.c_str(), s.length());

	// title and mac address
	s = "<b>" + String(name) + "</b><br>\r\n";
	s += "MAC: " + m + "<br>\r\n";

	// web interface configuration
	s += "<table border=1>\r\n";
	s += "<tr><td colspan=2 bgcolor=#E0E0E0><b>WEB INTERFACE</b></td></tr>\r\n";
	s += "<tr><td>Port</td><td><input type=text id='web_port' value='" + String(webPort) + "'></td></tr>\r\n";
	s += "<tr><td>Login</td><td><input type=text id='web_login' value='" + String(webLogin) + "'></td></tr>\r\n";
	s += "<tr><td>Password</td><td><input type=password id='web_pass' value='" + String(webPassword) + "'></td></tr>\r\n";
	s += "<tr><td>Pass Confirm</td><td><input type=password id='web_pass2' value='" + String(webPassword) + "'></td></tr>\r\n";
	s += "</table>\r\n";

	// ap configuration
	s += "<table border=1>\r\n";
	s += "<tr><td colspan=2 bgcolor=#E0E0E0><b>ACCESS POINT</b></td></tr>\r\n";
	s += "<tr><td>Mode</td><td><input type=radio id='modeap' name='mode' value='ap'" + (isAP?String(" checked"):String("")) + ">Access Point</td></tr>\r\n";
	s += "<tr><td>Channel</td><td><select id='apChannel'>";
	for (byte c=1; c<14; c++) s += "<option value='" + String(c) + "'" + (c==apChannel?String(" selected"):String("")) + ">" + String(c) + "</option>";
	s += "</select></td></tr>\r\n";
	s += "<tr><td>SSID</td><td><input type=text id='ap_ssid' value='" + String(apName) + "'></td></tr>\r\n";
	s += "<tr><td>Password</td><td><input type=password id='ap_pass' value='" + String(apPassword) + "'></td></tr>\r\n";
	s += "<tr><td>Pass Confirm</td><td><input type=password id='ap_pass2' value='" + String(apPassword) + "'></td></tr>\r\n";
	s += "</table>\r\n";

	// station configuration
	s += "<table border=1>\r\n";
	s += "<tr><td colspan=2 bgcolor=#E0E0E0><b>STATION</b></td></tr>\r\n";
	s += "<tr><td>Mode</td><td><input type=radio id='modest' name='mode' value='station'" + (isAP?String(""):String(" checked")) + ">Station</td></tr>\r\n";
	s += "<tr><td>SSID</td><td><input type=text id='ssid' value='" + String(ssid) + "'></td></tr>\r\n";
	s += "<tr><td>Password</td><td><input type=password id='pass' value='" + String(password) + "'></td></tr>\r\n";
	s += "<tr><td>Pass Confirm</td><td><input type=password id='pass2' value='" + String(password) + "'></td></tr>\r\n";
	s += "</table>\r\n";

	// udp/tcp ports configuration
	s += "<table border=1>\r\n";
	s += "<tr><td colspan=2 bgcolor=#E0E0E0><b>UDP|TCP LISTENERS</b></td></tr>\r\n";
	s += "<tr><td>UDP Port</td><td><input type=text id='udpPort' value='" + String(udpPort) + "'></td></tr>\r\n";
	s += "<tr><td>TCP Port</td><td><input type=text id='tcpPort' value='" + String(tcpPort) + "'></td></tr>\r\n";
	s += "</table>\r\n";

	// save button
	s += "<input type=button value='Save and Reset' onClick='save()'>\r\n";

	// end of HTTP
	s += "</body></html>\r\n";

	// write second part of response
	httpClient.write(s.c_str(), s.length());
	httpClient.flush();

	if (updated)
	{
		// give some time
		delay(2000);

		// reset the microcontroller
		Reset();
	}
}
////////////////////////////////////
// Scrape UTC Time from server
////////////////////////////////////
char* updateCurTime(void) {
    static int timeout_busy=0;
    int ipos;
    timeout_busy=0; //reset

    const char* timeServer = "aws.amazon.com";

    // send a bad header on purpose, so we get a 400 with a DATE: timestamp
    const char* timeServerGet = "GET example.com/ HTTP/1.1";
    String utctime;
    String GmtDate;
    static char dateStamp[20];
    static char chBuf[200];
    char utctimeraw[80];
    char* dpos;

    WiFiClient client;
    if (client.connect(timeServer, 80)) {
        //Send Request
        client.println(timeServerGet);
        client.println();
        while((!client.available())&&(timeout_busy++<5000)){
          // Wait until the client sends some data
          delay(1);
        }

        // kill client if timeout
        if(timeout_busy>=5000) {
            client.flush();
            client.stop();
            Serial.println("timeout receiving timeserver data\n");
            return dateStamp;
        }

        // read the http GET Response
        String req2 = client.readString();
        // Serial.println("");
        // Serial.println("");
        // Serial.print(req2);
        // Serial.println("");
        // Serial.println("");

        // close connection
        delay(1);
        client.flush();
        client.stop();

        ipos = req2.indexOf("Date:");
        if(ipos>0) {
          GmtDate = req2.substring(ipos,ipos+35);
          // Serial.println(GmtDate);
          utctime = GmtDate.substring(18,22) + getMonth(GmtDate.substring(14,17)) + GmtDate.substring(11,13) + GmtDate.substring(23,25) + GmtDate.substring(26,28) + GmtDate.substring(29,31);
          // Serial.println(utctime.substring(0,14));
          utctime.substring(0,14).toCharArray(dateStamp, 20);
        }
    }
    else {
      Serial.println("did not connect to timeserver\n");
    }
    timeout_busy=0;     // reset timeout
    return dateStamp;   // Return latest or last good dateStamp
}