Search code examples
chttpesp32esp-idfcjson

How to handle POST request with JSON payload on ESP32 server?


I am trying to receive json data from http server on ESP32, but I get core panic every time I try to access data inside my json. POST request is done using simple html form:

<form method="post" enctype='text/plain'>
    <fieldset>
        <legend>Fermentation:</legend>
        <input name="type" type="radio" value="Ale" /> Ale <br />
        <input checked="checked" name="type" type="radio" value="Lager" /> Lager <br />
        <label for="primary-duration">Duration of primary</label><br />
        <input name="primary-duration" type="text" value="5" /> <br />
        <input type="submit" value="Submit"><br />

    </fieldset>
</form>

char *buf contains data from POST like this: type=Lager primary-duration=5\0 After reading the data into buf I am parsing it using cJSON

cJSON *root = cJSON_Parse(buf);

and extracting "type" object

const cJSON *typeJSON = cJSON_GetObjectItemCaseSensitive(root, "type");

after getting my cJSON object it is properly recognized as a string by _IsString(), but I get "LoadProhibited" panic when trying to access it.

if (cJSON_IsString(typeJSON) && (typeJSON->valuestring != NULL))
{
    printf("%s", typeJSON->valuestring);
}else if(cJSON_IsString(typeJSON))
{
    ESP_LOGE(SERVER_HANDLER_TAG, "String error: Not a string");
}else
{
    ESP_LOGE(SERVER_HANDLER_TAG, "String error: empty string"); //I am always here, trying to print string (typeJSON->valuestring) results in kernel panic
}

I would be vary thankful for any advice.


Solution

  • Your <form> has attribute enctype='text/plain'; that means that the POST body will not contain data encoded in JSON.

    Indeed, string "type=Lager primary-duration=5" is not valid JSON.

    Unfortunately, enctype='application/json' is not available, so you have to serialize the form's fields manually, and then make a POST request with JSON data.

    For instance:

    <form action="javascript:void(0);">
      <input type="text" id="mytext1" />
      <button onclick="submitData()">Submit</button>
    </form>
    
    <script>
      async function submitData() {
        const mytext1 = document.getElementById("mytext1").value;
    
        const body = { mytext1 };
    
        const response = await fetch("target_page", {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify(body)
        });
    
        // if your server responds with text
        const serverResponse = await response.text();
    
        ...
      }
    </script>