lasselukkari / aWOT

Arduino web server library.
MIT License
283 stars 41 forks source link

Parse Multiple Query parameters of POST request #140

Closed kine90 closed 2 years ago

kine90 commented 2 years ago

Hi LAsse,

Thanks one more time for this library! I am having an unexpected behaviour with the parametrized function request::query to parse the data sent from a POST form, is there any exemple on this? Shorly, I can´t get the function to find any of the parameters in the url.

Here is the part of my code, with plenty of Serial.prints to figure out what´s going on:

void EthWebManager::handle_save(Request &req, Response &res) { String page = FPSTR(HTTP_BEGIN); page.replace("{pageTitle}","Settings received"); page += FPSTR(SETTINGS_RECEIVED_BODY); page += FPSTR(FOOTER); page += FPSTR(REDIRECT_SCRIPT); page.replace("{timeoutS}","12"); page.replace("{timeoutms}","12000"); page.replace("{target}","/"); page += FPSTR(HTML_END); res.set("Content-Type", "text/html"); res.print(page); Serial.println(req.readString()); for (unsigned int i = 0; i < _paramsCount; i++) { Serial.print("Looking for par: "); Serial.print(_params[i]->getName()); Serial.print(", old val: "); Serial.println(_params[i]->_value); Serial.println(req.query(_params[i]->getName(), _params[i]->_value, _params[i]->getValueLength())); Serial.print("New val: "); Serial.println(_params[i]->_value); } }

Here is the corresponding serial output: SensorReleaseTime=10&Freelights=%2300ff00&Busylights=%23ff0000&PulseDuration=15&BusyPulseRange=120&Freepulserange=40&EthIP=192.168.5.240&EthGateway=192.168.5.1&EthSubnet=255.255.255.0&EthDNS=8.8.8.8&Pod1Ch1MAC=4C%3A75%3A25%3AC3%3A06%3A18&Pod1Ch2MAC=4C%3A75%3A25%3AC1%3AB1%3A08&Pod2Ch1MAC=AC%3A0B%3AFB%3A6E%3AF3%3A1C&Pod2Ch2MAC=4C%3A75%3A25%3AC1%3A61%3AF8&Pod3Ch1MAC=4C%3A75%3A25%3AC4%3A1D%3A88&Pod3Ch2MAC=4C%3A75%3A25%3AC1%3A2A%3A48&Usr=user&Pas=password&submit= Looking for par: SensorReleaseTime, old val: 10 0 New val: Looking for par: Freelights, old val: #00ff00 0 New val: Looking for par: Busylights, old val: #ff0000 0 New val: Looking for par: PulseDuration, old val: 15 0 New val: Looking for par: BusyPulseRange, old val: 120 0 New val: Looking for par: Freepulserange, old val: 40 0 New val: Looking for par: EthIP, old val: 192.168.5.240 0 New val: Looking for par: EthGateway, old val: 192.168.5.1 0 New val: Looking for par: EthSubnet, old val: 255.255.255.0 0 New val: Looking for par: EthDNS, old val: 8.8.8.8 0 New val: Looking for par: Pod1Ch1MAC, old val: 4C:75:25:C3:06:18 0 New val: Looking for par: Pod1Ch2MAC, old val: 4C:75:25:C1:B1:08 0 New val: Looking for par: Pod2Ch1MAC, old val: AC:0B:FB:6E:F3:1C 0 New val: Looking for par: Pod2Ch2MAC, old val: 4C:75:25:C1:61:F8 0 New val: Looking for par: Pod3Ch1MAC, old val: 4C:75:25:C4:1D:88 0 New val: Looking for par: Pod3Ch2MAC, old val: 4C:75:25:C1:2A:48 0 New val: Looking for par: Usr, old val: user 0 New val: Looking for par: Pas, old val: password 0 New val:

You can see the complete query and the names I am asking the function to look for.

Digging deeper I had a look at the declaration of your query function, I can´t really understand how it works, but looks like it is never entering the while loop. I have modified it to add a serial output:

bool Request::query(const char name, char buffer, int bufferLength) { memset(buffer, 0, bufferLength);

char *position = m_query; int nameLength = strlen(name);

while ((position = strstr(position, name))) { Serial.println("QueryWhileLooping"); char previous = *(position - 1);

if ((previous == '\0' || previous == '&') &&
    *(position + nameLength) == '=') {
  position = position + nameLength + 1;
  while (*position && *position != '&' && --bufferLength) {
    *buffer++ = *position++;
  }

  return bufferLength > 0;
}

position++;

} Serial.println("Query exited while loop"); return false; }

And it seems to confirm my hypotesis....

SensorReleaseTime=10&Freelights=%2300ff00&Busylights=%23ff0000&PulseDuration=15&BusyPulseRange=120&Freepulserange=40&EthIP=192.168.5.240&EthGateway=192.168.5.1&EthSubnet=255.255.255.0&EthDNS=8.8.8.8&Pod1Ch1MAC=4C%3A75%3A25%3AC3%3A06%3A18&Pod1Ch2MAC=4C%3A75%3A25%3AC1%3AB1%3A08&Pod2Ch1MAC=AC%3A0B%3AFB%3A6E%3AF3%3A1C&Pod2Ch2MAC=4C%3A75%3A25%3AC1%3A61%3AF8&Pod3Ch1MAC=4C%3A75%3A25%3AC4%3A1D%3A88&Pod3Ch2MAC=4C%3A75%3A25%3AC1%3A2A%3A48&Usr=user&Pas=password&submit= Looking for par: SensorReleaseTime, old val: 10 Query exited while loop 0 New val: Looking for par: Freelights, old val: #00ff00 Query exited while loop 0 New val: Looking for par: Busylights, old val: #ff0000 Query exited while loop 0 New val: Looking for par: PulseDuration, old val: 15 Query exited while loop 0 New val: Looking for par: BusyPulseRange, old val: 120 Query exited while loop 0 New val: Looking for par: Freepulserange, old val: 40 Query exited while loop 0 New val: Looking for par: EthIP, old val: 192.168.5.240 Query exited while loop 0 New val: Looking for par: EthGateway, old val: 192.168.5.1 Query exited while loop 0 New val: Looking for par: EthSubnet, old val: 255.255.255.0 Query exited while loop 0 New val: Looking for par: EthDNS, old val: 8.8.8.8 Query exited while loop 0 New val: Looking for par: Pod1Ch1MAC, old val: 4C:75:25:C3:06:18 Query exited while loop 0 New val: Looking for par: Pod1Ch2MAC, old val: 4C:75:25:C1:B1:08 Query exited while loop 0 New val: Looking for par: Pod2Ch1MAC, old val: AC:0B:FB:6E:F3:1C Query exited while loop 0 New val: Looking for par: Pod2Ch2MAC, old val: 4C:75:25:C1:61:F8 Query exited while loop 0 New val: Looking for par: Pod3Ch1MAC, old val: 4C:75:25:C4:1D:88 Query exited while loop 0 New val: Looking for par: Pod3Ch2MAC, old val: 4C:75:25:C1:2A:48 Query exited while loop 0 New val: Looking for par: Usr, old val: user Query exited while loop 0 New val: Looking for par: Pas, old val: password Query exited while loop 0 New val: Now manually BusyPulseRange: Query exited while loop 0

kine90 commented 2 years ago

I continued investigating and I have fount that for some reason the m_query parameter used in the function query() to initialize *position is actually pointing to an empty string. I guess it is because I am using the POST method to send the compiled form (it contains password and other sensible stuff).

Anyway, I made a copy of your function, modified it to be able to pass inside a copy of the complete request. char reqCopy[800]; req.readBytes(reqCopy,800); myQuery(reqCopy, _params[i]->getName(), _params[i]->_value, _params[i]->getValueLength()));

Performing the search on the requst copy works as expected!

lasselukkari commented 2 years ago

To me it seems that you are trying to use the query function to read parameters from the request body? Am I correct?

The query function is used for reading parameter from the request url like /path/of/route?parameterName=parameterValue. See: https://en.wikipedia.org/wiki/Query_string

If you want to read the parameters from the post body use the form function. The tests show you how it works. As the body has no size limits the function works in different way than the query function. You can't read a parameters by name. Instead the function will read the next name and value pair every time you call it. Here is an example of the function being used in one of my projects: https://github.com/lasselukkari/AirMonitor/blob/master/AirMonitorServer/AirMonitorServer.ino#L175-L191

kine90 commented 2 years ago

Hi Lasse, Thanks a lot for your support and your awesome work! You are right, sorry for disturbing you. It took me a while but eventually I´ve figured out the error was exactly what you described. For now I got it working passing the response string as argument, but I will switch to the example you provided. Thanks again!

lasselukkari commented 2 years ago

I'm happy to hear you got it working!