Skip to content

Commit

Permalink
query filter added to handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Golubtsov committed Apr 29, 2011
1 parent ce762a6 commit ad134ad
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 80 deletions.
6 changes: 6 additions & 0 deletions debian/changelog
@@ -1,3 +1,9 @@
fastcgi-daemon2 (2.9-1) unstable; urgency=low

* query filter added to handler

-- Ilya Golubtsov (Ilya) <golubtsov@yandex-team.ru> Fri, 29 Apr 2011 10:28:16 +0400

fastcgi-daemon2 (2.8-5) unstable; urgency=low

* error log customization added
Expand Down
4 changes: 2 additions & 2 deletions fastcgi-daemon2-bf.spec
@@ -1,7 +1,7 @@
Summary: fastcgi-daemon2 is an application server for FastCGI
Name: fastcgi-daemon2
Version: 2.8
Release: 5%{?dist}
Version: 2.9
Release: 1%{?dist}

License: Yandex License
Group: System Environment/Libraries
Expand Down
4 changes: 2 additions & 2 deletions fastcgi-daemon2.spec
Expand Up @@ -6,8 +6,8 @@

Summary: fastcgi-daemon2 is an application server for FastCGI
Name: fastcgi-daemon2
Version: 2.8
Release: 5%{?dist}
Version: 2.9
Release: 1%{?dist}

License: Yandex License
Group: System Environment/Libraries
Expand Down
2 changes: 1 addition & 1 deletion include/details/Makefile.am
@@ -1,4 +1,4 @@
noinst_HEADERS = component_context.h componentset.h config.h functors.h \
handler_context.h handlerset.h loader.h parser.h range.h requestimpl.h \
xml.h data_buffer_impl.h string_buffer.h server.h request_cache.h \
thread_pool.h request_thread_pool.h globals.h
thread_pool.h request_thread_pool.h globals.h request_filter.h
5 changes: 3 additions & 2 deletions include/details/handlerset.h
Expand Up @@ -33,13 +33,14 @@ class Config;
class ComponentSet;
class Handler;
class Request;
class RequestFilter;

class HandlerSet : private boost::noncopyable
{
public:
struct HandlerDescription {
typedef std::map<std::string, boost::regex> FilterMap;
FilterMap filters;
typedef std::vector<std::pair<std::string, boost::shared_ptr<RequestFilter> > > FilterArray;
FilterArray filters;
std::vector<Handler*> handlers;
std::string poolName;
std::string id;
Expand Down
99 changes: 99 additions & 0 deletions include/details/request_filter.h
@@ -0,0 +1,99 @@
// Fastcgi Daemon - framework for design highload FastCGI applications on C++
// Copyright (C) 2011 Ilya Golubtsov <golubtsov@yandex-team.ru>

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#ifndef _FASTCGI_DETAILS_REQUEST_FILTER_H_
#define _FASTCGI_DETAILS_REQUEST_FILTER_H_

#include <string>

#include <boost/regex.hpp>


namespace fastcgi
{

class Request;

class RequestFilter {
public:
virtual bool check(const Request *request) const = 0;
};

class RegexFilter {
public:
RegexFilter(const std::string &regex);
~RegexFilter();

bool check(const std::string &value) const;
private:
boost::regex regex_;
};

class UrlFilter : public RequestFilter {
public:
UrlFilter(const std::string &regex);
~UrlFilter();

virtual bool check(const Request *request) const;
private:
RegexFilter regex_;
};

class HostFilter : public RequestFilter {
public:
HostFilter(const std::string &regex);
~HostFilter();

virtual bool check(const Request *request) const;
private:
RegexFilter regex_;
};

class PortFilter : public RequestFilter {
public:
PortFilter(const std::string &regex);
~PortFilter();

virtual bool check(const Request *request) const;
private:
RegexFilter regex_;
};

class AddressFilter : public RequestFilter {
public:
AddressFilter(const std::string &regex);
~AddressFilter();

virtual bool check(const Request *request) const;
private:
RegexFilter regex_;
};

class ParamFilter : public RequestFilter {
public:
ParamFilter(const std::string &name, const std::string &regex);
~ParamFilter();

virtual bool check(const Request *request) const;
private:
std::string name_;
RegexFilter regex_;
};

} // namespace fastcgi

#endif // _FASTCGI_DETAILS_REQUEST_FILTER_H_
2 changes: 1 addition & 1 deletion library/Makefile.am
Expand Up @@ -4,7 +4,7 @@ libfastcgi_daemon2_la_SOURCES = component.cpp config.cpp cookie.cpp except.cpp \
handler.cpp handlerset.cpp loader.cpp logger.cpp parser.cpp request.cpp \
requestimpl.cpp stream.cpp util.cpp xml.cpp componentset.cpp \
component_factory.cpp component_context.cpp data_buffer.cpp string_buffer.cpp \
server.cpp request_thread_pool.cpp globals.cpp response_time_statistics.cpp
server.cpp request_thread_pool.cpp globals.cpp response_time_statistics.cpp request_filter.cpp

AM_CPPFLAGS = -I../include -I../config @xml_CFLAGS@
AM_CXXFLAGS = -pthread
Expand Down
180 changes: 108 additions & 72 deletions library/handlerset.cpp
@@ -1,10 +1,10 @@
#include "settings.h"

#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

#include "details/handlerset.h"
#include "details/componentset.h"
#include "details/request_filter.h"

#include "fastcgi2/config.h"
#include "fastcgi2/component.h"
Expand All @@ -26,92 +26,128 @@ HandlerSet::~HandlerSet() {

void
HandlerSet::init(const Config *config, const ComponentSet *componentSet) {
std::vector<std::string> v;
std::vector<std::string> v;

config->subKeys("/fastcgi/handlers/handler", v);
for (std::vector<std::string>::const_iterator k = v.begin(), end = v.end(); k != end; ++k) {
HandlerDescription handlerDesc;
handlerDesc.poolName = config->asString(*k + "/@pool");
handlerDesc.id = config->asString(*k + "/@id", "");

const char *filterNames[] = {"url", "host", "address", "port"};
for (unsigned i = 0; i < sizeof(filterNames) / sizeof(char*); ++i) {
const std::string filterName = filterNames[i];
const std::string filterValue = config->asString(*k + "/@" + filterName, "");
if (!filterValue.empty()) {
handlerDesc.filters.insert(std::make_pair(filterName, boost::regex(filterValue)));
}
}

std::vector<std::string> components;
config->subKeys(*k + "/component", components);
for (std::vector<std::string>::const_iterator c = components.begin(); c != components.end(); ++c) {
const std::string componentName = config->asString(*c + "/@name");
Component *handlerComponent = componentSet->find(componentName);
if (!handlerComponent) {
throw std::runtime_error("Cannot find component: " + componentName);
}

Handler *handler = dynamic_cast<Handler*>(handlerComponent);
if (!handler) {
throw std::runtime_error("Component " + componentName + " does not implement interface Handler");
}

handlerDesc.handlers.push_back(handler);
}
handlers_.push_back(handlerDesc);
}
for (std::vector<std::string>::const_iterator k = v.begin(), end = v.end(); k != end; ++k) {
HandlerDescription handlerDesc;
handlerDesc.poolName = config->asString(*k + "/@pool");
handlerDesc.id = config->asString(*k + "/@id", "");

std::string url_filter = config->asString(*k + "/@url", "");
if (!url_filter.empty()) {
handlerDesc.filters.push_back(std::make_pair(
"url", boost::shared_ptr<RequestFilter>(new UrlFilter(url_filter))));
}

std::string host_filter = config->asString(*k + "/@host", "");
if (!host_filter.empty()) {
handlerDesc.filters.push_back(std::make_pair(
"host", boost::shared_ptr<RequestFilter>(new HostFilter(host_filter))));
}

std::string port_filter = config->asString(*k + "/@port", "");
if (!port_filter.empty()) {
handlerDesc.filters.push_back(std::make_pair(
"port", boost::shared_ptr<RequestFilter>(new PortFilter(port_filter))));
}

std::string address_filter = config->asString(*k + "/@address", "");
if (!address_filter.empty()) {
handlerDesc.filters.push_back(std::make_pair(
"address", boost::shared_ptr<RequestFilter>(new AddressFilter(address_filter))));
}

std::vector<std::string> q;
config->subKeys(*k + "/param", q);
for (std::vector<std::string>::const_iterator it = q.begin(); it != q.end(); ++it) {
std::string name = config->asString(*it + "/@name", "");
if (name.empty()) {
continue;
}
std::string value = config->asString(*it, "");
if (value.empty()) {
continue;
}
handlerDesc.filters.push_back(std::make_pair(
"param", boost::shared_ptr<RequestFilter>(new ParamFilter(name, value))));
}

std::vector<std::string> components;
config->subKeys(*k + "/component", components);
for (std::vector<std::string>::const_iterator c = components.begin(); c != components.end(); ++c) {
const std::string componentName = config->asString(*c + "/@name");
Component *handlerComponent = componentSet->find(componentName);
if (!handlerComponent) {
throw std::runtime_error("Cannot find component: " + componentName);
}

Handler *handler = dynamic_cast<Handler*>(handlerComponent);
if (!handler) {
throw std::runtime_error("Component " + componentName + " does not implement interface Handler");
}

handlerDesc.handlers.push_back(handler);
}
handlers_.push_back(handlerDesc);
}
}

const HandlerSet::HandlerDescription*
HandlerSet::findURIHandler(const Request *request) const {
for (HandlerArray::const_iterator i = handlers_.begin(); i != handlers_.end(); ++i) {
bool matched = true;
for (HandlerDescription::FilterMap::const_iterator f = i->filters.begin(); f != i->filters.end(); ++f) {
if (f->first == "url" && !boost::regex_match(request->getScriptName(), f->second)) {
matched = false;
break;
}
else if (f->first == "host" && !boost::regex_match(request->getHost(), f->second)) {
matched = false;
break;
}
else if (f->first == "address" && !boost::regex_match(request->getServerAddr(), f->second)) {
matched = false;
break;
}
else if (f->first == "port" && !boost::regex_match(boost::lexical_cast<std::string>(request->getServerPort()), f->second)) {
matched = false;
break;
}
}

if (matched) {
return &(*i);
}
for (HandlerArray::const_iterator i = handlers_.begin(); i != handlers_.end(); ++i) {
bool matched = true;
for (HandlerDescription::FilterArray::const_iterator f = i->filters.begin();
f != i->filters.end();
++f) {
if (f->first == "url" && !f->second->check(request)) {
matched = false;
break;
}
else if (f->first == "host" && !f->second->check(request)) {
matched = false;
break;
}
else if (f->first == "address" && !f->second->check(request)) {
matched = false;
break;
}
else if (f->first == "port" && !f->second->check(request)) {
matched = false;
break;
}
else if (f->first == "param" && !f->second->check(request)) {
matched = false;
break;
}
}

if (matched) {
return &(*i);
}
}
return NULL;
return NULL;
}

void
HandlerSet::findPoolHandlers(const std::string &poolName, std::set<Handler*> &handlers) const {
handlers.clear();
for (HandlerArray::const_iterator it = handlers_.begin();
it != handlers_.end();
++it) {
if (it->poolName == poolName) {
handlers.insert(it->handlers.begin(), it->handlers.end());
}
}
handlers.clear();
for (HandlerArray::const_iterator it = handlers_.begin();
it != handlers_.end();
++it) {
if (it->poolName == poolName) {
handlers.insert(it->handlers.begin(), it->handlers.end());
}
}
}

std::set<std::string>
HandlerSet::getPoolsNeeded() const {
std::set<std::string> pools;
for (HandlerArray::const_iterator i = handlers_.begin(); i != handlers_.end(); ++i) {
pools.insert(i->poolName);
}
return pools;
std::set<std::string> pools;
for (HandlerArray::const_iterator i = handlers_.begin(); i != handlers_.end(); ++i) {
pools.insert(i->poolName);
}
return pools;
}

} // namespace fastcgi
Expand Down

0 comments on commit ad134ad

Please sign in to comment.