<commit_before>#ifndef LIBTEN_HTTP_CLIENT_HH
#define LIBTEN_HTTP_CLIENT_HH

#include "ten/http/http_message.hh"
#include "ten/http/http_error.hh"
#include "ten/shared_pool.hh"
#include "ten/buffer.hh"
#include "ten/net.hh"
#include "ten/uri.hh"
#include "ten/task.hh"
#include <atomic>
#include <chrono_io>
#include <netinet/tcp.h>

namespace ten {

//! possibly recycle connections after a while
//  TODO: move down to common base with other clients

//! basic http client
class http_client {
public:
    using lifetime_t = optional<std::chrono::seconds>;
    using retire_t = optional<kernel::time_point>;
    static constexpr double pretire_factor = 0.8;
private:
    netsock _sock;
    buffer _buf;
    std::string _host;
    uint16_t _port;
    optional_timeout _conn_timeout;
    retire_t _pretire, _retire;

    void ensure_connection() {
        if (!_sock.valid()) {
            netsock cs{AF_INET, SOCK_STREAM};
            if (!cs.valid()) {
                throw http_makesock_error{};
            }
            try {
                cs.dial(_host.c_str(), _port, _conn_timeout);
            } catch (const errno_error &e) {
                throw http_dial_error{e};
            } catch (const std::exception &e) {
                throw http_dial_error{e.what()};
            }
            cs.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1);
            _sock = std::move(cs);
        }
    }

public:
    size_t max_content_length = ~(size_t)0;

    http_client(const std::string &host_, uint16_t port_ = 80,
                lifetime_t lifetime = nullopt, optional_timeout conn_timeout = nullopt)
        : _buf(4*1024), _host(host_), _port(port_), _conn_timeout(conn_timeout)
    {
        parse_host_port(_host, _port);

        if (lifetime) {
            _retire = kernel::now() + *lifetime;
            const auto pre_elig = (intmax_t)(lifetime->count() * pretire_factor);
            if (pre_elig >= 1)
                _pretire = kernel::now() + lifetime_t::value_type(pre_elig);
        }
    }

    std::string host() const                       { return _host; }
    uint16_t port() const                          { return _port; }
    optional_timeout conn_timeout() const          { return _conn_timeout; }
    retire_t pretire() const                       { return _pretire; }
    retire_t retire() const                        { return _retire; }
    bool pretire_by(kernel::time_point when) const { return _pretire && when >= *_pretire; }
    bool retire_by(kernel::time_point when) const  { return _retire  && when >= *_retire; }

    http_response get(const std::string &path, optional_timeout timeout = nullopt) {
        return perform(hs::GET, path, {}, {}, timeout);
    }
    http_response delete_(const std::string &path, optional_timeout timeout = nullopt) {
        return perform(hs::DELETE, path, {}, {}, timeout);
    }
    http_response post(const std::string &path, std::string data, optional_timeout timeout = nullopt) {
        return perform(hs::POST, path, {}, std::move(data), timeout);
    }
    http_response put(const std::string &path, std::string data, optional_timeout timeout = nullopt) {
        return perform(hs::PUT, path, {}, std::move(data), timeout);
    }

    http_response perform(const std::string &method, const std::string &path,
                          http_headers hdrs = {}, std::string data = {},
                          optional_timeout timeout = nullopt)
    {
        // Calculate canonical path
        uri u;
        u.scheme = "http";
        u.host = _host;
        u.port = _port;
        u.path = path;
        u.normalize();

        // HTTP/1.1 requires host header; include it always, why not
        if (!hdrs.contains(hs::Host))
            hdrs.set(hs::Host, u.host);

        http_request r{method, u.compose_path(), std::move(hdrs), std::move(data)};
        return perform(r, timeout);
    }

    http_response perform(http_request &r, optional_timeout timeout = nullopt) {
        VLOG(4) << "-> " << r.method << " " << _host << ":" << _port << " " << r.uri;

        if (r.body.size()) {
            r.set(hs::Content_Length, r.body.size());
        }

        try {
            ensure_connection();

            http_response resp(&r);

            std::string data = r.data();
            if (r.body.size() > 0) {
                data += r.body;
            }
            ssize_t nw = _sock.send(data.data(), data.size(), 0, timeout);
            if (nw < 0) {
                throw http_send_error{};
            }
            else if ((size_t)nw != data.size()) {
                std::ostringstream ss;
                ss << "short write: " << nw << " < " << data.size();
                throw http_error(ss.str().c_str());
            }

            http_parser parser;
            resp.parser_init(&parser);

            _buf.clear();

            while (!resp.complete) {
                _buf.reserve(4*1024);
                ssize_t nr = _sock.recv(_buf.back(), _buf.available(), 0, timeout);
                if (nr < 0) { throw http_recv_error{}; }
                if (!nr) { throw http_closed_error{}; }
                _buf.commit(nr);
                size_t len = _buf.size();
                resp.parse(&parser, _buf.front(), len);
                _buf.remove(len);
                if (resp.body.size() >= max_content_length) {
                    _sock.close(); // close this socket, we won't read anymore
                    return resp;
                }
            }
            // should not be any data left over in _buf
            CHECK(_buf.size() == 0);

            // if response requests closing socket, do it
            if (resp.close_after())
                _sock.close();

            VLOG(4) << "<- " << resp.status_code << " [" << resp.body.size() << "]";
            return resp;
        } catch (errorx &e) {
            if (_sock.valid())
                _sock.close();
            throw;
        }
    }
};

namespace detail {
class http_scoped_resource;
}

class http_pool : public shared_pool<http_client> {
    friend class detail::http_scoped_resource;

public:
    using scoped_resource = detail::http_scoped_resource;

    http_pool(const std::string &host_,
            uint16_t port_,
            optional<size_t> max_conn = nullopt,
            http_client::lifetime_t lifetime_ = nullopt,
            optional_timeout conn_timeout_ = nullopt)
        : shared_pool<http_client>(
            "http://" + host_ + ":" + std::to_string(port_),
            std::bind(&http_pool::new_resource, this),
            max_conn
          ),
          _host(host_),
          _port(port_),
          _lifetime(lifetime_),
          _conn_timeout(conn_timeout_)
    {
        if (_lifetime) {
            if (_lifetime->count() <= 0)
                throw_stream() << name() << ": invalid client lifetime " << *_lifetime;
            _lt = std::make_shared<lt_state>();
            _lt->t = task::spawn([=] {
                _lt_run(_impl(), _lt, _lifetime);
            });
        }
    }

protected:
    std::string _host;
    uint16_t _port;
    http_client::lifetime_t _lifetime;
    optional_timeout _conn_timeout;

    struct lt_state {
        task t;
        std::atomic<size_t> retired{};
        rendez worker;

        ~lt_state() {
            t.cancel();
        }
    };
    std::shared_ptr<lt_state> _lt;

    res_ptr new_resource() {
        VLOG(3) << name() << ": new http_client resource " << _host << ":" << _port;
        return std::make_shared<http_client>(_host, _port, _lifetime, _conn_timeout);
    }

    // periodically check the items at the front of the avail queue.
    // if they're 2x the max age, then they're excess and stale; toss 'em.
    // (but defer actual destruction until the pool_impl is unlocked.)
    // somewhat less stale connections are handled by the custom scoped_resource.
    static void _lt_run(std::shared_ptr<pool_impl> im,
                        std::shared_ptr<lt_state> lt,
                        http_client::lifetime_t lifetime)
    {
        const std::chrono::milliseconds interval{500 * std::min((std::chrono::milliseconds::rep)20L, lifetime->count())};
        VLOG(3) << im->name << ": LT interval=" << interval.count();
        for (;;) {
            std::vector<res_ptr> doomed; // declared first, destroyed last
            std::unique_lock<qutex> lk(im->mut);

            VLOG(4) << im->name << ": LT asleep";
            try {
                deadline dl{interval};
                lt->worker.sleep(lk);
            }
            catch (deadline_reached &) {
                // that's ok.  time to check the donuts
            }
            VLOG(4) << im->name << ": LT awake"
                    << "; retired=" << lt->retired.load()
                    << ", set=" << im->set.size()
                    << ", avail=" << im->avail.size();

            // perform requested replacements

            for (; lt->retired.load(); lt->retired--) {
                res_ptr c;
                try {
                    c = im->new_with_lock(lk);
                }
                catch (task_interrupted &) {
                    // let the task die
                    throw;
                }
                catch (std::exception &) {
                    // any other exception has been logged; skip this replacement
                    continue;
                }
                VLOG(4) << "LT: created " << c;
                im->avail.push_front(c);
                im->not_empty.wakeup();
            }

            // move deeply stale items into destructobucket, which then... destructs

            while (!im->avail.empty()) {
                auto c = im->avail.back();
                if (!c->retire_by(kernel::now()))
                    break;
                VLOG(3) << im->name << ": LT dropping stale " << c;
                im->avail.pop_back();
                im->set.erase(c);
                doomed.push_back(std::move(c));
            }
            if (!doomed.empty())
                im->not_empty.wakeup();  // in theory, this should never matter
        }
    }
};

namespace detail {

class http_scoped_resource : public scoped_resource<http_client> {
    std::shared_ptr<http_pool::lt_state> _lt;
    bool _mustdie;

public:
    //! RAII
    explicit http_scoped_resource(http_pool &p)
        : scoped_resource{p},
          _lt{p._lt},
          _mustdie{_c->pretire_by(kernel::now())}
    {
        if (_mustdie) {
            _lt->retired++;
            VLOG(4) << "LT: waking task, retired=" << _lt->retired.load();
            _lt->worker.wakeup();
        }
    }

    ~http_scoped_resource() {
        if (_mustdie)
            _success = false;
    }
};

} // end namespace detail

} // end namespace ten

#endif // LIBTEN_HTTP_CLIENT_HH
<commit_msg>add host-factory mode to shared http client pool<commit_after>#ifndef LIBTEN_HTTP_CLIENT_HH
#define LIBTEN_HTTP_CLIENT_HH

#include "ten/http/http_message.hh"
#include "ten/http/http_error.hh"
#include "ten/shared_pool.hh"
#include "ten/buffer.hh"
#include "ten/net.hh"
#include "ten/uri.hh"
#include "ten/task.hh"
#include <atomic>
#include <chrono_io>
#include <netinet/tcp.h>

namespace ten {

//! possibly recycle connections after a while
//  TODO: move down to common base with other clients

//! basic http client
class http_client {
public:
    using lifetime_t = optional<std::chrono::seconds>;
    using retire_t = optional<kernel::time_point>;
    static constexpr double pretire_factor = 0.8;
private:
    netsock _sock;
    buffer _buf;
    std::string _host;
    uint16_t _port;
    optional_timeout _conn_timeout;
    retire_t _pretire, _retire;

    void ensure_connection() {
        if (!_sock.valid()) {
            netsock cs{AF_INET, SOCK_STREAM};
            if (!cs.valid()) {
                throw http_makesock_error{};
            }
            try {
                cs.dial(_host.c_str(), _port, _conn_timeout);
            } catch (const errno_error &e) {
                throw http_dial_error{e};
            } catch (const std::exception &e) {
                throw http_dial_error{e.what()};
            }
            cs.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1);
            _sock = std::move(cs);
        }
    }

public:
    size_t max_content_length = ~(size_t)0;

    http_client(const std::string &host_, uint16_t port_ = 80,
                lifetime_t lifetime = nullopt, optional_timeout conn_timeout = nullopt)
        : _buf(4*1024), _host(host_), _port(port_), _conn_timeout(conn_timeout)
    {
        parse_host_port(_host, _port);

        if (lifetime) {
            _retire = kernel::now() + *lifetime;
            const auto pre_elig = (intmax_t)(lifetime->count() * pretire_factor);
            if (pre_elig >= 1)
                _pretire = kernel::now() + lifetime_t::value_type(pre_elig);
        }
    }

    std::string host() const                       { return _host; }
    uint16_t port() const                          { return _port; }
    optional_timeout conn_timeout() const          { return _conn_timeout; }
    retire_t pretire() const                       { return _pretire; }
    retire_t retire() const                        { return _retire; }
    bool pretire_by(kernel::time_point when) const { return _pretire && when >= *_pretire; }
    bool retire_by(kernel::time_point when) const  { return _retire  && when >= *_retire; }

    http_response get(const std::string &path, optional_timeout timeout = nullopt) {
        return perform(hs::GET, path, {}, {}, timeout);
    }
    http_response delete_(const std::string &path, optional_timeout timeout = nullopt) {
        return perform(hs::DELETE, path, {}, {}, timeout);
    }
    http_response post(const std::string &path, std::string data, optional_timeout timeout = nullopt) {
        return perform(hs::POST, path, {}, std::move(data), timeout);
    }
    http_response put(const std::string &path, std::string data, optional_timeout timeout = nullopt) {
        return perform(hs::PUT, path, {}, std::move(data), timeout);
    }

    http_response perform(const std::string &method, const std::string &path,
                          http_headers hdrs = {}, std::string data = {},
                          optional_timeout timeout = nullopt)
    {
        // Calculate canonical path
        uri u;
        u.scheme = "http";
        u.host = _host;
        u.port = _port;
        u.path = path;
        u.normalize();

        // HTTP/1.1 requires host header; include it always, why not
        if (!hdrs.contains(hs::Host))
            hdrs.set(hs::Host, u.host);

        http_request r{method, u.compose_path(), std::move(hdrs), std::move(data)};
        return perform(r, timeout);
    }

    http_response perform(http_request &r, optional_timeout timeout = nullopt) {
        VLOG(4) << "-> " << r.method << " " << _host << ":" << _port << " " << r.uri;

        if (r.body.size()) {
            r.set(hs::Content_Length, r.body.size());
        }

        try {
            ensure_connection();

            http_response resp(&r);

            std::string data = r.data();
            if (r.body.size() > 0) {
                data += r.body;
            }
            ssize_t nw = _sock.send(data.data(), data.size(), 0, timeout);
            if (nw < 0) {
                throw http_send_error{};
            }
            else if ((size_t)nw != data.size()) {
                std::ostringstream ss;
                ss << "short write: " << nw << " < " << data.size();
                throw http_error(ss.str().c_str());
            }

            http_parser parser;
            resp.parser_init(&parser);

            _buf.clear();

            while (!resp.complete) {
                _buf.reserve(4*1024);
                ssize_t nr = _sock.recv(_buf.back(), _buf.available(), 0, timeout);
                if (nr < 0) { throw http_recv_error{}; }
                if (!nr) { throw http_closed_error{}; }
                _buf.commit(nr);
                size_t len = _buf.size();
                resp.parse(&parser, _buf.front(), len);
                _buf.remove(len);
                if (resp.body.size() >= max_content_length) {
                    _sock.close(); // close this socket, we won't read anymore
                    return resp;
                }
            }
            // should not be any data left over in _buf
            CHECK(_buf.size() == 0);

            // if response requests closing socket, do it
            if (resp.close_after())
                _sock.close();

            VLOG(4) << "<- " << resp.status_code << " [" << resp.body.size() << "]";
            return resp;
        } catch (errorx &e) {
            if (_sock.valid())
                _sock.close();
            throw;
        }
    }
};

namespace detail {
class http_scoped_resource;
}

class http_pool : public shared_pool<http_client> {
    friend class detail::http_scoped_resource;

public:
    using scoped_resource = detail::http_scoped_resource;
    using host_port_t = std::pair<std::string, uint16_t>;

    // general case: arbitrary host generator
    http_pool(std::string name_,
              std::function< host_port_t() > host_factory_,
              optional<size_t> max_conn_ = nullopt,
              http_client::lifetime_t lifetime_ = nullopt,
              optional_timeout conn_timeout_ = nullopt)
        : shared_pool<http_client>(
            name_,
            [this]{ return new_resource(); },
            max_conn_
          ),
          _host_factory(host_factory_),
          _lifetime(lifetime_),
          _conn_timeout(conn_timeout_)
    {
        if (_lifetime) {
            if (_lifetime->count() <= 0)
                throw_stream() << name() << ": invalid client lifetime " << *_lifetime;
            _lt = std::make_shared<lt_state>();
            _lt->t = task::spawn([=] {
                _lt_run(_impl(), _lt, _lifetime);
            });
        }
    }

    // simple case: one host
    http_pool(std::string host_,
              uint16_t port_,
              optional<size_t> max_conn_ = nullopt,
              http_client::lifetime_t lifetime_ = nullopt,
              optional_timeout conn_timeout_ = nullopt)
        : http_pool(
            "http://" + host_ + ":" + std::to_string(port_),
            [=]{ return host_port_t{ host_, port_ }; },
            max_conn_,
            lifetime_,
            conn_timeout_
          )
    {}

protected:
    std::function< host_port_t() > _host_factory;
    http_client::lifetime_t _lifetime;
    optional_timeout _conn_timeout;

    struct lt_state {
        task t;
        std::atomic<size_t> retired{};
        rendez worker;

        ~lt_state() {
            t.cancel();
        }
    };
    std::shared_ptr<lt_state> _lt;

    res_ptr new_resource() {
        const auto hp = _host_factory();
        VLOG(3) << name() << ": new http_client resource " << hp.first << ":" << hp.second;
        return std::make_shared<http_client>(hp.first, hp.second, _lifetime, _conn_timeout);
    }

    // periodically check the items at the front of the avail queue.
    // if they're 2x the max age, then they're excess and stale; toss 'em.
    // (but defer actual destruction until the pool_impl is unlocked.)
    // somewhat less stale connections are handled by the custom scoped_resource.
    static void _lt_run(std::shared_ptr<pool_impl> im,
                        std::shared_ptr<lt_state> lt,
                        http_client::lifetime_t lifetime)
    {
        const std::chrono::milliseconds interval{500 * std::min((std::chrono::milliseconds::rep)20L, lifetime->count())};
        VLOG(3) << im->name << ": LT interval=" << interval.count();
        for (;;) {
            std::vector<res_ptr> doomed; // declared first, destroyed last
            std::unique_lock<qutex> lk(im->mut);

            VLOG(4) << im->name << ": LT asleep";
            try {
                deadline dl{interval};
                lt->worker.sleep(lk);
            }
            catch (deadline_reached &) {
                // that's ok.  time to check the donuts
            }
            VLOG(4) << im->name << ": LT awake"
                    << "; retired=" << lt->retired.load()
                    << ", set=" << im->set.size()
                    << ", avail=" << im->avail.size();

            // perform requested replacements

            for (; lt->retired.load(); lt->retired--) {
                res_ptr c;
                try {
                    c = im->new_with_lock(lk);
                }
                catch (task_interrupted &) {
                    // let the task die
                    throw;
                }
                catch (std::exception &) {
                    // any other exception has been logged; skip this replacement
                    continue;
                }
                VLOG(4) << "LT: created " << c;
                im->avail.push_front(c);
                im->not_empty.wakeup();
            }

            // move deeply stale items into destructobucket, which then... destructs

            while (!im->avail.empty()) {
                auto c = im->avail.back();
                if (!c->retire_by(kernel::now()))
                    break;
                VLOG(3) << im->name << ": LT dropping stale " << c;
                im->avail.pop_back();
                im->set.erase(c);
                doomed.push_back(std::move(c));
            }
            if (!doomed.empty())
                im->not_empty.wakeup();  // in theory, this should never matter
        }
    }
};

namespace detail {

class http_scoped_resource : public scoped_resource<http_client> {
    std::shared_ptr<http_pool::lt_state> _lt;
    bool _mustdie;

public:
    //! RAII
    explicit http_scoped_resource(http_pool &p)
        : scoped_resource{p},
          _lt{p._lt},
          _mustdie{_c->pretire_by(kernel::now())}
    {
        if (_mustdie) {
            _lt->retired++;
            VLOG(4) << "LT: waking task, retired=" << _lt->retired.load();
            _lt->worker.wakeup();
        }
    }

    ~http_scoped_resource() {
        if (_mustdie)
            _success = false;
    }
};

} // end namespace detail

} // end namespace ten

#endif // LIBTEN_HTTP_CLIENT_HH
<|endoftext|>


<commit_before>#ifndef VSMC_RNG_M128I_HPP
#define VSMC_RNG_M128I_HPP

#include <vsmc/rng/internal/common.hpp>
#include <emmintrin.h>

#define VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N) \
    VSMC_STATIC_ASSERT(                                                      \
            ((Offset < N) && (sizeof(T) * (N - Offset) >= sizeof(__m128i))), \
            TRY_TO_PACK_OR_UNPACK_A_TOO_SMALL_VECTOR_INTO_OR_FROM_m128i)

namespace vsmc {

/// \brief Test if an object is aligned for
template <typename T>
bool is_m128_aligned (T *ptr)
{return (reinterpret_cast<uintptr_t>(ptr) & static_cast<uintptr_t>(15)) == 0;}

/// \brief Aligned pack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack_a (const StaticVector<T, N, Traits> &c, __m128i &m)
{m = _mm_load_si128(reinterpret_cast<const __m128i *>(c.data() + Offset));}

/// \brief Unaligned pack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack_u (const StaticVector<T, N, Traits> &c, __m128i &m)
{m = _mm_loadu_si128(reinterpret_cast<const __m128i *>(c.data() + Offset));}

/// \brief Aligned unpack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack_a (const __m128i &m, StaticVector<T, N, Traits> &c)
{_mm_store_si128(reinterpret_cast<__m128i *>(c.data() + Offset), m);}

/// \brief Unaligned unpack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack_u (const __m128i &m, StaticVector<T, N, Traits> &c)
{_mm_storeu_si128(reinterpret_cast<__m128i *>(c.data() + Offset), m);}

/// \brief Pack a StaticVector into an __m128i object
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack (const StaticVector<T, N, Traits> &c, __m128i &m)
{
    VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N);
    is_m128_aligned(c.data()) ?
        m128i_pack_a<Offset>(c, m) : m128i_pack_u<Offset>(c, m);
}

/// \brief Unpack an __m128i object into a StaticVector
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack (const __m128i &m, StaticVector<T, N, Traits> &c)
{
    VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N);
    is_m128_aligned(c.data()) ?
        m128i_unpack_a<Offset>(m, c) : m128i_unpack_u<Offset>(m, c);
}

/// \brief Compare two __m128i objects
/// \ingroup RNG
inline bool m128i_is_equal (const __m128i &a, const __m128i &b)
{
    StaticVector<uint64_t, 2> sa;
    StaticVector<uint64_t, 2> sb;
    m128i_unpack<0>(a, sa);
    m128i_unpack<0>(b, sb);

    return sa == sb;
}

/// \brief Write an __m128i object into an output stream as two 64-bits
/// unsigned integers
/// \ingroup RNG
template <typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits> &m128i_output (
        std::basic_ostream<CharT, Traits> &os, const __m128i &a)
{
    if (os) {
        StaticVector<uint64_t, 2> sa;
        m128i_unpack<0>(a, sa);
        os << sa;
    }

    return os;
}

/// \brief Input an __m128i object from an input stream as two 64-bits
/// unsigned integers written by m128i_output
/// \ingroup RNG
template <typename CharT, typename Traits>
inline std::basic_istream<CharT, Traits> &m128i_input (
        std::basic_istream<CharT, Traits> &is, __m128i &a)
{
    if (is) {
        StaticVector<uint64_t, 2> sa;
        is >> sa;
        if (is) m128i_pack<0>(sa, a);
    }

    return is;
}

} // namespace vsmc

#endif // VSMC_RNG_M128I_HPP
<commit_msg>input and output m128i as chars<commit_after>#ifndef VSMC_RNG_M128I_HPP
#define VSMC_RNG_M128I_HPP

#include <vsmc/rng/internal/common.hpp>
#include <emmintrin.h>

#define VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N) \
    VSMC_STATIC_ASSERT(                                                      \
            ((Offset < N) && (sizeof(T) * (N - Offset) >= sizeof(__m128i))), \
            TRY_TO_PACK_OR_UNPACK_A_TOO_SMALL_VECTOR_INTO_OR_FROM_m128i)

namespace vsmc {

/// \brief Test if an object is aligned for
template <typename T>
bool is_m128_aligned (T *ptr)
{return (reinterpret_cast<uintptr_t>(ptr) & static_cast<uintptr_t>(15)) == 0;}

/// \brief Aligned pack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack_a (const StaticVector<T, N, Traits> &c, __m128i &m)
{m = _mm_load_si128(reinterpret_cast<const __m128i *>(c.data() + Offset));}

/// \brief Unaligned pack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack_u (const StaticVector<T, N, Traits> &c, __m128i &m)
{m = _mm_loadu_si128(reinterpret_cast<const __m128i *>(c.data() + Offset));}

/// \brief Aligned unpack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack_a (const __m128i &m, StaticVector<T, N, Traits> &c)
{_mm_store_si128(reinterpret_cast<__m128i *>(c.data() + Offset), m);}

/// \brief Unaligned unpack
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack_u (const __m128i &m, StaticVector<T, N, Traits> &c)
{_mm_storeu_si128(reinterpret_cast<__m128i *>(c.data() + Offset), m);}

/// \brief Pack a StaticVector into an __m128i object
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_pack (const StaticVector<T, N, Traits> &c, __m128i &m)
{
    VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N);
    is_m128_aligned(c.data()) ?
        m128i_pack_a<Offset>(c, m) : m128i_pack_u<Offset>(c, m);
}

/// \brief Unpack an __m128i object into a StaticVector
/// \ingroup RNG
template <std::size_t Offset, typename T, std::size_t N, typename Traits>
inline void m128i_unpack (const __m128i &m, StaticVector<T, N, Traits> &c)
{
    VSMC_STATIC_ASSERT_RNG_M128I_PACK(Offset, T, N);
    is_m128_aligned(c.data()) ?
        m128i_unpack_a<Offset>(m, c) : m128i_unpack_u<Offset>(m, c);
}

/// \brief Compare two __m128i objects
/// \ingroup RNG
inline bool m128i_is_equal (const __m128i &a, const __m128i &b)
{
    StaticVector<uint64_t, 2> sa;
    StaticVector<uint64_t, 2> sb;
    m128i_unpack<0>(a, sa);
    m128i_unpack<0>(b, sb);

    return sa == sb;
}

/// \brief Write an __m128i object into an output stream as 16 bytes
/// unsigned integers
/// \ingroup RNG
template <typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits> &m128i_output (
        std::basic_ostream<CharT, Traits> &os, const __m128i &a)
{
    if (os) {
        StaticVector<unsigned char, 16> sa;
        m128i_unpack<0>(a, sa);
        os << sa;
    }

    return os;
}

/// \brief Input an __m128i object from an input stream as 16 bytes
/// unsigned integers written by m128i_output
/// \ingroup RNG
template <typename CharT, typename Traits>
inline std::basic_istream<CharT, Traits> &m128i_input (
        std::basic_istream<CharT, Traits> &is, __m128i &a)
{
    if (is) {
        StaticVector<unsigned char, 16> sa;
        is >> sa;
        if (is) m128i_pack<0>(sa, a);
    }

    return is;
}

} // namespace vsmc

#endif // VSMC_RNG_M128I_HPP
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_LINK_HPP
#define XWIDGETS_LINK_HPP

#include <utility>

#include "xholder.hpp"
#include "xmaterialize.hpp"
#include "xobject.hpp"

namespace xw
{
    /********************
     * link declaration *
     ********************/

    using xlink_pair_type = std::tuple<xholder<xtransport>, std::string>;

    template <class D>
    class xlink : public xobject<D>
    {
    public:

        using base_type = xobject<D>;
        using derived_type = D;

        using pair_type = xlink_pair_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(pair_type, derived_type, source);
        XPROPERTY(pair_type, derived_type, target);

    protected:

        template <class S, class T>
        xlink(xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn);

        using base_type::base_type;

    private:

        void set_defaults();
    };

    using link = xmaterialize<xlink>;

    using link_generator = xgenerator<xlink>;

    /********************************
     * directional_link declaration *
     ********************************/

    using xdirectional_link_pair_type = std::pair<xholder<xtransport>, std::string>;

    template <class D>
    class xdirectional_link : public xobject<D>
    {
    public:

        using base_type = xobject<D>;
        using derived_type = D;

        using pair_type = xdirectional_link_pair_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(pair_type, derived_type, source);
        XPROPERTY(pair_type, derived_type, target);

    protected:

        template <class S, class T>
        xdirectional_link(const xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn);

        using base_type::base_type;

    private:

        void set_defaults();
    };

    using directional_link = xmaterialize<xdirectional_link>;

    using directional_link_generator = xgenerator<xdirectional_link>;

    /************************
     * xlink implementation *
     ************************/

    template <class D>
    inline xeus::xjson xlink<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(source, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(target, state);

        return state;
    }

    template <class D>
    inline void xlink<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(source, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(target, patch);
    }

    template <class D>
    template <class S, class T>
    inline xlink<D>::xlink(xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn)
        : base_type()
    {
        set_defaults();
        std::get<0>(this->source()) = s;
        std::get<1>(this->source()) = sn;
        std::get<0>(this->target()) = t;
        std::get<1>(this->target()) = tn;
    }

    template <class D>
    inline void xlink<D>::set_defaults()
    {
        this->_model_name() = "LinkModel";
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_module_version() = XWIDGETS_CONTROLS_VERSION;
    }

    /************************************
     * xdirectional_link implementation *
     ************************************/

    template <class D>
    inline xeus::xjson xdirectional_link<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(source, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(target, state);

        return state;
    }

    template <class D>
    inline void xdirectional_link<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(source, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(target, patch);
    }

    template <class D>
    template <class S, class T>
    inline xdirectional_link<D>::xdirectional_link(const xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn)
        : base_type()
    {
        set_defaults();
        std::get<0>(this->source()) = s;
        std::get<1>(this->source()) = sn;
        std::get<0>(this->target()) = t;
        std::get<1>(this->target()) = tn;
    }

    template <class D>
    inline void xdirectional_link<D>::set_defaults()
    {
        this->_model_name() = "DirectionalLinkModel";
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_module_version() = XWIDGETS_CONTROLS_VERSION;
    }

    /*********************
     * precompiled types *
     *********************/

#ifndef _WIN32
    extern template class xmaterialize<xlink>;
    extern template class xtransport<xmaterialize<xlink>>;
    extern template class xgenerator<xlink>;
    extern template class xtransport<xgenerator<xlink>>;

    extern template class xmaterialize<xdirectional_link>;
    extern template class xtransport<xmaterialize<xdirectional_link>>;
    extern template class xgenerator<xdirectional_link>;
    extern template class xtransport<xgenerator<xdirectional_link>>;
#endif
}
#endif
<commit_msg>Return std::pair occurrence<commit_after>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_LINK_HPP
#define XWIDGETS_LINK_HPP

#include <string>
#include <tuple>
#include <utility>

#include "xholder.hpp"
#include "xmaterialize.hpp"
#include "xobject.hpp"

namespace xw
{
    /********************
     * link declaration *
     ********************/

    using xlink_pair_type = std::tuple<xholder<xtransport>, std::string>;

    template <class D>
    class xlink : public xobject<D>
    {
    public:

        using base_type = xobject<D>;
        using derived_type = D;

        using pair_type = xlink_pair_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(pair_type, derived_type, source);
        XPROPERTY(pair_type, derived_type, target);

    protected:

        template <class S, class T>
        xlink(xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn);

        using base_type::base_type;

    private:

        void set_defaults();
    };

    using link = xmaterialize<xlink>;

    using link_generator = xgenerator<xlink>;

    /********************************
     * directional_link declaration *
     ********************************/

    using xdirectional_link_pair_type = std::tuple<xholder<xtransport>, std::string>;

    template <class D>
    class xdirectional_link : public xobject<D>
    {
    public:

        using base_type = xobject<D>;
        using derived_type = D;

        using pair_type = xdirectional_link_pair_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(pair_type, derived_type, source);
        XPROPERTY(pair_type, derived_type, target);

    protected:

        template <class S, class T>
        xdirectional_link(const xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn);

        using base_type::base_type;

    private:

        void set_defaults();
    };

    using directional_link = xmaterialize<xdirectional_link>;

    using directional_link_generator = xgenerator<xdirectional_link>;

    /************************
     * xlink implementation *
     ************************/

    template <class D>
    inline xeus::xjson xlink<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(source, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(target, state);

        return state;
    }

    template <class D>
    inline void xlink<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(source, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(target, patch);
    }

    template <class D>
    template <class S, class T>
    inline xlink<D>::xlink(xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn)
        : base_type()
    {
        set_defaults();
        std::get<0>(this->source()) = s;
        std::get<1>(this->source()) = sn;
        std::get<0>(this->target()) = t;
        std::get<1>(this->target()) = tn;
    }

    template <class D>
    inline void xlink<D>::set_defaults()
    {
        this->_model_name() = "LinkModel";
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_module_version() = XWIDGETS_CONTROLS_VERSION;
    }

    /************************************
     * xdirectional_link implementation *
     ************************************/

    template <class D>
    inline xeus::xjson xdirectional_link<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(source, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(target, state);

        return state;
    }

    template <class D>
    inline void xdirectional_link<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(source, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(target, patch);
    }

    template <class D>
    template <class S, class T>
    inline xdirectional_link<D>::xdirectional_link(const xtransport<S>& s, std::string sn, xtransport<T>& t, std::string tn)
        : base_type()
    {
        set_defaults();
        std::get<0>(this->source()) = s;
        std::get<1>(this->source()) = sn;
        std::get<0>(this->target()) = t;
        std::get<1>(this->target()) = tn;
    }

    template <class D>
    inline void xdirectional_link<D>::set_defaults()
    {
        this->_model_name() = "DirectionalLinkModel";
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_module_version() = XWIDGETS_CONTROLS_VERSION;
    }

    /*********************
     * precompiled types *
     *********************/

#ifndef _WIN32
    extern template class xmaterialize<xlink>;
    extern template class xtransport<xmaterialize<xlink>>;
    extern template class xgenerator<xlink>;
    extern template class xtransport<xgenerator<xlink>>;

    extern template class xmaterialize<xdirectional_link>;
    extern template class xtransport<xmaterialize<xdirectional_link>>;
    extern template class xgenerator<xdirectional_link>;
    extern template class xtransport<xgenerator<xdirectional_link>>;
#endif
}
#endif
<|endoftext|>


<commit_before>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * The CMS start page.
 */

#include <Wt/WApplication>
#include <Wt/WContainerWidget>
#include <Wt/WSignalMapper>
#include <Wt/WStackedWidget>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include <CoreLib/Random.hpp>
#include <CoreLib/System.hpp>
#include "CgiEnv.hpp"
#include "Cms.hpp"
#include "Cms.hpp"
#include "CmsChangeEmail.hpp"
#include "CmsChangePassword.hpp"
#include "CmsContacts.hpp"
#include "CmsDashboard.hpp"
#include "CmsNewsletter.hpp"
#include "CmsSubscribers.hpp"
#include "Div.hpp"
#include "Pool.hpp"
#include "SysMon.hpp"

using namespace std;
using namespace Wt;
using namespace CoreLib;
using namespace Service;

struct Cms::Impl : public Wt::WObject
{
public:
    Cms *m_parent;
    Wt::WStackedWidget *Contents;
    WText *LastSelectedMenuItem;

    SysMon *SystemMonitor;

public:
    explicit Impl(Cms *parent);

public:
    void OnMenuItemPressed(WText *sender);
};

Cms::Cms(CgiRoot *cgi) :
    Page(cgi),
    m_pimpl(std::make_unique<Cms::Impl>(this))
{
    m_cgiRoot->setTitle(tr("cms-page-title"));

    m_htmlRoot->clear();
    this->clear();
    this->setId("CmsPage");
    this->addWidget(Layout());
    m_htmlRoot->addWidget(this);
}

WWidget *Cms::Layout()
{
    Div *container = new Div("Cms", "container");
    Div *noScript = new Div(container);
    noScript->addWidget(new WText(tr("no-script")));

    std::string htmlData;
    std::string file;
    if (m_cgiEnv->GetCurrentLanguage() == CgiEnv::Language::Fa) {
        file = "../templates/cms-fa.wtml";
    } else {
        file = "../templates/cms.wtml";
    }

    if (CoreLib::FileSystem::Read(file, htmlData)) {
        WTemplate *tmpl = new WTemplate(container);
        tmpl->setTemplateText(WString(htmlData), TextFormat::XHTMLUnsafeText);

        tmpl->bindWidget("brand-title", new WText(tr("cms-page-title")));

        WText *dashboard = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard")), TextFormat::XHTMLUnsafeText);
        WText *newsletter = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-newsletter")), TextFormat::XHTMLUnsafeText);
        WText *subscribers = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-subscribers")), TextFormat::XHTMLUnsafeText);
        WText *contacts = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-contacts")), TextFormat::XHTMLUnsafeText);
        WText *changeEmail = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-admin-change-email")), TextFormat::XHTMLUnsafeText);
        WText *changePassword = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-admin-change-password")), TextFormat::XHTMLUnsafeText);
        WText *sysmon = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-system-monitor")), TextFormat::XHTMLUnsafeText);
        WText *switchLanguage = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-switch-language")), TextFormat::XHTMLUnsafeText);
        WText *exit = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-exit")), TextFormat::XHTMLUnsafeText);

        dashboard->setId("menu-item-dashboard");
        newsletter->setId("menu-item-newsletter");
        subscribers->setId("menu-item-subscribers");
        contacts->setId("menu-item-contacts");
        changeEmail->setId("menu-item-change-email");
        changePassword->setId("menu-item-change-password");
        sysmon->setId("menu-item-system-monitor");
        switchLanguage->setId("menu-item-switch-language");
        exit->setId("menu-item-exit");

        tmpl->bindWidget("dashboard", dashboard);
        tmpl->bindWidget("newsletter", newsletter);
        tmpl->bindWidget("subscribers", subscribers);
        tmpl->bindWidget("contacts", contacts);
        tmpl->bindWidget("admin", new WText(tr("cms-dashboard-admin")));
        tmpl->bindWidget("change-email", changeEmail);
        tmpl->bindWidget("change-password", changePassword);
        tmpl->bindWidget("system-monitor", sysmon);
        tmpl->bindWidget("switch-language", switchLanguage);
        tmpl->bindWidget("exit", exit);

        m_pimpl->Contents = new Wt::WStackedWidget();
        m_pimpl->SystemMonitor = new SysMon(m_cgiRoot);
        m_pimpl->Contents->addWidget(m_pimpl->SystemMonitor);
        tmpl->bindWidget("stcked-widget", m_pimpl->Contents);

        WSignalMapper<WText *, WStackedWidget *> *menuItemSignalMapper = new WSignalMapper<WText *, WStackedWidget *>(m_pimpl.get());
        menuItemSignalMapper->mapped().connect(m_pimpl.get(), &Cms::Impl::OnMenuItemPressed);
        menuItemSignalMapper->mapConnect(dashboard->clicked(), dashboard);
        menuItemSignalMapper->mapConnect(newsletter->clicked(), newsletter);
        menuItemSignalMapper->mapConnect(subscribers->clicked(), subscribers);
        menuItemSignalMapper->mapConnect(contacts->clicked(), contacts);
        menuItemSignalMapper->mapConnect(changeEmail->clicked(), changeEmail);
        menuItemSignalMapper->mapConnect(changePassword->clicked(), changePassword);
        menuItemSignalMapper->mapConnect(sysmon->clicked(), sysmon);
        menuItemSignalMapper->mapConnect(switchLanguage->clicked(), switchLanguage);
        menuItemSignalMapper->mapConnect(exit->clicked(), exit);
    }

    return container;
}

Cms::Impl::Impl(Cms *parent)
    : m_parent(parent),
      LastSelectedMenuItem(nullptr)
{

}

void Cms::Impl::OnMenuItemPressed(WText *sender)
{
    if (LastSelectedMenuItem != nullptr) {
        LastSelectedMenuItem->removeStyleClass("selected");
    }
    LastSelectedMenuItem = sender;
    LastSelectedMenuItem->setStyleClass("selected");

     if (sender->id() == "menu-item-system-monitor") {
         SystemMonitor->Resume();
         Contents->setCurrentIndex(6);
         return;
     } else {
         SystemMonitor->Pause();
     }

    if (sender->id() == "menu-item-dashboard") {
        Contents->setCurrentIndex(0);
    } else if (sender->id() == "menu-item-newsletter") {
        Contents->setCurrentIndex(1);
    } else if (sender->id() == "menu-item-subscribers") {
        Contents->setCurrentIndex(2);
    } else if (sender->id() == "menu-item-contacts") {
        Contents->setCurrentIndex(3);
    } else if (sender->id() == "menu-item-change-email") {
        Contents->setCurrentIndex(4);
    } else if (sender->id() == "menu-item-change-password") {
        Contents->setCurrentIndex(5);

    } else if (sender->id() == "menu-item-switch-language") {
        switch (m_parent->m_cgiEnv->GetCurrentLanguage()) {
        case CgiEnv::Language::None:
        case CgiEnv::Language::Invalid:
            break;
        case CgiEnv::Language::En:
            m_parent->Redirect("/?root&lang=fa");
            break;
        case CgiEnv::Language::Fa:
            m_parent->Redirect("/?root&lang=en");
            break;
        }

        return;

    } else if (sender->id() == "menu-item-exit") {
        std::srand((unsigned int)System::RandSeed());

        m_parent->m_cgiRoot->removeCookie("cms-session-user");
        m_parent->m_cgiRoot->removeCookie("cms-session-token");
        m_parent->Exit("/?root&logout");
        return;

    } else {
        LOG_WARNING("ERROR: INVALID STACKED-WIDGET PAGE ID!");
    }
}

<commit_msg>fontawesome menu icon fix<commit_after>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * The CMS start page.
 */

#include <Wt/WApplication>
#include <Wt/WContainerWidget>
#include <Wt/WSignalMapper>
#include <Wt/WStackedWidget>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include <CoreLib/Random.hpp>
#include <CoreLib/System.hpp>
#include "CgiEnv.hpp"
#include "Cms.hpp"
#include "Cms.hpp"
#include "CmsChangeEmail.hpp"
#include "CmsChangePassword.hpp"
#include "CmsContacts.hpp"
#include "CmsDashboard.hpp"
#include "CmsNewsletter.hpp"
#include "CmsSubscribers.hpp"
#include "Div.hpp"
#include "Pool.hpp"
#include "SysMon.hpp"

using namespace std;
using namespace Wt;
using namespace CoreLib;
using namespace Service;

struct Cms::Impl : public Wt::WObject
{
public:
    Cms *m_parent;
    Wt::WStackedWidget *Contents;
    WText *LastSelectedMenuItem;

    SysMon *SystemMonitor;

public:
    explicit Impl(Cms *parent);

public:
    void OnMenuItemPressed(WText *sender);
};

Cms::Cms(CgiRoot *cgi) :
    Page(cgi),
    m_pimpl(std::make_unique<Cms::Impl>(this))
{
    m_cgiRoot->setTitle(tr("cms-page-title"));

    m_htmlRoot->clear();
    this->clear();
    this->setId("CmsPage");
    this->addWidget(Layout());
    m_htmlRoot->addWidget(this);
}

WWidget *Cms::Layout()
{
    Div *container = new Div("Cms", "container");
    Div *noScript = new Div(container);
    noScript->addWidget(new WText(tr("no-script")));

    std::string htmlData;
    std::string file;
    if (m_cgiEnv->GetCurrentLanguage() == CgiEnv::Language::Fa) {
        file = "../templates/cms-fa.wtml";
    } else {
        file = "../templates/cms.wtml";
    }

    if (CoreLib::FileSystem::Read(file, htmlData)) {
        WTemplate *tmpl = new WTemplate(container);
        tmpl->setTemplateText(WString(htmlData), TextFormat::XHTMLUnsafeText);

        tmpl->bindWidget("brand-title", new WText(tr("cms-page-title")));

        WText *dashboard = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard")), TextFormat::XHTMLUnsafeText);
        WText *newsletter = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-newsletter")), TextFormat::XHTMLUnsafeText);
        WText *subscribers = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-subscribers")), TextFormat::XHTMLUnsafeText);
        WText *contacts = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-contacts")), TextFormat::XHTMLUnsafeText);
        WText *changeEmail = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-admin-change-email")), TextFormat::XHTMLUnsafeText);
        WText *changePassword = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-admin-change-password")), TextFormat::XHTMLUnsafeText);
        WText *sysmon = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-system-monitor")), TextFormat::XHTMLUnsafeText);
        WText *switchLanguage = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-switch-language")), TextFormat::XHTMLUnsafeText);
        WText *exit = new WText(
                    WString("
 {1}
")
                    .arg(tr("cms-dashboard-exit")), TextFormat::XHTMLUnsafeText);

        dashboard->setId("menu-item-dashboard");
        newsletter->setId("menu-item-newsletter");
        subscribers->setId("menu-item-subscribers");
        contacts->setId("menu-item-contacts");
        changeEmail->setId("menu-item-change-email");
        changePassword->setId("menu-item-change-password");
        sysmon->setId("menu-item-system-monitor");
        switchLanguage->setId("menu-item-switch-language");
        exit->setId("menu-item-exit");

        tmpl->bindWidget("dashboard", dashboard);
        tmpl->bindWidget("newsletter", newsletter);
        tmpl->bindWidget("subscribers", subscribers);
        tmpl->bindWidget("contacts", contacts);
        tmpl->bindWidget("admin", new WText(tr("cms-dashboard-admin")));
        tmpl->bindWidget("change-email", changeEmail);
        tmpl->bindWidget("change-password", changePassword);
        tmpl->bindWidget("system-monitor", sysmon);
        tmpl->bindWidget("switch-language", switchLanguage);
        tmpl->bindWidget("exit", exit);

        m_pimpl->Contents = new Wt::WStackedWidget();
        m_pimpl->SystemMonitor = new SysMon(m_cgiRoot);
        m_pimpl->Contents->addWidget(m_pimpl->SystemMonitor);
        tmpl->bindWidget("stcked-widget", m_pimpl->Contents);

        WSignalMapper<WText *, WStackedWidget *> *menuItemSignalMapper = new WSignalMapper<WText *, WStackedWidget *>(m_pimpl.get());
        menuItemSignalMapper->mapped().connect(m_pimpl.get(), &Cms::Impl::OnMenuItemPressed);
        menuItemSignalMapper->mapConnect(dashboard->clicked(), dashboard);
        menuItemSignalMapper->mapConnect(newsletter->clicked(), newsletter);
        menuItemSignalMapper->mapConnect(subscribers->clicked(), subscribers);
        menuItemSignalMapper->mapConnect(contacts->clicked(), contacts);
        menuItemSignalMapper->mapConnect(changeEmail->clicked(), changeEmail);
        menuItemSignalMapper->mapConnect(changePassword->clicked(), changePassword);
        menuItemSignalMapper->mapConnect(sysmon->clicked(), sysmon);
        menuItemSignalMapper->mapConnect(switchLanguage->clicked(), switchLanguage);
        menuItemSignalMapper->mapConnect(exit->clicked(), exit);
    }

    return container;
}

Cms::Impl::Impl(Cms *parent)
    : m_parent(parent),
      LastSelectedMenuItem(nullptr)
{

}

void Cms::Impl::OnMenuItemPressed(WText *sender)
{
    if (LastSelectedMenuItem != nullptr) {
        LastSelectedMenuItem->removeStyleClass("selected");
    }
    LastSelectedMenuItem = sender;
    LastSelectedMenuItem->setStyleClass("selected");

     if (sender->id() == "menu-item-system-monitor") {
         SystemMonitor->Resume();
         Contents->setCurrentIndex(6);
         return;
     } else {
         SystemMonitor->Pause();
     }

    if (sender->id() == "menu-item-dashboard") {
        Contents->setCurrentIndex(0);
    } else if (sender->id() == "menu-item-newsletter") {
        Contents->setCurrentIndex(1);
    } else if (sender->id() == "menu-item-subscribers") {
        Contents->setCurrentIndex(2);
    } else if (sender->id() == "menu-item-contacts") {
        Contents->setCurrentIndex(3);
    } else if (sender->id() == "menu-item-change-email") {
        Contents->setCurrentIndex(4);
    } else if (sender->id() == "menu-item-change-password") {
        Contents->setCurrentIndex(5);

    } else if (sender->id() == "menu-item-switch-language") {
        switch (m_parent->m_cgiEnv->GetCurrentLanguage()) {
        case CgiEnv::Language::None:
        case CgiEnv::Language::Invalid:
            break;
        case CgiEnv::Language::En:
            m_parent->Redirect("/?root&lang=fa");
            break;
        case CgiEnv::Language::Fa:
            m_parent->Redirect("/?root&lang=en");
            break;
        }

        return;

    } else if (sender->id() == "menu-item-exit") {
        std::srand((unsigned int)System::RandSeed());

        m_parent->m_cgiRoot->removeCookie("cms-session-user");
        m_parent->m_cgiRoot->removeCookie("cms-session-token");
        m_parent->Exit("/?root&logout");
        return;

    } else {
        LOG_WARNING("ERROR: INVALID STACKED-WIDGET PAGE ID!");
    }
}

<|endoftext|>


<commit_before>//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements prototype code for serialization of objects in clang.
//  It is not intended yet for public use, but simply is a placeholder to
//  experiment with new serialization features.  Serialization will eventually
//  be integrated as a proper component of the clang libraries.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/CFG.h"
#include "clang.h"
#include "ASTConsumers.h"
#include "clang/AST/TranslationUnit.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Streams.h"
#include <fstream>
#include <cstring>
using namespace clang;

//===----------------------------------------------------------------------===//
// Driver code.
//===----------------------------------------------------------------------===//

namespace {

class SerializationTest : public ASTConsumer {
  TranslationUnit TU;
  Diagnostic &Diags;
  FileManager &FMgr;
public:
  SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts)
                    : TU(LOpts), Diags(d), FMgr(fmgr) {}

  ~SerializationTest();

  virtual void Initialize(ASTContext& context) {
    TU.setContext(&context);
  }

  virtual void HandleTopLevelDecl(Decl *D) {
    TU.AddTopLevelDecl(D);
  }

private:
  bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
  bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
};

} // end anonymous namespace

ASTConsumer*
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr,
                               const LangOptions &LOpts) {

  return new SerializationTest(Diags,FMgr,LOpts);
}

bool SerializationTest::Serialize(llvm::sys::Path& Filename,
                                  llvm::sys::Path& FNameDeclPrint) {
  {
    // Pretty-print the decls to a temp file.
    std::ofstream DeclPP(FNameDeclPrint.c_str());
    assert (DeclPP && "Could not open file for printing out decls.");
    llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));

    for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I)
      FilePrinter->HandleTopLevelDecl(*I);
  }

  // Serialize the translation unit.
  return EmitASTBitcodeFile(TU,Filename);
}

bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
                                    llvm::sys::Path& FNameDeclPrint) {

  // Deserialize the translation unit.
  TranslationUnit* NewTU = ReadASTBitcodeFile(Filename,FMgr);

  if (!NewTU)
    return false;

  {
    // Pretty-print the deserialized decls to a temp file.
    std::ofstream DeclPP(FNameDeclPrint.c_str());
    assert (DeclPP && "Could not open file for printing out decls.");
    llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));

    for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
      FilePrinter->HandleTopLevelDecl(*I);
  }

  return true;
}

namespace {
  class TmpDirJanitor {
    llvm::sys::Path& Dir;
  public:
    explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}

    ~TmpDirJanitor() {
      llvm::cerr << "Removing: " << Dir.c_str() << '\n';
      Dir.eraseFromDisk(true);
    }
  };
}

SerializationTest::~SerializationTest() {

  std::string ErrMsg;
  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);

  if (Dir.isEmpty()) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  TmpDirJanitor RemoveTmpOnExit(Dir);

  llvm::sys::Path FNameDeclBefore = Dir;
  FNameDeclBefore.appendComponent("test.decl_before.txt");

  if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  llvm::sys::Path FNameDeclAfter = Dir;
  FNameDeclAfter.appendComponent("test.decl_after.txt");

  if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  llvm::sys::Path ASTFilename = Dir;
  ASTFilename.appendComponent("test.ast");

  if (ASTFilename.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  // Serialize and then deserialize the ASTs.
  bool status = Serialize(ASTFilename, FNameDeclBefore);
  assert (status && "Serialization failed.");
  status = Deserialize(ASTFilename, FNameDeclAfter);
  assert (status && "Deserialization failed.");

  // Read both pretty-printed files and compare them.

  using llvm::MemoryBuffer;

  llvm::OwningPtr<MemoryBuffer>
    MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str()));

  if(!MBufferSer) {
    llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
    return;
  }

  llvm::OwningPtr<MemoryBuffer>
    MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str()));

  if(!MBufferDSer) {
    llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
    return;
  }

  const char *p1 = MBufferSer->getBufferStart();
  const char *e1 = MBufferSer->getBufferEnd();
  const char *p2 = MBufferDSer->getBufferStart();
  const char *e2 = MBufferDSer->getBufferEnd();

  if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
    for ( ; p1 != e1 ; ++p1, ++p2  )
      if (*p1 != *p2) break;

  if (p1 != e1 || p2 != e2 )
    llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
  else
    llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
}
<commit_msg>Call delete on the deserialized TranslationUnit object.<commit_after>//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements prototype code for serialization of objects in clang.
//  It is not intended yet for public use, but simply is a placeholder to
//  experiment with new serialization features.  Serialization will eventually
//  be integrated as a proper component of the clang libraries.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/CFG.h"
#include "clang.h"
#include "ASTConsumers.h"
#include "clang/AST/TranslationUnit.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Streams.h"
#include <fstream>
#include <cstring>
using namespace clang;

//===----------------------------------------------------------------------===//
// Driver code.
//===----------------------------------------------------------------------===//

namespace {

class SerializationTest : public ASTConsumer {
  TranslationUnit TU;
  Diagnostic &Diags;
  FileManager &FMgr;
public:
  SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts)
                    : TU(LOpts), Diags(d), FMgr(fmgr) {}

  ~SerializationTest();

  virtual void Initialize(ASTContext& context) {
    TU.setContext(&context);
  }

  virtual void HandleTopLevelDecl(Decl *D) {
    TU.AddTopLevelDecl(D);
  }

private:
  bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
  bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
};

} // end anonymous namespace

ASTConsumer*
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr,
                               const LangOptions &LOpts) {

  return new SerializationTest(Diags,FMgr,LOpts);
}

bool SerializationTest::Serialize(llvm::sys::Path& Filename,
                                  llvm::sys::Path& FNameDeclPrint) {
  {
    // Pretty-print the decls to a temp file.
    std::ofstream DeclPP(FNameDeclPrint.c_str());
    assert (DeclPP && "Could not open file for printing out decls.");
    llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));

    for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I)
      FilePrinter->HandleTopLevelDecl(*I);
  }

  // Serialize the translation unit.
  return EmitASTBitcodeFile(TU,Filename);
}

bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
                                    llvm::sys::Path& FNameDeclPrint) {

  // Deserialize the translation unit.
  TranslationUnit* NewTU = ReadASTBitcodeFile(Filename,FMgr);

  if (!NewTU)
    return false;

  {
    // Pretty-print the deserialized decls to a temp file.
    std::ofstream DeclPP(FNameDeclPrint.c_str());
    assert (DeclPP && "Could not open file for printing out decls.");
    llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));

    for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
      FilePrinter->HandleTopLevelDecl(*I);
  }

  delete NewTU;

  return true;
}

namespace {
  class TmpDirJanitor {
    llvm::sys::Path& Dir;
  public:
    explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}

    ~TmpDirJanitor() {
      llvm::cerr << "Removing: " << Dir.c_str() << '\n';
      Dir.eraseFromDisk(true);
    }
  };
}

SerializationTest::~SerializationTest() {

  std::string ErrMsg;
  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);

  if (Dir.isEmpty()) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  TmpDirJanitor RemoveTmpOnExit(Dir);

  llvm::sys::Path FNameDeclBefore = Dir;
  FNameDeclBefore.appendComponent("test.decl_before.txt");

  if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  llvm::sys::Path FNameDeclAfter = Dir;
  FNameDeclAfter.appendComponent("test.decl_after.txt");

  if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  llvm::sys::Path ASTFilename = Dir;
  ASTFilename.appendComponent("test.ast");

  if (ASTFilename.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }

  // Serialize and then deserialize the ASTs.
  bool status = Serialize(ASTFilename, FNameDeclBefore);
  assert (status && "Serialization failed.");
  status = Deserialize(ASTFilename, FNameDeclAfter);
  assert (status && "Deserialization failed.");

  // Read both pretty-printed files and compare them.

  using llvm::MemoryBuffer;

  llvm::OwningPtr<MemoryBuffer>
    MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str()));

  if(!MBufferSer) {
    llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
    return;
  }

  llvm::OwningPtr<MemoryBuffer>
    MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str()));

  if(!MBufferDSer) {
    llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
    return;
  }

  const char *p1 = MBufferSer->getBufferStart();
  const char *e1 = MBufferSer->getBufferEnd();
  const char *p2 = MBufferDSer->getBufferStart();
  const char *e2 = MBufferDSer->getBufferEnd();

  if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
    for ( ; p1 != e1 ; ++p1, ++p2  )
      if (*p1 != *p2) break;

  if (p1 != e1 || p2 != e2 )
    llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
  else
    llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
}
<|endoftext|>


<commit_before>// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/common/user_agent/user_agent.h"

#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/synchronization/lock.h"
#include "webkit/common/user_agent/user_agent_util.h"

namespace webkit_glue {

namespace {

class UserAgentState {
 public:
  UserAgentState();
  ~UserAgentState();

  void Set(const std::string& user_agent, bool overriding);
  const std::string& Get(const GURL& url) const;

 private:
  mutable std::string user_agent_;
  // The UA string when we're pretending to be Mac Safari or Win Firefox.
  mutable std::string user_agent_for_spoofing_hack_;

  mutable bool user_agent_requested_;
  bool user_agent_is_overridden_;

  // This object can be accessed from multiple threads, so use a lock around
  // accesses to the data members.
  mutable base::Lock lock_;
};

UserAgentState::UserAgentState()
    : user_agent_requested_(false),
      user_agent_is_overridden_(false) {
}

UserAgentState::~UserAgentState() {
}

void UserAgentState::Set(const std::string& user_agent, bool overriding) {
  base::AutoLock auto_lock(lock_);
  if (user_agent == user_agent_) {
    // We allow the user agent to be set multiple times as long as it
    // is set to the same value, in order to simplify unit testing
    // given g_user_agent is a global.
    return;
  }
  DCHECK(!user_agent.empty());
  DCHECK(!user_agent_requested_) << "Setting the user agent after someone has "
      "already requested it can result in unexpected behavior.";
  user_agent_is_overridden_ = overriding;
  user_agent_ = user_agent;
}

bool IsMicrosoftSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
#if defined(OS_MACOSX)
  // The landing page for updating Silverlight gives a confusing experience
  // in browsers that Silverlight doesn't officially support; spoof as
  // Safari to reduce the chance that users won't complete updates.
  // Should be removed if the sniffing is removed: http://crbug.com/88211
  if (url.host() == "www.microsoft.com" &&
      StartsWithASCII(url.path(), "/getsilverlight", false)) {
    return true;
  }
#endif
  return false;
}

bool IsYahooSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
#if defined(OS_MACOSX)
  if ((url.host() == "downloads.yahoo.co.jp" &&
      StartsWithASCII(url.path(), "/docs/silverlight/", true)) ||
      url.host() == "gyao.yahoo.co.jp") {
    return true;
  }
#elif defined(OS_WIN)
  if (url.host() == "promotion.shopping.yahoo.co.jp") {
    return true;
  }
#endif
  return false;
}

const std::string& UserAgentState::Get(const GURL& url) const {
  base::AutoLock auto_lock(lock_);
  user_agent_requested_ = true;

  DCHECK(!user_agent_.empty());

  // Workarounds for sites that use misguided UA sniffing.
  if (!user_agent_is_overridden_) {
    if (IsMicrosoftSiteThatNeedsSpoofingForSilverlight(url) ||
        IsYahooSiteThatNeedsSpoofingForSilverlight(url)) {
      if (user_agent_for_spoofing_hack_.empty()) {
#if defined(OS_MACOSX)
        user_agent_for_spoofing_hack_ =
            BuildUserAgentFromProduct("Version/5.1.1 Safari/534.51.22");
#elif defined(OS_WIN)
        // Pretend to be Firefox. Silverlight doesn't support Win Safari.
        base::StringAppendF(
            &user_agent_for_spoofing_hack_,
            "Mozilla/5.0 (%s) Gecko/20100101 Firefox/8.0",
            webkit_glue::BuildOSCpuInfo().c_str());
#endif
      }
      DCHECK(!user_agent_for_spoofing_hack_.empty());
      return user_agent_for_spoofing_hack_;
    }
  }

  return user_agent_;
}

base::LazyInstance<UserAgentState> g_user_agent = LAZY_INSTANCE_INITIALIZER;

}  // namespace

void SetUserAgent(const std::string& user_agent, bool overriding) {
  g_user_agent.Get().Set(user_agent, overriding);
}

const std::string& GetUserAgent(const GURL& url) {
  return g_user_agent.Get().Get(url);
}

}  // namespace webkit_glue
<commit_msg>Disable Mac-specific UA spoofing for iOS<commit_after>// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/common/user_agent/user_agent.h"

#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/synchronization/lock.h"
#include "webkit/common/user_agent/user_agent_util.h"

namespace webkit_glue {

namespace {

class UserAgentState {
 public:
  UserAgentState();
  ~UserAgentState();

  void Set(const std::string& user_agent, bool overriding);
  const std::string& Get(const GURL& url) const;

 private:
  mutable std::string user_agent_;
  // The UA string when we're pretending to be Mac Safari or Win Firefox.
  mutable std::string user_agent_for_spoofing_hack_;

  mutable bool user_agent_requested_;
  bool user_agent_is_overridden_;

  // This object can be accessed from multiple threads, so use a lock around
  // accesses to the data members.
  mutable base::Lock lock_;
};

UserAgentState::UserAgentState()
    : user_agent_requested_(false),
      user_agent_is_overridden_(false) {
}

UserAgentState::~UserAgentState() {
}

void UserAgentState::Set(const std::string& user_agent, bool overriding) {
  base::AutoLock auto_lock(lock_);
  if (user_agent == user_agent_) {
    // We allow the user agent to be set multiple times as long as it
    // is set to the same value, in order to simplify unit testing
    // given g_user_agent is a global.
    return;
  }
  DCHECK(!user_agent.empty());
  DCHECK(!user_agent_requested_) << "Setting the user agent after someone has "
      "already requested it can result in unexpected behavior.";
  user_agent_is_overridden_ = overriding;
  user_agent_ = user_agent;
}

bool IsMicrosoftSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
#if defined(OS_MACOSX) && !defined(OS_IOS)
  // The landing page for updating Silverlight gives a confusing experience
  // in browsers that Silverlight doesn't officially support; spoof as
  // Safari to reduce the chance that users won't complete updates.
  // Should be removed if the sniffing is removed: http://crbug.com/88211
  if (url.host() == "www.microsoft.com" &&
      StartsWithASCII(url.path(), "/getsilverlight", false)) {
    return true;
  }
#endif
  return false;
}

bool IsYahooSiteThatNeedsSpoofingForSilverlight(const GURL& url) {
#if defined(OS_MACOSX) && !defined(OS_IOS)
  if ((url.host() == "downloads.yahoo.co.jp" &&
      StartsWithASCII(url.path(), "/docs/silverlight/", true)) ||
      url.host() == "gyao.yahoo.co.jp") {
    return true;
  }
#elif defined(OS_WIN)
  if (url.host() == "promotion.shopping.yahoo.co.jp") {
    return true;
  }
#endif
  return false;
}

const std::string& UserAgentState::Get(const GURL& url) const {
  base::AutoLock auto_lock(lock_);
  user_agent_requested_ = true;

  DCHECK(!user_agent_.empty());

  // Workarounds for sites that use misguided UA sniffing.
  if (!user_agent_is_overridden_) {
    if (IsMicrosoftSiteThatNeedsSpoofingForSilverlight(url) ||
        IsYahooSiteThatNeedsSpoofingForSilverlight(url)) {
      if (user_agent_for_spoofing_hack_.empty()) {
#if defined(OS_MACOSX) && !defined(OS_IOS)
        user_agent_for_spoofing_hack_ =
            BuildUserAgentFromProduct("Version/5.1.1 Safari/534.51.22");
#elif defined(OS_WIN)
        // Pretend to be Firefox. Silverlight doesn't support Win Safari.
        base::StringAppendF(
            &user_agent_for_spoofing_hack_,
            "Mozilla/5.0 (%s) Gecko/20100101 Firefox/8.0",
            webkit_glue::BuildOSCpuInfo().c_str());
#endif
      }
      DCHECK(!user_agent_for_spoofing_hack_.empty());
      return user_agent_for_spoofing_hack_;
    }
  }

  return user_agent_;
}

base::LazyInstance<UserAgentState> g_user_agent = LAZY_INSTANCE_INITIALIZER;

}  // namespace

void SetUserAgent(const std::string& user_agent, bool overriding) {
  g_user_agent.Get().Set(user_agent, overriding);
}

const std::string& GetUserAgent(const GURL& url) {
  return g_user_agent.Get().Get(url);
}

}  // namespace webkit_glue
<|endoftext|>