PageRenderTime 93ms CodeModel.GetById 40ms app.highlight 17ms RepoModel.GetById 34ms app.codeStats 0ms

/mordor/http/servlet.cpp

http://github.com/mozy/mordor
C++ | 137 lines | 119 code | 13 blank | 5 comment | 33 complexity | 363f8945c90fc110f2bf700c55aa3911 MD5 | raw file
  1// Copyright (c) 2010 - Mozy, Inc.
  2
  3#include "servlet.h"
  4
  5#include "mordor/assert.h"
  6#include "server.h"
  7
  8namespace Mordor {
  9namespace HTTP {
 10
 11Servlet::ptr
 12ServletDispatcher::getServletPtr(ServletDispatcher::ServletOrCreator &creator)
 13{
 14    Servlet::ptr servletPtr = boost::get<Servlet::ptr>(creator);
 15    if (servletPtr)
 16        return servletPtr;
 17    else
 18        return Servlet::ptr(boost::get<boost::function<Servlet *()> >(creator)());
 19}
 20
 21Servlet::ptr
 22ServletDispatcher::getServlet(const URI &uri)
 23{
 24    MORDOR_ASSERT(!uri.authority.userinfoDefined());
 25    Servlet::ptr result;
 26    if (m_servlets.empty())
 27        return result;
 28    URI copy(uri);
 29    copy.normalize();
 30    ServletHostMap::iterator it = m_servlets.find(copy.authority);
 31    if (it != m_servlets.end()) {
 32        result = getServlet(it->second, copy.path);
 33        if (result)
 34            return result;
 35    }
 36    if (copy.authority.hostDefined()) {
 37        // fall back to no authority defined scenario
 38        it = m_servlets.find(URI::Authority());
 39        if (it != m_servlets.end())
 40            result = getServlet(it->second, copy.path);
 41    }
 42    return result;
 43}
 44
 45void
 46ServletDispatcher::request(ServerRequest::ptr request)
 47{
 48    URI uri = request->request().requestLine.uri;
 49    if (!request->request().request.host.empty())
 50        uri.authority = request->request().request.host;
 51    Servlet::ptr servlet = getServlet(uri);
 52    if (servlet)
 53        servlet->request(request);
 54    else
 55        respondError(request, NOT_FOUND);
 56}
 57
 58Servlet::ptr
 59ServletDispatcher::getServletWildcard(ServletWildcardPathMap &vhost, const URI::Path &path)
 60{
 61    // reverse order because '*' < [a-zA-Z]
 62    for (ServletWildcardPathMap::reverse_iterator it = vhost.rbegin();
 63        it != vhost.rend(); ++it) {
 64        if (wildcardPathMatch(it->first, path))
 65            return getServletPtr(it->second);
 66    }
 67    return Servlet::ptr();
 68}
 69
 70Servlet::ptr
 71ServletDispatcher::getServlet(ServletPathMapPair &vhosts, const URI::Path &path)
 72{
 73    URI::Path copy(path);
 74    while (!copy.segments.empty()) {
 75        // search from non-wildcard path
 76        ServletPathMap::iterator it = vhosts.first.find(copy);
 77        if (it != vhosts.first.end())
 78            return getServletPtr(it->second);
 79        if (m_enableWildcard) {
 80            Servlet::ptr result = getServletWildcard(vhosts.second, copy);
 81            if (result)
 82                return result;
 83        }
 84        // can't find any match, shorten the path
 85        if (!copy.segments.back().empty()) {
 86            copy.segments.back().clear();
 87        } else {
 88            copy.segments.pop_back();
 89        }
 90    }
 91    return Servlet::ptr();
 92}
 93
 94void
 95ServletDispatcher::registerServlet(const URI &uri,
 96    const ServletOrCreator &servlet)
 97{
 98    MORDOR_ASSERT(!uri.authority.userinfoDefined());
 99    MORDOR_ASSERT(!uri.queryDefined());
100    MORDOR_ASSERT(!uri.fragmentDefined());
101    URI copy(uri);
102    copy.normalize();
103    ServletPathMap * vhost = NULL;
104    if (m_enableWildcard && isWildcardPath(copy.path))
105        vhost = &(m_servlets[copy.authority].second);
106    else
107        vhost = &(m_servlets[copy.authority].first);
108    MORDOR_ASSERT(vhost->find(copy.path) == vhost->end());
109    (*vhost)[copy.path] = servlet;
110}
111
112bool
113ServletDispatcher::wildcardPathMatch(const URI::Path &wildPath, const URI::Path &path)
114{
115    if (path.segments.size() != wildPath.segments.size())
116        return false;
117
118    for (size_t i = 0; i < path.segments.size(); ++i) {
119        if (wildPath.segments[i] == "*")
120            continue;
121        if (wildPath.segments[i] != path.segments[i])
122            return false;
123    }
124    return true;
125}
126
127bool
128ServletDispatcher::isWildcardPath(const URI::Path &path)
129{
130    for (std::vector<std::string>::const_iterator it=path.segments.begin();
131        it!=path.segments.end(); ++it) {
132        if (*it == "*") return true;
133    }
134    return false;
135}
136
137}}