1 /* This file is part of Metaproxy.
2 Copyright (C) Index Data
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <metaproxy/filter.hpp>
21 #include <metaproxy/package.hpp>
22 #include <metaproxy/util.hpp>
23 #include "filter_http_file.hpp"
28 #include <boost/thread/mutex.hpp>
35 #include <sys/types.h>
42 namespace mp = metaproxy_1;
43 namespace yf = mp::filter;
45 namespace metaproxy_1 {
47 struct HttpFile::Area {
48 std::string m_url_path_prefix;
49 std::string m_file_root;
53 class HttpFile::Mime {
57 Mime(std::string type);
61 friend class HttpFile;
63 typedef std::list<Area> AreaList;
64 typedef std::map<std::string,Mime> MimeMap;
68 void fetch_uri(mp::Session &session,
69 Z_HTTP_Request *req, mp::Package &package);
70 void fetch_file(mp::Session &session,
72 std::string &fname, mp::Package &package,
74 std::string get_mime_type(std::string &fname);
79 yf::HttpFile::Area::Area() : m_raw(false)
83 yf::HttpFile::Mime::Mime() {}
85 yf::HttpFile::Mime::Mime(std::string type) : m_type(type) {}
87 yf::HttpFile::HttpFile() : m_p(new Rep)
90 m_p->m_ext_to_map["html"] = Mime("text/html");
91 m_p->m_ext_to_map["htm"] = Mime("text/html");
92 m_p->m_ext_to_map["png"] = Mime("image/png");
93 m_p->m_ext_to_map["txt"] = Mime("text/plain");
94 m_p->m_ext_to_map["text"] = Mime("text/plain");
95 m_p->m_ext_to_map["asc"] = Mime("text/plain");
96 m_p->m_ext_to_map["xml"] = Mime("application/xml");
97 m_p->m_ext_to_map["xsl"] = Mime("application/xml");
101 a.m_url_path_prefix = "/etc";
103 m_p->m_area_list.push_back(a);
107 yf::HttpFile::~HttpFile()
111 std::string yf::HttpFile::Rep::get_mime_type(std::string &fname)
113 std::string file_part = fname;
114 std::string::size_type p = fname.find_last_of('/');
116 if (p != std::string::npos)
117 file_part = fname.substr(p+1);
119 p = file_part.find_last_of('.');
120 std::string content_type;
121 if (p != std::string::npos)
123 std::string ext = file_part.substr(p+1);
124 MimeMap::const_iterator it = m_ext_to_map.find(ext);
126 if (it != m_ext_to_map.end())
127 content_type = it->second.m_type;
129 if (content_type.length() == 0)
130 content_type = "application/octet-stream";
134 void yf::HttpFile::Rep::fetch_file(mp::Session &session,
136 std::string &fname, mp::Package &package,
139 mp::odr o(ODR_ENCODE);
141 if (strcmp(req->method, "GET"))
143 Z_GDU *gdu = o.create_HTTP_Response(session, req, 405);
144 package.response() = gdu;
148 FILE *f = fopen(fname.c_str(), "rb");
151 Z_GDU *gdu = o.create_HTTP_Response(session, req, 404);
152 package.response() = gdu;
155 if (fseek(f, 0L, SEEK_END) == -1)
158 Z_GDU *gdu = o.create_HTTP_Response(session, req, 404);
159 package.response() = gdu;
166 Z_GDU *gdu = o.create_HTTP_Response(session, req, 404);
167 package.response() = gdu;
171 char *fbuf = (char*) odr_malloc(o, sz);
174 if (fread(fbuf, sz, 1, f) != 1)
176 Z_GDU *gdu = o.create_HTTP_Response(session, req, 500);
177 package.response() = gdu;
185 mp::odr decode(ODR_DECODE);
188 odr_setbuf(decode, (char *) fbuf, sz, 0);
189 int r = z_GDU(decode, &gdu, 0, 0);
192 gdu = o.create_HTTP_Response(session, req, 500);
197 gdu = o.create_HTTP_Response(session, req, 200);
198 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
199 hres->content_len = sz;
200 hres->content_buf = fbuf;
201 std::string content_type = get_mime_type(fname);
202 z_HTTP_header_add(o, &hres->headers,
203 "Content-Type", content_type.c_str());
205 package.response() = gdu;
208 void yf::HttpFile::Rep::fetch_uri(mp::Session &session,
209 Z_HTTP_Request *req, mp::Package &package)
212 std::string::size_type p;
213 std::string path = req->path;
216 if (p != std::string::npos)
217 path = path.erase(p);
220 if (p != std::string::npos)
221 path = path.erase(p);
223 path = mp::util::uri_decode(path);
227 if (p != std::string::npos)
232 AreaList::const_iterator it;
233 for (it = m_area_list.begin(); it != m_area_list.end(); it++)
235 std::string::size_type l = it->m_url_path_prefix.length();
237 if (path.compare(0, l, it->m_url_path_prefix) == 0)
239 std::string fname = it->m_file_root + path.substr(l);
240 package.log("http_file", YLOG_LOG, "%s", fname.c_str());
241 fetch_file(session, req, fname, package, it->m_raw);
249 void yf::HttpFile::process(mp::Package &package) const
251 Z_GDU *gdu = package.request().get();
252 if (gdu && gdu->which == Z_GDU_HTTP_Request)
253 m_p->fetch_uri(package.session(), gdu->u.HTTP_Request, package);
258 void mp::filter::HttpFile::configure(const xmlNode * ptr, bool test_only,
261 for (ptr = ptr->children; ptr; ptr = ptr->next)
263 if (ptr->type != XML_ELEMENT_NODE)
265 if (!strcmp((const char *) ptr->name, "mimetypes"))
267 std::string fname = mp::xml::get_text(ptr);
273 throw mp::filter::FilterException
274 ("Can not open mime types file " + fname);
277 std::vector<std::string> args;
278 while (f.getline(args))
281 for (i = 1; i<args.size(); i++)
282 m_p->m_ext_to_map[args[i]] = args[0];
285 else if (!strcmp((const char *) ptr->name, "area"))
287 xmlNode *a_node = ptr->children;
290 for (; a_node; a_node = a_node->next)
292 if (a_node->type != XML_ELEMENT_NODE)
295 if (mp::xml::is_element_mp(a_node, "documentroot"))
296 a.m_file_root = mp::xml::get_text(a_node);
297 else if (mp::xml::is_element_mp(a_node, "prefix"))
298 a.m_url_path_prefix = mp::xml::get_text(a_node);
299 else if (mp::xml::is_element_mp(a_node, "raw"))
300 a.m_raw = mp::xml::get_bool(a_node, false);
302 throw mp::filter::FilterException
304 + std::string((const char *) a_node->name)
308 if (a.m_file_root.length())
310 m_p->m_area_list.push_back(a);
315 throw mp::filter::FilterException
317 + std::string((const char *) ptr->name)
318 + " in virt_db filter");
323 static mp::filter::Base* filter_creator()
325 return new mp::filter::HttpFile;
329 struct metaproxy_1_filter_struct metaproxy_1_filter_http_file = {
340 * c-file-style: "Stroustrup"
341 * indent-tabs-mode: nil
343 * vim: shiftwidth=4 tabstop=8 expandtab