+ return d->proxy;
+}
+
+const std::string& Client::proxyAuth() const
+{
+ return d->proxyAuth;
+}
+
+void Client::setProxy( const std::string& proxy,
+ int port,
+ const std::string& auth )
+{
+ d->proxy = proxy;
+ d->proxyPort = port;
+ d->proxyAuth = auth;
+}
+
+bool Client::hasActiveRequests() const
+{
+ #if defined(ENABLE_CURL)
+ return !d->requests.empty();
+ #else
+ ConnectionDict::const_iterator it = d->connections.begin();
+ for (; it != d->connections.end(); ++it) {
+ if (it->second->isActive()) return true;
+ }
+
+ return false;
+#endif
+}
+
+void Client::receivedBytes(unsigned int count)
+{
+ d->bytesTransferred += count;
+ d->totalBytesDownloaded += count;
+}
+
+unsigned int Client::transferRateBytesPerSec() const
+{
+ unsigned int e = d->timeTransferSample.elapsedMSec();
+ if (e > 400) {
+ // too long a window, ignore
+ d->timeTransferSample.stamp();
+ d->bytesTransferred = 0;
+ d->lastTransferRate = 0;
+ return 0;
+ }
+
+ if (e < 100) { // avoid really narrow windows
+ return d->lastTransferRate;
+ }
+
+ unsigned int ratio = (d->bytesTransferred * 1000) / e;
+ // run a low-pass filter
+ unsigned int smoothed = ((400 - e) * d->lastTransferRate) + (e * ratio);
+ smoothed /= 400;
+
+ d->timeTransferSample.stamp();
+ d->bytesTransferred = 0;
+ d->lastTransferRate = smoothed;
+ return smoothed;
+}
+
+uint64_t Client::totalBytesDownloaded() const
+{
+ return d->totalBytesDownloaded;
+}
+
+size_t Client::requestWriteCallback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ size_t byteSize = size * nmemb;
+ Request* req = static_cast<Request*>(userdata);
+ req->processBodyBytes(ptr, byteSize);
+
+ Client* cl = req->http();
+ if (cl) {
+ cl->receivedBytes(byteSize);
+ }
+
+ return byteSize;
+}
+
+size_t Client::requestReadCallback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ size_t maxBytes = size * nmemb;
+ Request* req = static_cast<Request*>(userdata);
+ size_t actualBytes = req->getBodyData(ptr, 0, maxBytes);
+ return actualBytes;
+}
+
+size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems, void *userdata)
+{
+ size_t byteSize = size * nitems;
+ Request* req = static_cast<Request*>(userdata);
+ std::string h = strutils::simplify(std::string(rawBuffer, byteSize));
+
+ if (req->readyState() == HTTP::Request::OPENED) {
+ req->responseStart(h);
+ return byteSize;
+ }
+
+ if (h.empty()) {
+ // got a 100-continue reponse; restart
+ if (req->responseCode() == 100) {
+ req->setReadyState(HTTP::Request::OPENED);
+ return byteSize;
+ }
+
+ req->responseHeadersComplete();
+ return byteSize;
+ }
+
+ if (req->responseCode() == 100) {
+ return byteSize; // skip headers associated with 100-continue status
+ }
+
+ size_t colonPos = h.find(':');
+ if (colonPos == std::string::npos) {
+ SG_LOG(SG_IO, SG_WARN, "malformed HTTP response header:" << h);
+ return byteSize;
+ }
+
+ std::string key = strutils::simplify(h.substr(0, colonPos));
+ std::string lkey = boost::to_lower_copy(key);
+ std::string value = strutils::strip(h.substr(colonPos + 1));
+
+ req->responseHeader(lkey, value);
+ return byteSize;
+}
+
+void Client::debugDumpRequests()
+{
+#if defined(ENABLE_CURL)
+ SG_LOG(SG_IO, SG_INFO, "== HTTP request dump");
+ ClientPrivate::RequestCurlMap::iterator it = d->requests.begin();
+ for (; it != d->requests.end(); ++it) {
+ SG_LOG(SG_IO, SG_INFO, "\t" << it->first->url());
+ }
+ SG_LOG(SG_IO, SG_INFO, "==");
+#else
+ SG_LOG(SG_IO, SG_INFO, "== HTTP connection dump");
+ ConnectionDict::iterator it = d->connections.begin();
+ for (; it != d->connections.end(); ++it) {
+ it->second->debugDumpRequests();
+ }
+ SG_LOG(SG_IO, SG_INFO, "==");
+#endif
+}
+
+void Client::clearAllConnections()
+{
+#if defined(ENABLE_CURL)
+ curl_multi_cleanup(d->curlMulti);
+ d->createCurlMulti();
+#else
+ ConnectionDict::iterator it = d->connections.begin();
+ for (; it != d->connections.end(); ++it) {
+ delete it->second;
+ }
+ d->connections.clear();
+#endif