parse HTTP GET request into something useful

I am a reformed web developer. From 1997 till 2014 I was fortunate to have someone pay me to sit at a desk and goof off most of the day, occasionally producing code to run the back end of web sites. I am very familiar with PHP and MySQL; and a bit rusty in PERL. I no longer do that, I got burned out, I'm competing with hacks and pedestrian DYI software and it doesn't pay like it used to. Now I "make forklifts smart", so to speak.

I thought I was doing really well creating various Arduino scripts until this one. I got a WeMos D1 R2 and have had minimal problems sending data in small chunks TO a web server, storing it in MySQL and doing "stuff" with it.

Then I tried the other way, sending commands from a web browser to the Arduino and it's kicking my butt.

The problem isn't receiving the information, the problem is doing anything with it once I receive it.

Simple example, let's say I have the board connected to my home WiFi and two garage door openers via relays.

Garage door #1 is a momentary switch, garage door #2 is older and you have to hold it closed in order to get it to run, it doesn't matter if it's open or closed, same circuit, the garage door opener "figures it out" as to which way to run.

So, my theory (and I'm sure there's better ways to do this, but bear with me) is you have two URLs available.
http://192.168.1.2/control?door=1&time=1
http://192.168.1.2/control?door=2&time=25
Either request returns the same "page" with the links as well as closes the appropriate relay for the appropriate amount of time in seconds.

If you browse to 192.168.1.2/ it simply returns the page with links, but since there's no "control" "command", it doesn't do anything else.

I wrote one earlier using String, which I understand and agree is evil, there are remnants of that code commented out. I'm trying to accomplish the same thing using char, or char *. To be perfectly honest, I am having a hard time understanding when is appropriate to use each one and simply switch to the other when my code doesn't compile.

What's very frustrating right now is the fact that I can't even verify my single character insertion worked because every attempt to Serial.print(get_line), Serial.print((char *)get_line), etc doesn't compile and attempting to use a for loop to iterate a print statement for each get_line compiles but blows up and resets the Arduino.
Original code from Wemos webserver example - esp8266 learning
I didn't even get to the point where I'd change "ledPin", so let's pretend that's the relays in question.
The "found a space" part is important to sniff out the GET request.
Later, that would be further parsed into key=>value pairs so I'd know what to do with which relay.
Ultimately, I want to be able to handle anywhere from zero to six key=>value pairs which will usually be numeric or empty.
Current code:
```
*#include <ESP8266WiFi.h>

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

int ledPin = D5;
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);

pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

// Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

WiFi.begin(ssid, password);

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

// Start the server
  server.begin();
  Serial.println("Server started");

// Print the IP address
  Serial.print("Use this URL : ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");

}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (client) {// Wait until the client sends some data
    Serial.println("new client");
    while(!client.available()){
      delay(1);
    }

//char * get_line[255] = { (char *) client.readStringUntil('\r').c_str() };
    //printf (get_line[]);
    int space_count = 0;
    int j = 0;
    char * get_line[255];
    char c;
    while(space_count < 2){
      c = client.read();
      Serial.print(c);
      if(c == ' '){
        space_count ++;
        Serial.println("found a space");
      }
      get_line[j] = (char *) c;
      j++;
      get_line[j] = '\0'; 
    }
   
    /*String action = client.readStringUntil('/'); //garbage
    action = client.readStringUntil('?'); //garbage
    if(action.indexOf(' ') != -1)
      action = action.substring(0, action.indexOf(' '));
    Serial.println("action:" + action);
    if(action.indexOf("control") == -1){
      return;
    }
    Serial.print("action location: ");
    Serial.println(action.indexOf("control"));
    String param1name = client.readStringUntil('=');
    String param1value = client.readStringUntil('&');
    String param2name = client.readStringUntil('=');
    String param2value = client.readStringUntil('&');
    String param3name = client.readStringUntil('=');
    String param3value = client.readStringUntil('&');
 
    Serial.print("param1: " + param1name);
    Serial.println("=> " + param1value);
    Serial.print("param2: " + param2name);
    Serial.println("=> " + param2value);
    Serial.print("param3: " + param3name);
    Serial.println("=> " + param3value);
    */
    client.flush();
 
    // Match the request
    //this is where all the fun stuff would happen, like specifying which one
    //and timing it and such.
 
    int value = LOW;
    //I could do it this way, but each key=>value pair would increase the amount of code needed exponentially. 1 is two outcomes, 2 is four, three is eight, etc.
    /if (request.indexOf("/LED=ON") != -1) {
      digitalWrite(ledPin, HIGH);
      value = HIGH;
    }
    if (request.indexOf("/LED=OFF") != -1){
      digitalWrite(ledPin, LOW);
      value = LOW;
    }
/
 
 
 
    // Return the response
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println(""); //  do not forget this one
    client.println("");
    client.println("");
 
    client.print("Led pin is now: ");
 
    if(value == HIGH) {
      client.print("On"); 
    } else {
      client.print("Off");
    }
    client.println("

");
    client.println("Click <a href="/control?door=1&time=1">Door 1
");
    client.println("Click <a href="/control?door=2&time=25">Door 2
");
    client.println("");
 
    delay(1);
    Serial.println("Client disconnected");
    Serial.println("");
  }
}*
```

Even if you do think strings are 'evil', you'll have to get used to them since these are used extensively in the Arduino core code for the ESP8266

You can use the arg() method of the ESP8266WebServer class to parse the querystring sent by the browser.

// browser sends:
http://192.168.1.2/control?door=2&time=25

// web server code snippet

ESP8266WebServer server (80);
. . . 
server.handleClient();
. . .
Serial.println ( server.arg("door" )  ) ;
Serial.println ( server.arg("time" )  ) ;

Will give the arg a shot, didn't see that before, but sounds like it could solve my problem.

Thanks!

6v6gt:
Even if you do think strings are 'evil', you'll have to get used to them since these are used extensively in the Arduino core code for the ESP8266

You can use the arg() method of the ESP8266WebServer class to parse the querystring sent by the browser.

// browser sends:
http://192.168.1.2/control?door=2&time=25

// web server code snippet

ESP8266WebServer server (80);
. . .
server.handleClient();
. . .
Serial.println ( server.arg("door" )  ) ;
Serial.println ( server.arg("time" )  ) ;

I was initially very confused because I got the following error:
'class WiFiServer' has no member named 'arg'

Then I realized your code uses an entirely different "server" object. While for most people, it's not necessary to send mime-types and such, I do like that this includes that functionality out of the box. My initial script these had to be built line by line, which isn't difficult, just tedious.

Completely different, but working code which addresses both the "control" aspect as well as the args:
Stolen from the end of Getting started with the WeMos D1 ESP8266 WiFi Board – Cyan Infinite "HelloServer.ino"

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
 
const char* ssid     = "Verizon";
const char* password = "password";
 
ESP8266WebServer server(80);
 
const int led = 2;
 
void handleRoot() {
  digitalWrite(led, 1);
  server.send(200, "text/plain", "Hello from esp8266!");
  digitalWrite(led, 0);
}
 
void handleNotFound(){
  digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  digitalWrite(led, 0);
}
 
void setup(void){
  pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
 
  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }
 
  server.on("/", handleRoot);
 
  server.on("/inline", [](){
    server.send(200, "text/plain", "this works as well");
  });

  server.on("/control", [](){
    server.send(200, "text/plain", "this works as well");
    Serial.println ( server.arg("door" )  ) ;
    Serial.println ( server.arg("time" )  ) ;
  });
 
  server.onNotFound(handleNotFound);
 
  server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void){
  server.handleClient();
}

This is a very good start and hopefully it'll be a lot less frustrating than the other script.

Thanks.