PageRenderTime 274ms CodeModel.GetById 111ms app.highlight 61ms RepoModel.GetById 99ms app.codeStats 1ms

/mordor/examples/wget.cpp

http://github.com/mozy/mordor
C++ | 155 lines | 144 code | 10 blank | 1 comment | 24 complexity | 4319df9a33a9c00e5cb2415991e90075 MD5 | raw file
  1// Copyright (c) 2009 - Mozy, Inc.
  2
  3#include "mordor/predef.h"
  4
  5#include <iostream>
  6
  7#include <boost/bind.hpp>
  8#include <boost/shared_ptr.hpp>
  9#include <boost/program_options.hpp>
 10
 11#include "mordor/config.h"
 12#include "mordor/exception.h"
 13#include "mordor/http/auth.h"
 14#include "mordor/http/broker.h"
 15#include "mordor/http/client.h"
 16#include "mordor/http/multipart.h"
 17#include "mordor/http/proxy.h"
 18#include "mordor/iomanager.h"
 19#include "mordor/main.h"
 20#include "mordor/sleep.h"
 21#include "mordor/socket.h"
 22#include "mordor/streams/socket.h"
 23#include "mordor/streams/ssl.h"
 24#include "mordor/streams/std.h"
 25#include "mordor/streams/transfer.h"
 26
 27using namespace Mordor;
 28namespace po = boost::program_options;
 29
 30static bool getCredentials(HTTP::ClientRequest::ptr priorRequest,
 31    std::string &scheme, std::string &username, std::string &password,
 32    const std::string &user, const std::string &pass,
 33    size_t attempts, bool forProxy)
 34{
 35    if (!priorRequest)
 36        return false;
 37    if (attempts > 1)
 38        return false;
 39    username = user;
 40    password = pass;
 41    const HTTP::ChallengeList &challengeList = forProxy ?
 42        priorRequest->response().response.proxyAuthenticate :
 43        priorRequest->response().response.wwwAuthenticate;
 44#ifdef WINDOWS
 45    if (HTTP::isAcceptable(challengeList, "Negotiate")) {
 46        scheme = "Negotiate";
 47        return true;
 48    }
 49    if (HTTP::isAcceptable(challengeList, "NTLM")) {
 50        scheme = "NTLM";
 51        return true;
 52    }
 53#endif
 54    if (HTTP::isAcceptable(challengeList, "Digest")) {
 55        scheme = "Digest";
 56        return true;
 57    }
 58    if (HTTP::isAcceptable(challengeList, "Basic")) {
 59        scheme = "Basic";
 60        return true;
 61    }
 62    return false;
 63}
 64
 65MORDOR_MAIN(int argc, char *argv[])
 66{
 67    Config::loadFromEnvironment();
 68    StdoutStream stdoutStream;
 69    IOManager ioManager;
 70    po::options_description desc("Allowed options");
 71    desc.add_options()
 72        ("help", "print this help message")
 73        ("username", po::value<std::string>(), "username")
 74        ("password", po::value<std::string>(), "password")
 75        ("proxyusername", po::value<std::string>(), "proxyusername")
 76        ("proxypassword", po::value<std::string>(), "proxypassword")
 77        ("uri", po::value<std::string>(), "uri to download");
 78    po::positional_options_description positions;
 79    positions.add("uri", -1);
 80    po::variables_map vm;
 81    try {
 82        po::store(po::command_line_parser(argc, argv).options(desc).positional(positions).run(), vm);
 83    } catch (...) {
 84        std::cout << desc << "\n";
 85        return 1;
 86    }
 87    if (vm.count("help") || !vm.count("uri")) {
 88        std::cout << desc << "\n";
 89        return 1;
 90    }
 91
 92    try {
 93        URI uri = vm["uri"].as<std::string>();
 94        MORDOR_ASSERT(uri.authority.hostDefined());
 95        MORDOR_ASSERT(!uri.schemeDefined() || uri.scheme() == "http" || uri.scheme() == "https");
 96
 97        HTTP::RequestBrokerOptions options;
 98        options.ioManager = &ioManager;
 99        std::string username, password, proxyusername, proxypassword;
100        if (vm.count("username")) username = vm["username"].as<std::string>();
101        if (vm.count("password")) password = vm["password"].as<std::string>();
102        if (vm.count("proxyusername")) proxyusername = vm["proxyusername"].as<std::string>();
103        if (vm.count("proxypassword")) proxypassword = vm["proxypassword"].as<std::string>();
104        if (vm.count("proxyusername"))
105            options.getProxyCredentialsDg = boost::bind(&getCredentials, _2, _3, _5, _6,
106                proxyusername, proxypassword, _7, true);
107#ifdef OSX
108        else
109            options.getProxyCredentialsDg = &HTTP::getCredentialsFromKeychain;
110#endif
111        HTTP::RequestBroker::ptr proxyBroker =
112            HTTP::createRequestBroker(options).first;
113        if (vm.count("username"))
114            options.getCredentialsDg = boost::bind(&getCredentials, _2, _3, _5, _6,
115                username, password, _7, false);
116#ifdef OSX
117        else
118            options.getCredentialsDg = &HTTP::getCredentialsFromKeychain;
119#endif
120        options.proxyRequestBroker = proxyBroker;
121#ifdef WINDOWS
122        HTTP::ProxyCache proxyCache;
123        options.proxyForURIDg = boost::bind(
124            &HTTP::ProxyCache::proxyFromUserSettings, &proxyCache, _1);
125#elif defined (OSX)
126        HTTP::ProxyCache proxyCache(proxyBroker);
127        options.proxyForURIDg = boost::bind(
128            &HTTP::ProxyCache::proxyFromSystemConfiguration, &proxyCache, _1);
129#else
130        options.proxyForURIDg = &HTTP::proxyFromConfig;
131#endif
132        HTTP::RequestBroker::ptr requestBroker =
133            HTTP::createRequestBroker(options).first;
134
135        HTTP::Request requestHeaders;
136        requestHeaders.requestLine.uri = uri;
137        requestHeaders.request.host = uri.authority.host();
138        HTTP::ClientRequest::ptr request = requestBroker->request(requestHeaders);
139        if (request->hasResponseBody()) {
140            if (request->response().entity.contentType.type != "multipart") {
141                transferStream(request->responseStream(), stdoutStream);
142            } else {
143                Multipart::ptr responseMultipart = request->responseMultipart();
144                for (BodyPart::ptr bodyPart = responseMultipart->nextPart(); bodyPart;
145                    bodyPart = responseMultipart->nextPart()) {
146                    transferStream(bodyPart->stream(), stdoutStream);
147                }
148            }
149        }
150        return request->response().status.status == HTTP::OK ? 0 : request->response().status.status;
151    } catch (...) {
152        std::cerr << boost::current_exception_diagnostic_information() << std::endl;
153        return 2;
154    }
155}