Best way to parse out incoming HTTP post request on Arduino?

不想你离开。 提交于 2021-01-29 13:02:25

问题


I'm writing a simple HTTP webserver on my Arduino Uno Wifi Rev2 to handle an incoming HTTP POST Request in JSON format.

This is how I'm sending the HTTP request (with JSON) from my client:

curl \
--request POST \
--header "Content-Type: application/json" \
--data '{
    "A": "B",
    "C": "D"    
}' \
"http://192.168.4.1/myEndpoint"

This is the string the Arduino web-server receives:

POST /myEndpoint HTTP/1.1\r\nHost: 192.168.4.1\r\nUser-Agent: curl/7.54.0\r\nAccept: */*\r\nContent-Type: application/json\r\nContent-Length: 34\r\n\r\n{\n    "A": "B",\n    "C": "D"    \n}

I'm using Nick Gammon's Arduino Regexp library to parse this request, validate it and extract the JSON data.

This works, but parsing the HTTP request in this way is extremely brittle and feels hacky. It could easily break if a different client re-orders/omits a header or skips the carriage return characters. This is the god-awful regexp I'm using for validation:

    httpRegexp = "POST /myEndpoint HTTP/[%d%.]+%\r%\nHost: 192%.168%.4%.1%\r%\nUser%-Agent: curl/[%d%.]+%\r%\nAccept: %*/%*%\r%\nContent%-Type: application/json%\r%\nContent%-Length: %d+%\r%\n%\r%\n{%s*\"[A-Za-z]+\"%s*:%s*\".+\"%s*,%s*\"[A-Za-z]+\"%s*:%s*\".+\"%s*}";

Is there a better/recommended way for me to validate and parse the HTTP request? This must be a problem that others have already encountered and solved. Please post a code fragment solving this issue if possible.


回答1:


As a starter:
First send a correct (syntax!) test request

curl \
 request POST \
header "Content-Type:application/json" \
data '{"A":"B","C":"D"}' \
"http://192.168.4.1/myEndpoint"

there are tons of excellent examples if you do a search for :

arduino webserver ethernet library

on your favorite search enginne.
One would be: https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/
or you use the webserver library from esp8266 and adapt it (not really hard imho)
you would do on the Arduino something like

webServer.on("/myroute/lighton", HTTP_POST, readJson);

char jsonField[64] = '\0'; //This is a predefined buffer for data handilng

the function would look like (partly working code, partly pseudo code )

bool readJson(){
 if (webserver.args() == 0) return false;  // we could do in the caller an error handling on that
 strcpy (jsonField, webserver.arg(1).c_str());  // here we copy the json to a buffer

 /** Get rid of starting and finishing bracket and copy to */
   strncpy(jsonField , jsonField + 1, strlen(jsonField) - 2);
  jsonField[strlen(jsonField) - 2] = '\0';
   uint16_t maxIndex = strlen(jsonField); // number of characters received - without the brackets
     uint16_t index = 0;
  int16_t nextIndex = 0;
  uint8_t  i = 0;
  // In this routine we get the value pairs e.g. "A":"B"
  while ((nextIndex != -1) && (nextIndex < maxIndex)) {
    nextIndex = indexOf(jsonField, ',', index);

    ... the next step would be to process the value pairs by stripping the " and split on the ':' delimiter --
    if you need just the values = content in your example B and D its easy, 
    you could do 
    if (strcmp (firstValofPair ,'A')==0) valueB = atoi(B); // given B is a number and we have to convert from char to int

    .... some more logic and you have a simple reliable JSON Parser for all kind of web server usage

  }
 return true; // success parsing
}

I have implemented this kind of logic in some real live scenarios and all work reliable and stable for some years now. A final tip:
Never use the Arduino String class in Arduino webserver scenarios. The String class fractures your heap and crashes your Arduino. In my example I use fixed chars which are compiled to the stack and keeps your memory happy.




回答2:


The linked Regexp library is based on Lua, which has an interesting pattern match operator

%b() balanced nested pair ( ... ( ... ) ... )

Then to capture a balanced curly brace expression at the end of the HTTP request, use the expression

"(%b{})%s*$"

As pointed out in the comments, this doesn't mean the capture is valid JSON. The next step would be to pass the captured substring to a JSON parser for validation.



来源:https://stackoverflow.com/questions/60862963/best-way-to-parse-out-incoming-http-post-request-on-arduino

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!