bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.73k stars 1.12k forks source link

DynamicJsonBuffer leads to exceptions #191

Closed sukhmeet032795 closed 8 years ago

sukhmeet032795 commented 8 years ago

Hi,

I have two urls i.e /upload and /checkout. On making an api call to /upload, i get a json which is similar to the one shown below. This json is stored using Dynamic Json Buffer. On basis of this , at success i make another api call to /checkout and i get another json which i again store using DynamicJsonBuffer. My Code is:

{
    "status": "OK",
    "online_payment": true,
    "payments_available": [
        {
            "sub_text": null,
            "image_url": "http://s27.postimg.org/rqnb7w0dr/logo.png",
            "type": "Wallet",
            "id": 3,
            "name": "payu"
        },
        {
            "sub_text": "Some text",
            "image_url": "http://s27.postimg.org/rqnb7w0dr/logo.png",
            "type": "Wallet",
            "id": 2,
            "name": "paytm_wallet"
        },
        {
            "sub_text": "Yo PAL !!",
            "image_url": "http://s27.postimg.org/rqnb7w0dr/logo.png",
            "type": "Gateway",
            "id": 1,
            "name": "payu"
        }
    ],
    "sale_string": "",
    "deliver_now": true,
    "enable_discount": true,
    "stored_cards": [],
    "paytm_cashback": "",
    "chat_enabled": true,
    "autodebit_enabled": false,
    "discount_details": {},
    "basket": [
        {
            "sale_price_changed": false,
            "qt": 3,
            "sst": "",
            "mrp": 37,
            "attributes": "Carton,100 GM",
            "product_image": "http://url.s3.amazonaws.com/images/product/FOODAI0156181/0/FOODAI0154536181_150x150.jpg",
            "out_of_stock": false,
            "sale_price": 36.5,
            "product_title": "Amul Butter",
            "product_id": 156181
        },
        {
            "sale_price_changed": false,
            "qt": 2,
            "sst": "",
            "mrp": 140,
            "attributes": "200 GM",
            "product_image": "http://url.s3.amazonaws.com/images/product/FOODAI0157986/0/FOODAI01344557986_150x150.jpg",
            "out_of_stock": false,
            "sale_price": 138,
            "product_title": "Amul A+ Cheese Slice",
            "product_id": 157986
        }
    ],
    "cash_points": 0,
    "paytm_snackbar_text": "The amount will be debited on delivery.",
    "msg": "Cart updated/created",
    "payment_offers": {
        "cc": "",
        "payumoney": "10% cashback",
        "paytmwallet": "15% cashback",
        "dc": "",
        "netbanking": ""
    },
    "slots_available": true,
    "fetch_card_payload": {
        "url": "https://info.payu.in/merchant/postservice.php?form=2",
        "payload": {
            "var1": "",
            "command": "get_user_cards",
            "hash": "",
            "key": ""
        }
    },
    "cart_id": 6492
}

The length of the json is not fixed, it may vary depending on the number of products int the basket. I was using DynamicJsonBuffer for storing the json but it causes exceptions

My code is:

void sendUploadRequest() {

  String section="header";
  String responce="";
  String httpCode="";

  blinkLed.attach(0.6, blink);
  delay(1000);

  StaticJsonBuffer<200> jsonBuffer;

  JsonObject& jsonData = jsonBuffer.createObject();

  JsonArray& products = jsonData.createNestedArray("products");

  JsonObject& product1 = jsonBuffer.createObject();
  product1["product_id"] = 156181;
  product1["qt"] = 3;
  product1["sale_price"] = 36.5;
  products.add(product1); 

  JsonObject& product2 = jsonBuffer.createObject();
  product2["product_id"] = 157986;
  product2["qt"] = 2;
  product2["sale_price"] = 138;
  products.add(product2);  

  jsonData["session_id"] = "c6rqhv7untwmk1a";
  jsonData["zone_id"] = 4;

  int len = jsonData.measureLength();

  char buffer[256];
  jsonData.printTo(buffer, sizeof(buffer));

//  Serial.println(buffer);

//  const char server[] = "url.com";
//  String PostData = "{ 'products': '[ { 'product_id' :156181, 'qt' :3, 'sale_price' :36.5}, { 'product_id' :157986, 'qt' :2, 'sale_price' :138} ]', 'session_id' : 'c6rqhv7untwmk1a' , 'zone_id':4 }";
  if (client.connect(host, 80)) {

    client.println("POST /user/cart/bulk_upload/ HTTP/1.1");
    client.println("Host:url");
    client.println("Cache-Control: no-cache");
    client.print("Content-Length: ");
    client.println(len);
    client.println();
    client.println(buffer);
    while(!client.available()){
      int timeout = millis() + 5000;
      while (client.available() == 0) {
        if (timeout - millis() < 0) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return;
        }
      }    
    }

    while (client.connected())
    {
      if ( client.available() )
      {
        if(section == "header"){

          String line = client.readStringUntil('\r');
          if(line == "\n"){

            section="json";
          }

          if(httpCode.length() == 0){

            httpCode=line.substring(9, 12);
          }
        }
        else if(section=="json"){

          String line = client.readStringUntil('\n');
          responce=line;
        }
      }      
    }

    if(httpCode == "200"){

      int size = responce.length() + 1;
      char responceJson[size];
      responce.toCharArray(responceJson, size);

      DynamicJsonBuffer json;
      JsonObject &json_parser = json.parseObject(responceJson);

      const char* sta= json_parser["status"];
      Serial.println(sta);

      const char* sta1="OK";
      if (sta != sta1){

        Serial.println("in");
        sendCheckoutRequest();
      }
    }  

    Serial.println(httpCode);
    client.stop();

  } 
  else {

    Serial.println("Connection failed");
    Serial.println("Disconnecting.");
    client.stop();
  }
  blinkLed.detach();
  digitalWrite(2, LOW);
}

On success it calls sendCheckoutRequest, which is:

void sendCheckoutRequest() {

//  blinkLed.attach(0.6, blink);
//  delay(1000);
//  const char server[] = "u";

  String section="header";
  String responceCheckout="";
  String httpCodeCheckout="";

  String PostData = "asap=true&session_id=c6rqhv7untwmk1a&zone_id=4";
  if (client.connect(host, 80)) {

    client.println("POST /user/checkout/ HTTP/1.1");
    client.println("Host: url");
    client.println("Cache-Control: no-cache");rl
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.print("Content-Length: ");
    client.println(PostData.length());
    client.println();
    client.println(PostData);
    while(!client.available()){
      int timeout = millis() + 5000;
      while (client.available() == 0) {
        if (timeout - millis() < 0) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return;
        }
      }    
    }

    while (client.connected())
    {
      if ( client.available() )
      {
        if(section == "header"){

          String line = client.readStringUntil('\r');
          if(line == "\n"){

            section="json";
          }

          if(httpCodeCheckout.length() == 0){

            httpCodeCheckout=line.substring(9, 12);
          }
        }
        else if(section=="json"){

          String line = client.readStringUntil('\n');
          responceCheckout=line;
        }
      }      
    }

    Serial.println(responceCheckout);

//    if(httpCode == "200"){
//
      int size = responceCheckout.length() + 1;
      char responceCheckoutJson[size];
      responceCheckout.toCharArray(responceCheckoutJson, size);

      DynamicJsonBuffer json;
      JsonObject &data = json.parseObject(responceCheckoutJson);

      data.printTo(Serial);
      const char* stat= data["status"];
      Serial.println(stat);
//      
//      if (sta == "OK"){
//
//        Serial.println("Successful");
//      }
//    }  
//     
//    Serial.println(httpCode);
    client.stop();

  } 
  else {

    Serial.println("Connection failed");
    Serial.println("Disconnecting.");
    client.stop();
  }
//  blinkLed.detach();
  digitalWrite(2, LOW);
}

Now when i store another json, i get exceptions as:

ctx: sys 
sp: 3ffefa10 end: 3fffffb0 offset: 01a0

>>>stack>>>
3ffefbb0:  3ffefe34 3fff3f84 3fff3f84 4020c244  
3ffefbc0:  3ffefc40 00000000 3ffefbac 40207f24

How can i resolve this? Is it possible to store the jsons in same static memory by erasing other one from memory? How can i use StaticJsonBuffer to accomplish this job successfully..

Need urgent help.Thanks in advance.

bblanchon commented 8 years ago

I'll assume you're running on an ESP8866.

The DynamicJsonBuffer release the memory as soon as it's out of scope, so whar you're doing is good.

Since you know the that the JSON is big, you should specify an initial capacity to the constructor. the default is 256B, you can easily push it to 4064.

But I can see that you're loosing a lot of memory by duplicating the strings.

Instead of this:

int size = responceCheckout.length() + 1;
char responceCheckoutJson[size];
responceCheckout.toCharArray(responceCheckoutJson, size);
DynamicJsonBuffer json;
JsonObject &data = json.parseObject(responceCheckoutJson);

You should do this:

DynamicJsonBuffer json(4096);
JsonObject &data = json.parseObject(const_cast<char*>(responceCheckout.c_str()));

But I'm not sure, this is the reason of the crash... Can you please locate the line of the exception more precisely? Can you please check how much memory is available when those function starts? Can you please print the jsonBuffer.size() after the parse?

Also, have a look at #168, #179, #184, #119 and FAQ

sukhmeet032795 commented 8 years ago

Thanks for a quick reply.

I tried what you suggested, the size comes out to be 1204....and i looking out for the exception line......meanwhile thanks a ton

Btw is DynamicJsonBuffer json(4096) taking the same memory everytime i re-declare it or takes a new memory?

bblanchon commented 8 years ago

If you do this:

{
    DynamicJsonBuffer buffer1(4096);
    // [...]
}

{
    DynamicJsonBuffer buffer2(4096);
    // [...]
}

Then it's very likely that buffer1 and buffer2 will use the exact same 4096 bytes of heap.

However, if you do this:

{
    DynamicJsonBuffer buffer1(4096);
    // [...]

    DynamicJsonBuffer buffer2(4096);
    // [...]
}

then in this case buffer1 and buffer2 will be in memory at the same time and therefore use 8192 bytes of heap.

sukhmeet032795 commented 8 years ago

Hey.was out of town

Thanks for all the help..appreciate it a lot

Skhatavkar commented 6 years ago

dynamicjsonbuffer does not have a name type