From 1751782d8e3c9d4574754463ffd43373cf92133a Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Thu, 19 Jan 2006 21:43:51 +0000 Subject: [PATCH] Implemented first bits of http_file filter which serves plain files via HTTP. Needs to add XML config parsing + mime type reading. --- src/Makefile.am | 3 +- src/factory_static.cpp | 5 +- src/filter_http_file.cpp | 223 ++++++++++++++++++++++++++++++++++++++++++++++ src/filter_http_file.hpp | 41 +++++++++ src/util.cpp | 35 +++++++- src/util.hpp | 6 +- 6 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 src/filter_http_file.cpp create mode 100644 src/filter_http_file.hpp diff --git a/src/Makefile.am b/src/Makefile.am index cedd45a..05bd100 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.45 2006-01-19 12:18:09 marc Exp $ +## $Id: Makefile.am,v 1.46 2006-01-19 21:43:51 adam Exp $ MAINTAINERCLEANFILES = Makefile.in config.in config.hpp @@ -28,6 +28,7 @@ libyp2_la_SOURCES = \ filter_backend_test.cpp filter_backend_test.hpp \ filter_session_shared.cpp filter_session_shared.hpp \ filter_template.cpp filter_template.hpp \ + filter_http_file.cpp filter_http_file.hpp \ factory_static.cpp factory_static.hpp \ pipe.cpp pipe.hpp \ util.cpp util.hpp \ diff --git a/src/factory_static.cpp b/src/factory_static.cpp index 8e7f283..41bd521 100644 --- a/src/factory_static.cpp +++ b/src/factory_static.cpp @@ -1,8 +1,7 @@ -/* $Id: factory_static.cpp,v 1.6 2006-01-15 20:03:14 adam Exp $ +/* $Id: factory_static.cpp,v 1.7 2006-01-19 21:43:51 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% - */ #include @@ -19,6 +18,7 @@ #include "filter_auth_simple.hpp" #include "filter_backend_test.hpp" #include "filter_frontend_net.hpp" +#include "filter_http_file.hpp" #include "filter_log.hpp" #include "filter_multi.hpp" #include "filter_session_shared.hpp" @@ -32,6 +32,7 @@ yp2::FactoryStatic::FactoryStatic() &yp2_filter_auth_simple, &yp2_filter_backend_test, &yp2_filter_frontend_net, + &yp2_filter_http_file, &yp2_filter_log, &yp2_filter_multi, &yp2_filter_session_shared, diff --git a/src/filter_http_file.cpp b/src/filter_http_file.cpp new file mode 100644 index 0000000..533f575 --- /dev/null +++ b/src/filter_http_file.cpp @@ -0,0 +1,223 @@ +/* $Id: filter_http_file.cpp,v 1.1 2006-01-19 21:44:26 adam Exp $ + Copyright (c) 2005, Index Data. + +%LICENSE% + */ + +#include "config.hpp" + +#include "filter.hpp" +#include "package.hpp" + +#include + +#include "util.hpp" +#include "filter_http_file.hpp" + +#include +#include + +#include + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_SYS_STAT_H +#include +#endif + +namespace yf = yp2::filter; + +namespace yp2 { + namespace filter { + struct HttpFile::Area { + std::string m_url_path_prefix; + std::string m_file_root; + }; + class HttpFile::Mime { + friend class Rep; + std::string m_type; + public: + Mime(std::string type); + Mime(); + }; + class HttpFile::Rep { + friend class HttpFile; + + typedef std::list AreaList; + typedef std::map MimeMap; + + MimeMap m_ext_to_map; + AreaList m_area_list; + void fetch_uri(yp2::Session &session, + Z_HTTP_Request *req, yp2::Package &package); + void fetch_file(yp2::Session &session, + Z_HTTP_Request *req, + std::string &fname, yp2::Package &package); + std::string get_mime_type(std::string &fname); + }; + } +} + +yf::HttpFile::Mime::Mime() {} + +yf::HttpFile::Mime::Mime(std::string type) : m_type(type) {} + +yf::HttpFile::HttpFile() : m_p(new Rep) +{ + m_p->m_ext_to_map["html"] = Mime("text/html"); + m_p->m_ext_to_map["htm"] = Mime("text/html"); + m_p->m_ext_to_map["png"] = Mime("image/png"); + m_p->m_ext_to_map["txt"] = Mime("text/plain"); + m_p->m_ext_to_map["text"] = Mime("text/plain"); + m_p->m_ext_to_map["asc"] = Mime("text/plain"); + m_p->m_ext_to_map["xml"] = Mime("application/xml"); + m_p->m_ext_to_map["xsl"] = Mime("application/xml"); + + Area a; + a.m_url_path_prefix = "/etc"; + a.m_file_root = ".."; + m_p->m_area_list.push_back(a); +} + +yf::HttpFile::~HttpFile() +{ +} + +std::string yf::HttpFile::Rep::get_mime_type(std::string &fname) +{ + std::string file_part = fname; + std::string::size_type p = fname.find_last_of('/'); + + if (p != std::string::npos) + file_part = fname.substr(p+1); + + p = file_part.find_last_of('.'); + std::string content_type; + if (p != std::string::npos) + { + std::string ext = file_part.substr(p+1); + MimeMap::const_iterator it = m_ext_to_map.find(ext); + + if (it != m_ext_to_map.end()) + content_type = it->second.m_type; + } + if (content_type.length() == 0) + content_type = "application/octet-stream"; + return content_type; +} + +void yf::HttpFile::Rep::fetch_file(yp2::Session &session, + Z_HTTP_Request *req, + std::string &fname, yp2::Package &package) +{ + struct stat sbuf; + yp2::odr o; + + if (stat(fname.c_str(), &sbuf)) + { + Z_GDU *gdu = o.create_HTTP_Response(session, req, 404); + package.response() = gdu; + return; + } + if ((sbuf.st_mode & S_IFMT) != S_IFREG) + { + Z_GDU *gdu = o.create_HTTP_Response(session, req, 404); + package.response() = gdu; + return; + } + if (sbuf.st_size > (off_t) 1000000) + { + Z_GDU *gdu = o.create_HTTP_Response(session, req, 404); + package.response() = gdu; + return; + } + + FILE *f = fopen(fname.c_str(), "rb"); + if (!f) + { + Z_GDU *gdu = o.create_HTTP_Response(session, req, 404); + package.response() = gdu; + return; + } + Z_GDU *gdu = o.create_HTTP_Response(session, req, 200); + + Z_HTTP_Response *hres = gdu->u.HTTP_Response; + hres->content_len = sbuf.st_size; + hres->content_buf = (char*) odr_malloc(o, hres->content_len); + fread(hres->content_buf, 1, hres->content_len, f); + + fclose(f); + + std::string content_type = get_mime_type(fname); + + z_HTTP_header_add(o, &hres->headers, + "Content-Type", content_type.c_str()); + package.response() = gdu; +} + +void yf::HttpFile::Rep::fetch_uri(yp2::Session &session, + Z_HTTP_Request *req, yp2::Package &package) +{ + bool sane = true; + std::string path = req->path; + + // we don't consider ?, # yet.. + + // we don't allow .. + std::string::size_type p = path.find(".."); + if (p != std::string::npos) + sane = false; + + if (sane) + { + AreaList::const_iterator it; + for (it = m_area_list.begin(); it != m_area_list.end(); it++) + { + std::string::size_type l = it->m_url_path_prefix.length(); + + if (path.compare(0, l, it->m_url_path_prefix) == 0) + { + std::string fname = it->m_file_root + path; + fetch_file(session, req, fname, package); + return; + } + } + } + yp2::odr o; + Z_GDU *gdu = o.create_HTTP_Response(session, req, 404); + package.response() = gdu; +} + +void yf::HttpFile::process(yp2::Package &package) const +{ + Z_GDU *gdu = package.request().get(); + if (gdu && gdu->which == Z_GDU_HTTP_Request) + m_p->fetch_uri(package.session(), gdu->u.HTTP_Request, package); + else + package.move(); +} + +static yp2::filter::Base* filter_creator() +{ + return new yp2::filter::HttpFile; +} + +extern "C" { + struct yp2_filter_struct yp2_filter_http_file = { + 0, + "http_file", + filter_creator + }; +} + + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/filter_http_file.hpp b/src/filter_http_file.hpp new file mode 100644 index 0000000..b0ebdd4 --- /dev/null +++ b/src/filter_http_file.hpp @@ -0,0 +1,41 @@ +/* $Id: filter_http_file.hpp,v 1.1 2006-01-19 21:44:26 adam Exp $ + Copyright (c) 2005, Index Data. + +%LICENSE% + */ + +#ifndef FILTER_HTTP_FILE_HPP +#define FILTER_HTTP_FILE_HPP + +#include + +#include "filter.hpp" + +namespace yp2 { + namespace filter { + class HttpFile : public Base { + class Rep; + class Area; + class Mime; + boost::scoped_ptr m_p; + public: + HttpFile(); + ~HttpFile(); + void process(yp2::Package & package) const; + }; + } +} + +extern "C" { + extern struct yp2_filter_struct yp2_filter_http_file; +} + +#endif +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/util.cpp b/src/util.cpp index d745065..c8cf573 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,4 +1,4 @@ -/* $Id: util.cpp,v 1.11 2006-01-18 14:10:47 adam Exp $ +/* $Id: util.cpp,v 1.12 2006-01-19 21:43:51 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% @@ -318,6 +318,39 @@ Z_APDU *yp2::odr::create_scanResponse(Z_APDU *in_apdu, return apdu; } +Z_GDU *yp2::odr::create_HTTP_Response(yp2::Session &session, + Z_HTTP_Request *hreq, int code) +{ + const char *response_version = "1.0"; + bool keepalive = false; + if (!strcmp(hreq->version, "1.0")) + { + const char *v = z_HTTP_header_lookup(hreq->headers, "Connection"); + if (v && !strcmp(v, "Keep-Alive")) + keepalive = true; + else + session.close(); + response_version = "1.0"; + } + else + { + const char *v = z_HTTP_header_lookup(hreq->headers, "Connection"); + if (v && !strcmp(v, "close")) + session.close(); + else + keepalive = true; + response_version = "1.1"; + } + + Z_GDU *gdu = z_get_HTTP_Response(m_odr, code); + Z_HTTP_Response *hres = gdu->u.HTTP_Response; + hres->version = odr_strdup(m_odr, response_version); + if (keepalive) + z_HTTP_header_add(m_odr, &hres->headers, "Connection", "Keep-Alive"); + + return gdu; +} + Z_ReferenceId **yp2::util::get_referenceId(Z_APDU *apdu) { switch (apdu->which) diff --git a/src/util.hpp b/src/util.hpp index c905304..f610ce5 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -1,4 +1,4 @@ -/* $Id: util.hpp,v 1.9 2006-01-18 10:57:27 adam Exp $ +/* $Id: util.hpp,v 1.10 2006-01-19 21:43:51 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% @@ -13,6 +13,8 @@ #include +#include "package.hpp" + namespace yp2 { namespace util { bool pqf(ODR odr, Z_APDU *apdu, const std::string &q); @@ -58,6 +60,8 @@ namespace yp2 { Z_APDU *create_scanResponse(Z_APDU *in_apdu, int error, const char *addinfo); Z_APDU *create_APDU(int type, Z_APDU *in_apdu); + Z_GDU *create_HTTP_Response(yp2::Session &session, + Z_HTTP_Request *req, int code); private: ODR m_odr; }; -- 1.7.10.4