• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 273
  • Last Modified:

Write a file to a socket issue

Hello,
I am working on an HTTP response object, and have run into a problem when trying to send a file back. Everything works fine for text based files, but the moment I try to send a binary (lets say an image for example), I get garbage all over the server screen, and nothing out to the browser.

The code is attached.

Fix worth 500 points.

Thanks,
Rick
void Response::output (std::string out)
{
    //write the data to the socket
    int toSend = out.length();
    int sent = 0;

    std::cout << out;
    
    while (sent < toSend)
    {
        int tmp = write(client,out.c_str(),out.length());
        
        sent += tmp;
        
        out.erase(0,tmp);
    }
}

void Response::httpSendFile(std::string path)
{
    //open a file, and transfer it as a stream
    std::ifstream myReadFile;

    myReadFile.open(path,std::ios::binary);

    if (myReadFile.is_open())
    {
        int begin = myReadFile.tellg();

        myReadFile.seekg (0, std::ios::end);

        int end = myReadFile.tellg();

        int lng = end - begin;

        myReadFile.seekg (0);

        int start = path.find_last_of(".");

        std::string mime = determineMimeType(path.substr(start,path.length()));

        output("HTTP/1.1 200 OK\r\n");
    
        //get the current date/time
        std::string now = asctime(localtime(new time_t()));
    
        output("Date: " + now);

        output("Server: HTTP Service 1.1\r\n");
        output("Content-Type: " + mime + "\r\n");
        
        if (cookie.length() > 0)
            output("Set-Cookie: " + cookie + "\r\n");

        std::stringstream length;

        length << lng;

        output("Content-Length: " +  length.str() + "\r\n\r\n");

        char tmp[4096];

        while (!myReadFile.eof())
        {
            myReadFile >> tmp;
            output(tmp);
        }
        
        myReadFile.close();
    }
    else
    {
        sendBadHeader("404 Not Found");
    }

}

Open in new window

0
richardsimnett
Asked:
richardsimnett
  • 3
1 Solution
 
jkrCommented:
HTTP is a text based protocol and binary data has to be base64-encoded so it can be sent using it.  See e.g. http://www.adp-gmbh.ch/cpp/common/base64.html ("Encoding and decoding base64 with C++") and/or http://www.codeproject.com/KB/cpp/base64coding.aspx ("Base64 Encoding and Decoding")
0
 
jkrCommented:
Oh, and since it recently became common here that once an issue (here base64) was addressed with an example that other experts come forth with even more examples ("Hey, that is only slightly different, but try it anyway!") without having contributed to the original issue, we might as well cover up all other possibilites in this context: http://www.google.com/q=base64+encode+C%2B%2B
0
 
richardsimnettAuthor Commented:
jkr,
let me ask you a question. is base 64 encoding the same as url encoding / decoding?
0
 
jkrCommented:
It looks a similar way, yet it is not the same - see http://en.wikipedia.org/wiki/Percent-encoding
0
 
Todd GerbertIT ConsultantCommented:
>> HTTP is a text based protocol and binary data has to be base64-encoded so it can be sent using it.

I realize I'm a little late with this, but I think it's probably worth pointing out the above statement is wildly inaccurate, there is no reason your HTTP server can't respond with binary content, it does not need to be Base64-encoded (maybe you were thinking of SMTP).  In fact, if you telnet to www.google.com on port 80 and manually type the HTTP request for the Google logo:
GET /images/logos/ps_logo2.png HTTP/1.1
Host: www.google.com

Open in new window

You can plainly see the web server responds with the raw, unencoded, 8-bit content of of the PNG file.


However, you should make sure you're setting the Content-Type, Content-Length, Transfer-Encoding headers et al properly.  You also can't handle binary data internally in your application as if it were text.  Your Response::output isn't working when you select a binary file because you're trying to pass it into a std::string.  If you changed your Response::output to accept a void* and a count instead of a string (or added an overload to such effect) your code would probably work.
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now