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