PageRenderTime 103ms CodeModel.GetById 60ms app.highlight 11ms RepoModel.GetById 29ms app.codeStats 0ms

/mordor/http/servlet.h

http://github.com/mozy/mordor
C Header | 134 lines | 86 code | 24 blank | 24 comment | 0 complexity | 59e7417b0ba6b83aa12b19033398c6ec MD5 | raw file
  1#ifndef __MORDOR_HTTP_SERVLET_H__
  2#define __MORDOR_HTTP_SERVLET_H__
  3// Copyright (c) 2010 - Mozy, Inc.
  4
  5#include <boost/bind.hpp>
  6#include <boost/function.hpp>
  7#include <boost/shared_ptr.hpp>
  8#include <boost/variant.hpp>
  9
 10#include "mordor/factory.h"
 11#include "mordor/uri.h"
 12
 13namespace Mordor {
 14namespace HTTP {
 15
 16class ServerRequest;
 17
 18class Servlet
 19{
 20public:
 21    typedef boost::shared_ptr<Servlet> ptr;
 22
 23public:
 24    virtual ~Servlet() {}
 25
 26    virtual void request(boost::shared_ptr<ServerRequest> request) = 0;
 27    void operator()(boost::shared_ptr<ServerRequest> requestPtr)
 28    { request(requestPtr); }
 29};
 30
 31class ServletFilter : public Servlet
 32{
 33public:
 34    typedef boost::shared_ptr<ServletFilter> ptr;
 35
 36public:
 37    ServletFilter(Servlet::ptr parent) : m_parent(parent) {}
 38
 39    Servlet::ptr parent() { return m_parent; }
 40
 41private:
 42    Servlet::ptr m_parent;
 43};
 44
 45/// Dispatches different parts of the URI namespace to registered servlets
 46///
 47/// Supports vhosts - if the registered URI has an authority defined, it will
 48/// create a vhost for that authority, and only accept requests with the given
 49/// Host header.  Other or missing Host headers will fall back to a servlet
 50/// defined with no authority.
 51/// Supports wildcard - '*' can be used in URI segments to allow matching any
 52/// content in the segment
 53/// Differing schemes (http vs. https) are not currently supported; the scheme
 54/// is currently ignored
 55/// URI match rule:
 56/// * authority match first, if no authority matches, fall back to rules in no authority
 57/// - non-wildcard character matching rule:
 58///   * longest path match first
 59///   * the same path is not allowed to register more than once, otherwise
 60///     assertion will be triggered.
 61/// - wildcard character matching rule:
 62///   * longest path match first
 63///   * if there is more than one path matches, following precedence will be considered
 64///     - non-wildcard path,
 65///     - wildcard path with right-most postion of the left-most '*'
 66class ServletDispatcher : public Servlet
 67{
 68private:
 69    typedef boost::variant<boost::shared_ptr<Servlet>,
 70            boost::function<Servlet *()> > ServletOrCreator;
 71    typedef std::map<URI::Path, ServletOrCreator> ServletPathMap;
 72    typedef ServletPathMap ServletWildcardPathMap;
 73    typedef std::pair<ServletPathMap, ServletWildcardPathMap> ServletPathMapPair;
 74    typedef std::map<URI::Authority, ServletPathMapPair> ServletHostMap;
 75public:
 76    typedef boost::shared_ptr<ServletDispatcher> ptr;
 77
 78public:
 79    ServletDispatcher(bool enableWildcard = false)
 80        : m_enableWildcard(enableWildcard)
 81    {}
 82
 83public:
 84    /// Use to register a servlet that can share the same Servlet object every
 85    /// time (saves a boost::bind and heap allocation for every request)
 86    void registerServlet(const URI &uri, boost::shared_ptr<Servlet> servlet)
 87    { registerServlet(uri, ServletOrCreator(servlet)); }
 88
 89    template <class T>
 90    void registerServlet(const URI &uri)
 91    {
 92        typedef Creator<Servlet, T> CreatorType;
 93        boost::shared_ptr<CreatorType> creator(new CreatorType());
 94        registerServlet(boost::bind(&CreatorType::create0, creator));
 95    }
 96    template <class T, class A1>
 97    void registerServlet(const URI &uri, A1 a1)
 98    {
 99        typedef Creator<Servlet, T, A1> CreatorType;
100        boost::shared_ptr<CreatorType> creator(new CreatorType());
101        registerServlet(uri, boost::bind(&CreatorType::create1, creator, a1));
102    }
103    template <class T, class A1, class A2>
104    void registerServlet(const URI &uri, A1 a1, A2 a2)
105    {
106        typedef Creator<Servlet, T, A1, A2> CreatorType;
107        boost::shared_ptr<CreatorType> creator(new CreatorType());
108        registerServlet(uri, boost::bind(&CreatorType::create2, creator, a1,
109            a2));
110    }
111
112    Servlet::ptr getServlet(const URI &uri);
113
114    void request(boost::shared_ptr<ServerRequest> request);
115
116    static bool isWildcardPath(const URI::Path &path);
117    static bool wildcardPathMatch(const URI::Path &wildPath, const URI::Path &path);
118
119private:
120    Servlet::ptr getServlet(ServletPathMapPair &vhost, const URI::Path &path);
121    Servlet::ptr getServletWildcard(ServletWildcardPathMap &vhost, const URI::Path &path);
122
123    void registerServlet(const URI &uri, const ServletOrCreator &servlet);
124
125    static Servlet::ptr getServletPtr(ServletOrCreator &);
126
127private:
128    ServletHostMap m_servlets;
129    bool m_enableWildcard;
130};
131
132}}
133
134#endif