Skip to content

Why http POST form allows only 32 postArgs elements? #3284

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

Open
drschlaumeier opened this issue May 23, 2017 · 7 comments
Open

Why http POST form allows only 32 postArgs elements? #3284

drschlaumeier opened this issue May 23, 2017 · 7 comments

Comments

@drschlaumeier
Copy link

Basic Infos

My Webserver Configuration Page needs to POST a form with >32 elements. Why ESP8266WebServer::_parseForm allows only 32 postArgs elements?

Hardware

Hardware: ESP-8285
Core Version: 2.4.0 ...

Description

I'm building a WebServer around my home light control based on Sonoff Touch device. The flexible configuration page of the webserver uses a html page with form and tables filled with some postArgs elements (some input - type text, some select, some input - type checkbox). All together I have 37 postArgs elements to POST back to my WebServer. After long debugging the esp CRASH I found that the ESP8266WebServer::_parseForm allows only 32 postArgs elements. ... see below code from "Parsing.cpp"
Why only 32? Can someone change to higher value? Any other idea what I can do? Is splitting the config page into several pages the right way?

Thanks in advance

bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
  (void) len;
#ifdef DEBUG_ESP_HTTP_SERVER
  DEBUG_OUTPUT.print("Parse Form: Boundary: ");
  DEBUG_OUTPUT.print(boundary);
  DEBUG_OUTPUT.print(" Length: ");
  DEBUG_OUTPUT.println(len);
#endif
  String line;
  int retry = 0;
  do {
    line = client.readStringUntil('\r');
    ++retry;
  } while (line.length() == 0 && retry < 3);

  client.readStringUntil('\n');
  //start reading the form
  if (line == ("--"+boundary)){
    RequestArgument* postArgs = new RequestArgument[32];
    int postArgsLen = 0;
    while(1){
      String argName;
      String argValue;
      String argType;
      String argFilename;
      bool argIsFile = false;

.......

Settings in IDE

Module: Generic ESP8266 Module
Flash Size: 1MB
CPU Frequency: 80Mhz
Flash Mode: DOUT
Flash Frequency: 40Mhz
Upload Using: OTA / SERIAL
Reset Method: ck

################################################

@igrr
Copy link
Member

igrr commented May 24, 2017

The value of 32 was chosen as a compromise between supporting forms with a lot of fields and not having to allocate large postArgs array.

Possible solutions:

  • introduce a run-time setting (e.g. ESP8266WebServer::setMaxPostArgs(size_t))
  • do a two-pass parsing: count the number of arguments on the first pass, allocate the array, fill it on the second pass
  • replace an array with a vector which will grow dynamically as the arguments are added

@drschlaumeier
Copy link
Author

Many thanks.
I personally prefer the third solution since i do not need to care on setting the max postArgs and not wasting time with two-pass.
However, I manually changed to postArgs array to 64 for now. Waiting for enhancement ...

@igrr
Copy link
Member

igrr commented May 24, 2017

Please feel free to submit a PR with the 3rd solution :)

@drschlaumeier
Copy link
Author

Hmm, I somehow expected that comment :-)
I'm not a good c programmer but I can try ...The first solution is easy :-) The third is tricky ... e.g. to catch all the possible errors.
Can I PR the first solution ?

@devyte
Copy link
Collaborator

devyte commented Sep 6, 2017

@drschlaumeier using a std::vector is far easier than an array that gets allocated/deallocated. For this, you would need something along these lines:
#include
...

replace:

  int              _currentArgCount;
  RequestArgument* _currentArgs;

with
std::vector<RequestArgument> _currentArgs;

Don't init _currentArgs(0) in the constructor, don't alloc it anywhere, clear it wherever it gets deleted.

Replace references to _currentArgCount with _currentArgs.size().

When a new RequestArgument is added, do something like this:
_currentArgs.emplace_back(key, value);

Likely some additional changes, but the above should cover the important stuff.

Be aware that there is currently a bug in Arduino.h that makes #include not compile sometimes. To make certain:

#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include <vector>

@yoursunny
Copy link
Contributor

Be aware that there is currently a bug in Arduino.h that makes #include not compile sometimes. To make certain:
#undef min
#undef max

I wonder why Arduino.h #defines min and max, instead of using standard library's version?

#include <algorithm>
using std::min;
using std::max;

@devyte
Copy link
Collaborator

devyte commented Aug 18, 2018

@yoursunny that has already been fixed, and 3rd party libs have also been fixed to comply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants