Arduino Web Server Form Processing

Hey guys, first post here :slight_smile: As a longtime lurker, Thank you in advance for all your help!

My question boils down to obtaining the string of data posted by the user to the web page served by the arduino using either the GET or POST methods. I'm relatively new to html and web server protocol, but from what I've gathered, the user sends data through either the GET or POST methods as dictated by the html form code.

My problem is I have not been able to figure out how to pull that string and parse it. The webpage I've written just takes a single text box submission. Do you guys have experience doing this with the TinyWebServer library? I've looked over his examples, but they all seem to use the SD card to host seperate .php and .js files that handle form submission. Is the SD card required for this sort of simple form processing? Is there any way to put my own function within the html form that simply receives the submitted string? I've tried to write angleout_handler that I want to read the characters submitted by the web page, but every time I use Serial.println to debug the string, it's not the sequence of number's I'm expecting. I don't fully understand how the client and server interact when the web.process() function runs, especially as it relates to the handlers and the headers. If someone has some experience with this sort of server interactions, a general rundown on the subject would be much appreciated.

Code:

#include <SPI.h>
#include <Servo.h>
#include <Ethernet.h>
#include <Flash.h>
#include <SdFatUtil.h>
#include <TinyWebServer.h>

Servo shoulder;
Servo elbow;
String angle,angleout,commandstring;
String angle1String = String(13);
String angle2String = String(13);
String readString = String(50);
int angleval1, angleval2;
int prismaticval, shouldersave, elbowsave;

boolean index_handler(TinyWebServer& web_server);
boolean angleout_handler(TinyWebServer& web_server);

static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Don't forget to modify the IP to an available one on your home network
byte ip[] = { 129, 210, 18, 50 };

const char* headers[] = {
  "Content-Length",
  "Query-String",
  NULL
};

TinyWebServer::PathHandler handlers[] = {
  {"/", TinyWebServer::GET, &index_handler },
  {"/angleout""*", TinyWebServer::POST, &angleout_handler },
  {NULL},
};
static char buffer[160];
int Size= 15;
int testsize;

boolean index_handler(TinyWebServer& web_server) {
  web_server.send_error_code(200);
  web_server.end_headers();
  web_server << F("<html><body>\n");
  web_server << F("Enter commands as:XXXYYY where X is arm angle and Y is extension\n");
  web_server << F("
\n");
  web_server << F("where X is the arm extension, values 000 - 179\n");
  web_server << F("and Y is the arm angle, values 000 - 179\n");
  web_server << F("
\n");
  web_server << F("e.g. 090030 for 90 units of extension and 30 degree angle\n");
  web_server << F("negative values are accepted for relative commands only\n");
  web_server << F("<form name=input action='/angleout' method=post>\n");
  web_server << F("Angle1 input: <input type=text name=angle1 />\n");
  web_server << F("
\n");
  web_server << F("<input type=radio name=R value=1 />\n");
  web_server << F("absolute command 
\n");
  web_server << F("<input type=radio name=R value=2 />\n");
  web_server << F("relative command <input type=submit value=submit> 
\n");
  web_server << F("</form></body></html>\n");
  return true;
}


boolean angleout_handler(TinyWebServer& web_server){
  web_server.send_error_code(200);
  web_server.send_content_type("text/plain");
  web_server.end_headers();
  Client& client = web_server.get_client();
  if (client.available()){
   char pathstring = (char)client.read();
   //pathstring = *web_server.get_file_from_path(web_server.get_path());
  //Serial.println(pathstring);
   //web_server << F("client is available!");
   web_server << (pathstring);
  /*
  Client& client = web_server.get_client();
  if (client.available()) {
    char ch = (char)client.read();
    //if (ch == '?'){
     // for (int i=0;i<7;i++){
        pathstring += ch;
        web_server.decode_url_encoded(pathstring);
        web_server << (pathstring);
     // }
     // Serial.println(pathstring);
    //}
    if (pathstring.substring(0) == "&"){
      //parsecommand(pathstring);
      Serial.println(pathstring);
      return true;
    }
  }
  */
  }
return true;
}
 

boolean has_ip_address = false;
TinyWebServer web = TinyWebServer(handlers, headers);

const char* ip_to_str(const uint8_t* ipAddr)
{
  static char buf[16];
  sprintf(buf, "%d.%d.%d.%d\0", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
  return buf;
}

void setup() {
  Serial.begin(115200);
  shoulder.attach(9);
  elbow.attach(8);
  pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH); // but turn off the W5100 chip!
  pinMode(4, OUTPUT); // set the SS pin as an output (necessary!)
  digitalWrite(4, HIGH); // but turn off the SD card functionality!

  Serial << F("Free RAM: ") << FreeRam() << "\n";

  Serial << F("Setting up the Ethernet card...\n");
  Ethernet.begin(mac, ip);

  // Start the web server.
  Serial << F("Web server starting...\n");
  web.begin();

  Serial << F("Ready to accept HTTP requests.\n\n");
}

void loop() {
  web.process();
  
}

Thanks again

bump I've got this same problem!

I have some notes on my webpage Arduino Web forms - tutorial which may help. Below is the code which will get the response back from the form so that you can parse it as needed.

#include <SPI.h>
#include <Ethernet.h>
#define MaxHeaderLength 16    //maximum length of http header required


byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   //physical mac address
byte ip[] = { 
  192, 168, 2, 201 };   // static ip of Arduino
byte gateway[] = { 
  192, 168, 2, 254 };  // gateway address
byte subnet[] = { 
  255, 255, 255, 0 };  //subnet mask
EthernetServer server(80);   //web server port
String HttpHeader = String(MaxHeaderLength); 


void setup(){
  //enable serial monitor
  Serial.begin(9600);
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  //initialize variable
  HttpHeader="";

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //read MaxHeaderLength number of characters in the HTTP header
        //discard the rest until \n
        if (HttpHeader.length() < MaxHeaderLength)
        {
          //store characters to string
          HttpHeader = HttpHeader + c; 
        }
        //if HTTP request has ended
        if (c == '\n') { 
          // show the string on the monitor
          Serial.println(HttpHeader);
          // start of web page
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("<html><head></head><body>");
          client.println();
          client.print("<form method=get>");
          client.print("<input type='radio' name=r value='1'> One
");
          client.print("<input type='radio' name=r value='2' checked> Two
");
          client.print("<input type='radio' name=r value='3'> Three
");
          client.print("<input type=submit value=submit></form>");
          client.print("</body></html>");
          //clearing string for next read
          HttpHeader="";
          //stopping client
          client.stop();
        }
      }
    }
  }
}

thanks pindari
your second example works great for reading values by the arduino

#include <SPI.h>
#include <Ethernet.h>
#define MaxHeaderLength 16    //maximum length of http header required


byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   //physical mac address
byte ip[] = { 
  192, 168, 2, 201 };   // static ip of Arduino
byte gateway[] = { 
  192, 168, 2, 254 };  // gateway address
byte subnet[] = { 
  255, 255, 255, 0 };  //subnet mask
EthernetServer server(80);   //web server port
String HttpHeader = String(MaxHeaderLength); 


void setup(){
  //enable serial monitor
  Serial.begin(9600);
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
   //initialize variable
  HttpHeader="";

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
         char c = client.read();
         //read MaxHeaderLength number of characters in the HTTP header
         //discard the rest until \n
         if (HttpHeader.length() < MaxHeaderLength)
         {
           //store characters to string
           HttpHeader = HttpHeader + c; 
         }
         //if HTTP request has ended
         if (c == '\n') { 
           // show the string on the monitor
           Serial.println(HttpHeader);
          // start of web page
           client.println("HTTP/1.1 200 OK");
           client.println("Content-Type: text/html");
           client.println("<html><head></head><body>");
           client.println();
           client.print("<form method=get>");
           client.print("<input type='radio' name=r value='1'> One
");
           client.print("<input type='radio' name=r value='2' checked> Two
");
           client.print("<input type='radio' name=r value='3'> Three
");
            client.print("<input type=submit value=submit></form>");
           client.print("</body></html>");
           //clearing string for next read
           HttpHeader="";
           //stopping client
            client.stop();
         }
       }
     }
   }

}

Pindari, Thanks for the excellent write up. I just got my arduino and dying to understand what you did. Now off to try the code...