Of course, there's that payload part.
- Everything beyond the response header and that blank line is considered payload—that's the file, the JSON, the HTML, the image, the cat video.
- Every single byte that comes through should be replicated, in order, to a local copy.
static string getFileName(const string& path) {
if (path.empty() || path[path.size() - 1] == '/') {
return "index.html"; // not always correct, but not the point
}
size_t found = path.rfind('/');
return path.substr(found + 1);
}
static const size_t kBufferSize = 1024; // just a random, large size
static void savePayload(iosockstream& ss, const string& filename) {
ofstream output(filename, ios::binary); // don't assume it's text
size_t totalBytes = 0;
while (!ss.fail()) {
char buffer[kBufferSize] = {'\0'};
ss.read(buffer, sizeof(buffer));
totalBytes += ss.gcount();
output.write(buffer, ss.gcount());
}
cout << "Total number of bytes fetched: " << totalBytes << endl;
}
- The HTTP/1.0 protocol dictates that everything beyond that blank line is payload, and that once the server publishes each and every byte of the payload, it closes it's end of the connection. That server-side close is the client-side's EOF, and we write everything we read.
- Note that we open an ofstream in binary mode, predominantly so the ofstream doesn't do anything funky with byte characters that are incidentally newline characters.
- gcount returns the number of bytes read by the most recent call to read. (This I did not know until I wrote this example).
- The HTTP/1.1 protocol allows for connections to remain open, even after the initial payload has come through. I specifically avoid this here by going with HTTP/1.0, which doesn't allow this.