We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Write a file to a socket issue

richardsimnett
on
Medium Priority
283 Views
Last Modified: 2012-05-11
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

Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2012
Commented:
Unlock this solution with a free trial preview.
(No credit card required)
Get Preview
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
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

Author

Commented:
jkr,
let me ask you a question. is base 64 encoding the same as url encoding / decoding?
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
It looks a similar way, yet it is not the same - see http://en.wikipedia.org/wiki/Percent-encoding
Todd GerbertSenior Engineer
CERTIFIED EXPERT
Top Expert 2010

Commented:
>> 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.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a free trial preview!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.