3

I want to write a server side code. It should work with popular browsers and wget. My server check that file exists or not, if exists then browser can download it. But I have some problems. Honestly, I read lots of question-answer (for example: Send binary file in HTTP response using C sockets) but I didn't find out. My browser (Chrome) can get text. But I cannot send any binary data or images etc. I am changing header according to downloading files. But I cannot send a downloadable files yet.

I have some questions.

void *clientWorker(void * acceptSocket) {
     int newSocket = (int) acceptSocket;
     char okStatus[] = "HTTP/1.1 200 OK\r\n"
                       "Content-Type: text/html\r\n"
                       "Connection: close\r\n"
                       "Content-Length: 20\r\n"
                       "\r\n"
                       "s";
     writeLn(newSocket, okStatus);
     const char * fileName = "/home/tyra/Desktop/example.txt";
     sendF(newSocket, fileName);
}

1- If I wouldn't write "s" or something else inokStatus, my message cannot send. I don't understand anything of this.

This is writeLn function :

void writeLn(int acceptSocket, const char * buffer) {
    int n = write(acceptSocket, buffer, strlen(buffer) - 1);
    if (n < 0) {
        error("Error while writing");
    }
}

This is sendF function :

string buffer;
string line;
ifstream myfile(fileName);
struct stat filestatus;
stat(fileName, &filestatus);
int fsize = filestatus.st_size;
if (myfile.is_open()) {
    while (myfile.good()) {
        getline(myfile, line);
        buffer.append(line);
    }
    cout << buffer << endl;
}
writeLn(acceptSocket, buffer.c_str());
cout << fsize << " bytes\n";

A little messy. I haven't used file size yet. If I send a file, then I rearrange these things.

2- I can send text and browser demonstrates it but browser didn't understand new lines. If text file contains (123\n456\n789), browser demonstrates (123456789). I think I should change Content-Type header, but I didn't find out.

I don't want that browser demonstrates text files. Browser should download it. How can I send downloadable files?

Sorry, I explain everything pretty complicated.

6
  • I think one of the problems is that okStatus[] has no zero-termination char at the end. Try adding it to the end, instead of 's' Commented May 25, 2011 at 10:51
  • @Tony The Tiger Thanks for helping. I tried and it didn't work. Commented May 25, 2011 at 10:54
  • @Tony The Tiger Literal strings are automatically null-terminated Commented May 25, 2011 at 11:02
  • I don't know if its relevant, but the Connection: close part of okStatus is only followed only by a \n. It should be followed by \r\n. Commented May 25, 2011 at 11:04
  • @Andy, hmmm I wasn't entirely sure. Commented May 25, 2011 at 11:05

3 Answers 3

2

As to your first question, you should find out the exact size of the file and specify it in your "Content-Length: xxxx\r\n" header. And, of course, you should ensure that the data is sent completely out.

Indeed, in your writeF function you use a std::string as a buffer:

string buffer;

this is not appropriate for binary data. You should allocate a raw char array of the right size:

int fsize = file.tellg();
char* buffer = new char[fsize];
file.seekg (0, ios::beg);
file.read (buffer, size);
file.close();

As to the second point, when your data is not HTML, specify as Content-Type: text/plain; otherwise, your carriage return should be represented by <br> instead of "\r\n".

In case of binary downloads, to have the data download as a file (and not shown in the browser), you should specify

Content-Type: application/octet-stream
Sign up to request clarification or add additional context in comments.

5 Comments

Hello sergio. If I send binary data, chrome or firefox automatically download it?
Hello Thorn, see my edit. You need the Content-Type: application/octet-stream
Can I send rar file or something else with the same method (getline()) by changing only Content-Type?
Thorn, sure you can send rar files. Anyway, the getline approach is not the best. See my edit for code snippet specific to binary data.
If I want to send a downloadable file, I should send it in binary form, am I right? In this way, we can obtain a file which is identical with on the server? (not losing '\n')
1

The issue is strlen here. strlen terminates when it gets a '\0' character. In binary file you will have a number of '\0' characters.

While reading the file you should find out the file size. This size should be used in int n = write(acceptSocket, buffer, strlen(buffer) - 1); in place of strlen

Change the writeLn(acceptSocket, buffer.c_str()); to writeLn(acceptSocket, buffer.c_str(), buffer.size()); and try...

For the case of 123\n456\n789 you need to send <PRE>123\n456\n789</PRE> as browser will parse this text as html and not like the OS parses and shows the output. The other way you can do is replace all \n with <BR> ...

7 Comments

Hello. Thanks for the answer. My first question is solved by your helping. I changed it and it works. About my second question, I do not want to demonstrate the text, browser should download it. I think I should change Content-Type and I send it right way (not getline), I do not know.
@Thom If the browser is able to parse mime "text/html" it's very likely that he'll do that as it is more convenient. But there is a way around: use the headers to indicate you want a download with Content-Disposition: attachment;filename="test.jpg". See apptools.com/phptools/force-download.php for more details. It's php but the main http concepts still apply.
I'm not sure if I got it. I assume that you want your text file to be downloaded not displayed on the browser. In that case as @RedX suggested you need to use Content-Disposition: attachment;filename="test.txt".
@Thorn: You can have a look at this article Content-Type. Its a nice read
@RedX Thank you for advice. It works. Your link is very helpful. @Mayank Exactly:)
|
0

Regarding question 1 - if you don't want to send any content back then remove the s from the end of okStatus and specify Content-Length: 0\r\n in the header

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.