1 /* This file is part of Metaproxy.
2 Copyright (C) 2005-2013 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
23 #include "filter_http_client.hpp"
24 #include <metaproxy/util.hpp>
25 #include "router_chain.hpp"
26 #include <metaproxy/package.hpp>
28 #include <boost/regex.hpp>
29 #include <boost/lexical_cast.hpp>
31 #define BOOST_AUTO_TEST_MAIN
32 #define BOOST_TEST_DYN_LINK
34 #include <boost/test/auto_unit_test.hpp>
36 using namespace boost::unit_test;
37 namespace mp = metaproxy_1;
39 class FilterHeaderRewrite: public mp::filter::Base {
41 void process(mp::Package & package) const {
42 Z_GDU *gdu = package.request().get();
44 if (gdu && gdu->which == Z_GDU_HTTP_Request)
46 std::cout << "Request headers" << std::endl;
47 Z_HTTP_Request *hreq = gdu->u.HTTP_Request;
49 for (Z_HTTP_Header *header = hreq->headers;
51 header = header->next)
53 std::cout << header->name << ": " << header->value << std::endl;
54 rewrite_req_header(header);
58 gdu = package.response().get();
59 if (gdu && gdu->which == Z_GDU_HTTP_Response)
61 std::cout << "Respose headers" << std::endl;
62 Z_HTTP_Response *hr = gdu->u.HTTP_Response;
64 for (Z_HTTP_Header *header = hr->headers;
66 header = header->next)
68 std::cout << header->name << ": " << header->value << std::endl;
73 void configure(const xmlNode* ptr, bool test_only, const char *path) {};
75 void rewrite_req_header(Z_HTTP_Header *header) const
77 //exec regex against value
78 boost::regex re(req_uri_rx);
80 std::string hvalue(header->value);
81 std::map<std::string, std::string> vars;
82 if (regex_match(hvalue, what, re))
85 for (i = 1; i < what.size(); ++i)
87 //check if the group is named
88 std::map<int, std::string>::const_iterator it
89 = groups_by_num.find(i);
90 if (it != groups_by_num.end())
92 std::string name = it->second;
96 //rewrite the header according to the recipe
97 std::string rvalue = sub_vars(req_uri_pat, vars);
98 std::cout << "Rewritten '"+hvalue+"' to '"+rvalue+"'\n";
102 std::cout << "No match found in '" + hvalue + "'\n";
106 static void parse_groups(const std::string & str,
107 std::map<int, std::string> & groups_bynum,
108 std::map<std::string, int> & groups_byname)
112 for (int i = 0; i < str.size(); ++i)
114 if (!esc && str[i] == '\\')
119 if (!esc && str[i] == '(') //group starts
122 if (i+1 < str.size() && str[i+1] == '?') //group with attrs
125 if (i+1 < str.size() && str[i+1] == 'P') //optional, python
127 if (i+1 < str.size() && str[i+1] == '<') //named
132 while (++i < str.size())
134 if (str[i] == '>') { term = true; break; }
135 if (!isalnum(str[i]))
136 throw mp::filter::FilterException
137 ("Only alphanumeric chars allowed, found "
141 + boost::lexical_cast<std::string>(i));
145 throw mp::filter::FilterException
146 ("Unterminated group name '" + gname
147 + " in '" + str +"'");
148 groups_bynum[gnum] = gname;
149 groups_byname[gname] = gnum;
150 std::cout << "Found named group '" << gname
151 << "' at $" << gnum << std::endl;
159 static std::string sub_vars (const std::string & in,
160 const std::map<std::string, std::string> & vars)
164 for (int i = 0; i < in.size(); ++i)
166 if (!esc && in[i] == '\\')
171 if (!esc && in[i] == '$') //var
173 if (i+1 < in.size() && in[i+1] == '{') //ref prefix
178 while (++i < in.size())
180 if (in[i] == '}') { term = true; break; }
183 if (!term) throw mp::filter::FilterException
184 ("Unterminated var ref in '"+in+"' at "
185 + boost::lexical_cast<std::string>(i));
186 std::map<std::string, std::string>::const_iterator it
188 if (it != vars.end())
193 throw mp::filter::FilterException
194 ("Malformed or trimmed var ref in '"
195 +in+"' at "+boost::lexical_cast<std::string>(i));
207 const std::string & req_uri_rx,
208 const std::string & req_uri_pat,
209 const std::string & resp_uri_rx,
210 const std::string & resp_uri_pat)
212 this->req_uri_rx = req_uri_rx;
213 this->req_uri_pat = req_uri_pat;
215 parse_groups(req_uri_rx, groups_by_num, groups_by_name);
216 this->resp_uri_rx = resp_uri_rx;
217 this->resp_uri_pat = resp_uri_pat;
221 std::map<std::string, std::string> vars;
222 std::string req_uri_rx;
223 std::string resp_uri_rx;
224 std::string req_uri_pat;
225 std::string resp_uri_pat;
226 std::map<int, std::string> groups_by_num;
227 std::map<std::string, int> groups_by_name;
232 BOOST_AUTO_TEST_CASE( test_filter_rewrite_1 )
236 FilterHeaderRewrite fhr;
243 BOOST_AUTO_TEST_CASE( test_filter_rewrite_2 )
247 mp::RouterChain router;
249 FilterHeaderRewrite fhr;
251 ".*?(?<host>[^:]+):(?<port>\\d+).*",
252 "http://${host}:${port}/somepath",
255 mp::filter::HTTPClient hc;
260 // create an http request
264 Z_GDU *gdu_req = z_get_HTTP_Request_uri(odr,
265 "http://localhost:80/~jakub/targetsite.php", 0, 1);
267 pack.request() = gdu_req;
270 pack.router(router).move();
272 //analyze the response
273 Z_GDU *gdu_res = pack.response().get();
274 BOOST_CHECK(gdu_res);
275 BOOST_CHECK_EQUAL(gdu_res->which, Z_GDU_HTTP_Response);
277 Z_HTTP_Response *hres = gdu_res->u.HTTP_Response;
281 catch (std::exception & e) {
282 std::cout << e.what();
290 * c-file-style: "Stroustrup"
291 * indent-tabs-mode: nil
293 * vim: shiftwidth=4 tabstop=8 expandtab