0

I am trying to get json data from a url:

sub.domain.com/rest/getdiscounts?supermarketid=5323

I want to get the data returned from that url. In terminal I can do it like this:

curl --user user:password "http://sub.domain.com/rest/getdiscounts?supermarketid=5323"

I have tried multiple things so far, such as :

static string lastResponse;

size_t server_response_stream(void *ptr, size_t size, size_t nmemb, void *)
{
  lastResponse += (const char*)ptr;
  return size * nmemb;
}

bool get_request(string data1, string& errorDescription)
{
  CURL *curl = curl_easy_init();
  if (curl == NULL)
  {
    errorDescription = "Unable to initialise Curl";
    cout << errorDescription << std::endl;
    return false;
  }
  const string url = "http://sub.domain.com/rest/";
  curl_easy_setopt(curl, CURLOPT_URL, (url + "getdiscounts").c_str());
  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_easy_setopt(curl, CURLOPT_USERPWD, USPA);

  char* dc1 = curl_easy_escape(curl, data1.c_str(), 0);
  string arg = "supermarketid=" + (string)dc1;
  const char* dt = arg.c_str();

  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dt);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(dt));

  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

  lastResponse = "";
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, server_response_stream);

  CURLcode res = curl_easy_perform(curl);

  res = curl_easy_perform(curl);

  if (res != CURLE_OK)
  {
    errorDescription = "Curl call to server failed!";
    cout << errorDescription << std::endl;
    return false;
  }

  curl_easy_cleanup(curl);
  return true;
}

I used as sources this question and this link.

EDIT: Thanks for the help! I started from scratch again and it is working now:

static string responseStr;
size_t write_callback(void *ptr, size_t size, size_t nmemb, void *)
{
  responseStr = (const char*)ptr;
  return size * nmemb;
}

string get_request()
{
  CURL *curl;
  CURLcode res;

  curl = curl_easy_init();
  if (curl)
  {
    curl_easy_setopt(curl, CURLOPT_URL, "http://sub.domain.com/rest/getdiscounts?supermarketid=5323");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_easy_setopt(curl, CURLOPT_USERPWD, CREDENTIALS);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);

    res = curl_easy_perform(curl);

    if (res != CURLE_OK)
    {
      cout << "curl_easy_perform() failed!" << std::endl;
      curl_easy_strerror(res);
      curl_easy_cleanup(curl);
      return "";
    }

    else if (res == CURLE_OK)
    {
      curl_easy_cleanup(curl);
      return responseStr;
    }
  }
}
Community
  • 1
  • 1
Zero
  • 355
  • 1
  • 4
  • 12

1 Answers1

0

The first argument ptr of the CURLOPT_WRITEFUNCTION callback function server_response_stream, points to the data received. That data is not null terminated.

The string += operator must receive a pointer to a null terminated string.

The call lastResponse += (const char*)ptr; is causing undefined behavior. The bytes will have to be appended to the string in a different way. You can append the string character by character, using the arguments size and nmemb to determine the size of the buffer.

2501
  • 25,460
  • 4
  • 47
  • 87
  • Why is this needed?\ – Zero Mar 30 '16 at 12:59
  • @Zero I'm not sure what do you mean by that. Which part is not clear? I explained the problem in the answer. – 2501 Mar 30 '16 at 13:00
  • I mean what is causing the undefined behavoiur when I set lastResponse directly? – Zero Mar 30 '16 at 13:02
  • @Zero The line `lastResponse += (const char*)ptr;` is causing undefined behavior, more specifically the underlying call to the overloaded operator. – 2501 Mar 30 '16 at 13:03