Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
160 lines (135 sloc) 5.05 KB
#include <sys/time.h>
#include "network_interface.h"
#include "std_metadata.h"
#include "yadfs_exception.h"
#include "utils.h"
struct NetworkInterface::Callbacks {
static size_t onHeaderLine(void *ptr, size_t size, size_t nmemb, void *stream) {
((NetworkInterface*)stream)->onHeaderLine(std::string((const char*) ptr, size*nmemb));
return size*nmemb;
}
static size_t onData(void* ptr, size_t size, size_t nmemb, void *stream) {
((NetworkInterface*)stream)->onData((const uint8_t*)ptr, size*nmemb);
return size*nmemb;
}
};
NetworkInterface::NetworkInterface(const std::string server)
: mCURL(curl_easy_init())
, mServer(server)
, mCurrentHeaders()
, mCurrentData()
, mCallbacks(new Callbacks)
{
}
NetworkInterface::~NetworkInterface() {
if (mCURL) {
curl_easy_cleanup(mCURL);
mCURL=0;
}
}
int64_t NetworkInterface::store(const std::string& path, const std::multimap<std::string, std::string>& metadata, const std::string* content) {
}
int64_t NetworkInterface::fetch(const std::string& path, std::multimap<std::string, std::string>& metadata, std::string* content) {
std::stringstream url;
url << "fetch?path=" << url_encode(path);
std::multimap<std::string, std::string>::iterator currentHashValue(metadata.find(YADFS_META_SHA256));
const bool has_previous_hash(currentHashValue != metadata.end());
const bool do_head_request(has_previous_hash || !content);
bool need_to_fetch_content(content);
if (do_head_request) {
if (200==perform("HEAD", url.str(), metadata)) {
if (has_previous_hash) {
std::multimap<std::string, std::string>::iterator newHashValue(mCurrentHeaders.find(YADFS_META_SHA256));
if (newHashValue != mCurrentHeaders.end()) {
if (newHashValue->second == currentHashValue->second) {
need_to_fetch_content=false;
}
}
}
}
}
if (need_to_fetch_content) {
if (200==perform("GET", url.str(), metadata)) {
content->swap(mCurrentData);
}
else {
std::string message("Could not fetch ");
message+=path;
throw yadfs_exception(message);
}
}
// TODO: all the headers that start with YADFS_META_PREFIX are metadata
// TODO: transaction id is in YADFS_HEADER_LAST_SERIAL_ID
return -1; // placeholder
}
uint32_t NetworkInterface::perform(const std::string& method, const std::string& url, const std::multimap<std::string, std::string>& headers, const std::string* content) {
// Setup curl request
timeval tv;
gettimeofday(&tv, 0);
std::stringstream volatile_url;
volatile_url << mServer << url << "?not_in_cache=" << tv.tv_sec << "_" << tv.tv_usec;
curl_easy_setopt(mCURL, CURLOPT_URL, volatile_url.str().c_str());
curl_slist* curl_headers(0);
// default headers
curl_headers = curl_slist_append(curl_headers, "Accept: */*");
curl_headers = curl_slist_append(curl_headers, "Accept-Charset: UTF-8");
curl_headers = curl_slist_append(curl_headers, "Keep-Alive: 36000");
curl_headers = curl_slist_append(curl_headers, "Connection: keep-alive");
// custom headers
std::multimap<std::string, std::string>::const_iterator it(headers.begin());
std::string header_tmp;
while (it != headers.end()) {
header_tmp = it->first;
header_tmp.append(": ");
header_tmp.append(it->second);
curl_headers = curl_slist_append(curl_headers, header_tmp.c_str());
}
curl_easy_setopt(mCURL, CURLOPT_HTTPHEADER, curl_headers);
curl_easy_setopt(mCURL, CURLOPT_WRITEFUNCTION, Callbacks::onData);
curl_easy_setopt(mCURL, CURLOPT_WRITEDATA, this);
curl_easy_setopt(mCURL, CURLOPT_HEADERFUNCTION, Callbacks::onHeaderLine);
curl_easy_setopt(mCURL, CURLOPT_WRITEHEADER, this);
curl_easy_setopt(mCURL, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(mCURL, CURLOPT_POST, 0);
curl_easy_setopt(mCURL, CURLOPT_NOBODY, 1);
if (method=="HEAD") {
curl_easy_setopt(mCURL, CURLOPT_HTTPGET, 0);
curl_easy_setopt(mCURL, CURLOPT_POST, 0);
curl_easy_setopt(mCURL, CURLOPT_NOBODY, 1);
}
else if (content) {
// If caller provided some content, we'll do a POST request,
curl_easy_setopt(mCURL, CURLOPT_POST, 1);
curl_easy_setopt(mCURL, CURLOPT_POSTFIELDS, &((*content)[0]));
curl_easy_setopt(mCURL, CURLOPT_POSTFIELDSIZE, content->size());
}
else {
// else we'll simply do a GET
curl_easy_setopt(mCURL, CURLOPT_HTTPGET, 1);
curl_easy_setopt(mCURL, CURLOPT_POST, 0);
curl_easy_setopt(mCURL, CURLOPT_NOBODY, 1);
}
// Clear current content
mCurrentHeaders.clear();
mCurrentData.clear();
if (curl_easy_perform(mCURL)) {
std::string message("Could not perform HTTP request to ");
message+=volatile_url.str();
throw yadfs_exception(message);
}
curl_slist_free_all(curl_headers);
long http_code = 0;
curl_easy_getinfo(mCURL, CURLINFO_RESPONSE_CODE, &http_code);
return (uint32_t) http_code;
}
void NetworkInterface::onHeaderLine(const std::string& line) {
// split key-value
size_t colon(line.find(": "));
if (colon==std::string::npos) colon=line.size();
std::string key(line.substr(0, colon));
std::string value(line.substr(colon+2));
mCurrentHeaders.insert(std::pair<std::string, std::string>(key, value));
}
void NetworkInterface::onData(const uint8_t* data, size_t length) {
mCurrentData.append((const char*) data, length);
}