Лучший способ разобрать входящий HTTP пост-запрос на Arduino? - PullRequest
0 голосов
/ 26 марта 2020

Я пишу простой HTTP-сервер на моем Arduino Uno Wifi Rev2 для обработки входящего HTTP-запроса POST в формате JSON.

Вот как я отправляю HTTP-запрос (с JSON) от моего клиента:

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

Это строка, которую получает веб-сервер Arduino:

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}

Я использую Ника Гаммона Библиотека Arduino Regexp для анализа этого запроса, проверки его и извлечения данных JSON.

Это работает, но синтаксический анализ HTTP-запроса таким образом чрезвычайно хрупок и кажется хакерским. Это может легко сломаться, если другой клиент переупорядочит / пропустит заголовок или пропустит символы возврата каретки. Это ужасное регулярное выражение, которое я использую для проверки:

    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*}";

Есть ли лучший / рекомендуемый способ проверки и анализа HTTP-запроса? Это должно быть проблемой, с которой другие уже столкнулись и решили. Если возможно, опубликуйте фрагмент кода, решающий эту проблему.

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Как стартер:
Сначала отправьте правильный (синтаксис!) Тестовый запрос

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

есть множество отличных примеров, если вы выполните поиск:

arduino webserver ethe rnet library

в вашем любимом поисковике.
Один из них: https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/
или вы используете библиотеку веб-сервера из esp8266 и адаптируете ее (не совсем hard imho)
вы бы сделали на Arduino что-то вроде

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

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

функция будет выглядеть (частично рабочий код, частично псевдокод)

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 реализовали этот вид логики c в некоторых реальных сценариях ios, и все они работают надежно и стабильно уже несколько лет. Последний совет:
Никогда не используйте класс Arduino String в сценарии веб-сервера Arduino ios. Класс String ломает вашу кучу и разбивает Arduino. В моем примере я использую фиксированные символы, которые компилируются в стек и сохраняют вашу память счастливой.

0 голосов
/ 26 марта 2020

Связанная библиотека Regexp основана на Lua, в котором есть интересный оператор сопоставления с образцом

% b () сбалансированная вложенная пара (... (...) ...)

Затем, чтобы получить сбалансированное выражение фигурных скобок в конце HTTP-запроса, используйте выражение

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

Как указано в комментариях, это не означает, что Захват действителен JSON. Следующим шагом будет передача захваченной подстроки в анализатор JSON для проверки.

...