#include <string>
#include <iostream>
#include <vector>
#include <queue>
#include <cstdio>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include "httpclient.h"
#define BUF_SIZE 4096
class MyPutRequester : public Pipelined::HttpRequester
{
public:
MyPutRequester(const std::string& directory)
: directory_(directory), buf_(NULL)
{
}
virtual ~MyPutRequester()
{
delete[] buf_;
}
virtual void Run(Pipelined::HttpClient *client);
virtual void HandleResponse(const std::string& request, const Pipelined::HttpStatus& status,
const std::multimap<std::string, std::string>& headers, Pipelined::Stream* body);
virtual void HandleFinish(std::queue<std::string>& requests);
ssize_t GetFileSize(FILE *fptr) const;
void SendFile(FILE *fptr, Pipelined::HttpClient* client) const;
private:
const std::string& directory_;
char* buf_;
std::queue<std::string> files_;
std::vector<std::string> failed_;
};
// The override to do the PUTs
void MyPutRequester::Run(Pipelined::HttpClient *client)
{
// Build up a queue of files
DIR* dir = opendir(directory_.c_str());
if (dir != NULL) {
struct dirent* ent;
while ((ent = readdir(dir))) {
std::string name = ent->d_name;
if (name[0] != '.') {
name = directory_ + '/' + name;
struct stat statbuf;
int result = stat(name.c_str(), &statbuf);
if (buf_ == NULL) {
if (statbuf.st_blksize != -1) {
// Use the optimum buffer size
buf_ = new char[statbuf.st_blksize];
}
else {
std::cerr << "Couldn't get block size" << "std::endl";
buf_ = new char[BUF_SIZE];
}
}
if (result == 0) {
if (S_ISREG(statbuf.st_mode)) { // Regular files only
files_.push(name);
}
}
else {
std::cerr << "Couldn't stat file " << name << std::endl;
}
}
}
closedir(dir);
// Send them
while (!files_.empty()) {
std::string name = files_.front();
FILE *fptr = fopen(name.c_str(), "r");
if (fptr != NULL) {
std::string uri("/cgi-bin/put/");
uri += name;
client->StartRequest("PUT", uri);
client->SendHeader("Content-Length", GetFileSize(fptr));
client->EndHeaders();
SendFile(fptr, client);
fclose(fptr);
}
else {
std::cerr << "Couldn't open file " << name << std::endl;
}
files_.pop();
}
}
else {
std::cerr << "Couldn't open directory " << directory_ << std::endl;
}
}
// The override to handle responses
void MyPutRequester::HandleResponse(const std::string& request, const Pipelined::HttpStatus& status,
const std::multimap<std::string, std::string>& headers, Pipelined::Stream* body)
{
// Request
std::cout << request << "\n";
// Status line
std::cout << status.version << " " << status.code << " " << status.message << "\n";
// Headers
for (std::multimap<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it) {
std::cout << it->first << ": " << it->second << "\n";
}
std::cout << "\n";
// Read the entity body
char buf[BUF_SIZE];
while (!body->Eof()) {
size_t bytes_read = body->Read(buf, BUF_SIZE);
if (bytes_read > 0) {
printf("%.*s", bytes_read, buf);
}
}
std::cout << "\n" << std::endl;
// If the request didn't succeed, add it to the failed vector
if (status.code > 299) {
failed_.push_back(request);
}
}
// The override for finishing
void MyPutRequester::HandleFinish(std::queue<std::string>& requests)
{
// Requests that did not get a reply
if (!requests.empty()) {
std::cout << "The following requests did not receive a reply:\n";
while (!requests.empty()) {
std::cout << requests.front() << "\n";
requests.pop();
}
}
// Requests that failed
if (!failed_.empty()) {
std::cout << "The following requests failed:\n";
for (std::vector<std::string>::const_iterator it = failed_.begin();
it != failed_.end(); ++it) {
std::cout << *it << "\n";
}
}
// Files that were not sent
if (!files_.empty()) {
std::cout << "The following files were not sent:\n";
while (!files_.empty()) {
std::cout << files_.front() << "\n";
files_.pop();
}
}
}
// Helper to find the size of an open file
ssize_t MyPutRequester::GetFileSize(FILE *fptr) const
{
ssize_t length;
fseek(fptr, 0L, SEEK_END);
length = ftell(fptr);
fseek(fptr, 0L, SEEK_SET);
return length;
}
// Helper to send the file
void MyPutRequester::SendFile(FILE *fptr, Pipelined::HttpClient* client) const
{
size_t bytes_read;
while ((bytes_read = fread(buf_, 1, BUF_SIZE, fptr))) {
size_t bytes_sent = 0;
while (bytes_sent < bytes_read) {
size_t sent = client->Write(buf_ + bytes_sent, bytes_read - bytes_sent);
if (bytes_sent >= 0) {
bytes_sent += sent;
}
}
}
}
int main(int argc, char **argv)
{
std::string directory;
if (argc > 1) {
directory = argv[1];
}
else {
directory = ".";
}
try {
MyPutRequester requester(directory);
Pipelined::HttpClient client("localhost");
client.Run(&requester);
}
catch (std::exception& ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
}
return 0;
}