1

I'm currently learning how to develop HTTP proxy using libcurl. Upon I successfully got HTTP responses, I wrote them into a string before I do further process using callback function. In the further process function, I need to convert those string into char* at first which leaded to a losing data problem for those HTTP responses contain image data like png and gif. While rest of HTTP responses contain pure text data like HTML and css were working fine.

My query and question is why the c_str() function eliminated those unreadable data like image data during conversion? Is there any way to solve this losing data problem?

Code: char* sData_source_ ;

void Client::send(string msg)
{
   sData_source_ = (char*)msg.c_str();
   cout << "Your string is " << strlen(sData_source_)<<endl; 
}

Output: Sending HTTP Response[608]: FD:9 HTTP/1.1 200 OK Date: Wed, 29 Aug 2012 00:58:25 GMT Server: Apache/2.2.16 (Debian) Last-Modified: Tue, 28 Aug 2012 18:34:36 GMT ETag: "13e4735-136-4c857b1b54700" Accept-Ranges: bytes Keep-Alive: timeout=15, max=99 Content-Type: image/png Content-Length: 310 Connection: keep-alive �PNG

IHDR��o�|d�IT pHYs � �B�4� tEXtSoftwareMacromedia Fireworks MX��*$tEXtCreation Time12/06/04g�m�IDATx���1� E�u��r -�R)�]X֚��w�<Ѱ�1F���������� tX��!�Z��=:$TJ��{�3�CRgb:$v4v�Cb��(���B��!tH�L�[k�_wx8/:,@����� xQ�2]�|��IEND�B`� Your string is 306

Note: As you guys can observe from above output that the total HTTP response is 608 bytes initially. However, it becomes 306 after conversion using c_str() function.

Thank you and looking forward to someone reply. :D

Paul Peng
  • 31
  • 1
  • 5
  • 3
    Image data like *gif* and *png* can contain `0` as data which `strlen` treats as end of string `null` terminator.You should not rely on `strlen()` for this instead you should keep track of the data bytes separately. – Alok Save Aug 29 '12 at 10:15
  • Your explicit conversion to `char *` is useless, `c_str()` returns a `const char *`. Besides that I'm upvoting since I'm very curious to see the answer to this question. – Jean-Marie Comets Aug 29 '12 at 10:17
  • 1
    As mentioned by @Als you cannot rely on strlen(), instead of it, use the `size` method of your `msg` string; this method must return the correct size; in the other hand, if you're working with raw data not with characters, [use the `data()` method instead of the `c_str()` mehtod](http://stackoverflow.com/questions/194634/string-c-str-vs-data). – PaperBirdMaster Aug 29 '12 at 10:26
  • 2
    A potentially bigger problem is that you're storing a pointer to a local object, which will be destroyed when the function returns. You need to ensure that the string outlives any usage of `sData_source_` (or change that to a `std::string`, or restructure your code to avoid static storage). – Mike Seymour Aug 29 '12 at 10:52
  • Thanks to your guys comments, I solved the problem. – Paul Peng Aug 30 '12 at 08:50

2 Answers2

3

Looks like you trying to treat a binary file as a string.

As soon as a \0 terminator is encountered, the string will end. Consider the following:

const char* foo = "abc\012345667";
int length = strlen(foo);

The length is 3, as the original string has been terminated after 3 characters.

Aesthete
  • 18,622
  • 6
  • 36
  • 45
  • Yes, Aesthete.You are right for the route cause. Since I deal with raw data instead of characters sometimes, I need to use data() method instead of c_str() as mentioned by PaperBirdMaster in above comments. – Paul Peng Aug 30 '12 at 08:53
0

Here is the solution after I modified my code, just want to share with others who may deal with same problem in future.

 size_t SData_length; 

 void Client::send(string msg)
 {
    sData_length = msg.size(); 

    // allocate memory for sData_source
    sData_source_ = (char*)malloc(sData_length);

    // copy data to sData_source
    memcpy(sData_source_, msg.data(), sData_length); 

    // compare data after copy
   if(memcmp(sData_source_, msg.data(), sData_length) == 0)
   {
    cout<<"Copy Data Succeed"<<endl;
   }
}
Paul Peng
  • 31
  • 1
  • 5