Merge branch 'master' into http_file_raw
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 19 Jun 2013 09:44:09 +0000 (11:44 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 19 Jun 2013 09:44:09 +0000 (11:44 +0200)
52 files changed:
IDMETA
NEWS
configure.ac
debian/changelog
debian/control
doc/http_client.xml
etc/Makefile.am
etc/config-proxy-with-loggging.xml [deleted file]
etc/config-proxy.xml [new file with mode: 0644]
example-module/Makefile
example-module/mytest.cpp [new file with mode: 0644]
include/metaproxy/Makefile.am
include/metaproxy/router_chain.hpp [new file with mode: 0644]
include/metaproxy/router_xml.hpp [new file with mode: 0644]
include/metaproxy/util.hpp
metaproxy.spec
src/.gitignore
src/Makefile.am
src/factory_filter.cpp
src/factory_filter.hpp
src/factory_static.cpp
src/filter_cql_to_rpn.cpp
src/filter_cql_to_rpn.hpp
src/filter_http_client.cpp
src/filter_http_rewrite.cpp [new file with mode: 0644]
src/filter_http_rewrite.hpp [new file with mode: 0644]
src/filter_sort.cpp
src/filter_sru_to_z3950.cpp
src/filter_sru_to_z3950.hpp
src/html_parser.cpp [new file with mode: 0644]
src/html_parser.hpp [new file with mode: 0644]
src/metaproxy_prog.cpp
src/router_chain.cpp
src/router_chain.hpp [deleted file]
src/router_xml.cpp [new file with mode: 0644]
src/test_filter2.cpp
src/test_filter_auth_simple.cpp
src/test_filter_backend_test.cpp
src/test_filter_bounce.cpp
src/test_filter_frontend_net.cpp
src/test_filter_log.cpp
src/test_filter_multi.cpp
src/test_filter_query_rewrite.cpp
src/test_filter_record_transform.cpp
src/test_filter_rewrite.cpp [new file with mode: 0644]
src/test_filter_sru_to_z3950.cpp
src/test_filter_virt_db.cpp
src/test_filter_z3950_client.cpp
src/test_html_parser.cpp [new file with mode: 0644]
src/util.cpp
win/makefile
xml/schema/retrievalinfo.rnc

diff --git a/IDMETA b/IDMETA
index 3863584..deeb878 100644 (file)
--- a/IDMETA
+++ b/IDMETA
@@ -1,4 +1,4 @@
 DEBIAN_DIST="wheezy squeeze"
-UBUNTU_DIST="quantal precise oneiric natty lucid"
+UBUNTU_DIST="quantal precise oneiric lucid"
 CENTOS_DIST="centos5 centos6"
-VERSION=1.3.55
+VERSION=1.3.58
diff --git a/NEWS b/NEWS
index df28d02..0f7fd00 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,41 @@
+--- 1.3.58 2013/06/12
+
+Fix loading of filters cql_rpn and sru_z3950 . Was broken by 1.3.57.
+
+--- 1.3.57 2013/06/12
+
+Make RouterChain and RouterXML part of public API (libmetaproxy).
+
+http_client: honor X-Metaproxy-Proxy as an alternative to
+the "proxy" configuration. Allows proxy to be set per HTTP request.
+
+sru_z3950: For SRU requests recognize x-client prefixes as a way
+to ingest "database parameters".. The suffix of x-client- serves
+as database argument name. Multiple may be given. For example:
+  http://path/db/?operation=searchRetrieve&x-client-user=a&x-client-password=b
+is turned into Z39.50 database
+  db,user=a&password=b
+
+--- 1.3.56 2013/05/27
+
+New filter present_chunk. This filter allows splitting of present requests into smaller chunks.
+
+New filter sd_remove, which replaces surrogate diagnostics with
+SUTRS records. This filter tries to deal with clients that breaks
+when receiving surrogate diagnostics.
+
+new filter http_client. Same role as z3950_client, but just for
+HTTP. Allows Metaproxy to operate as a HTTP proxy.
+
+New filter http_rewrite1, which serves as purpose on how to rewrite
+HTTP content with Metaproxy.
+
+Use libboost-system if available, because newer versions of libboost-threads
+requires libboost-system.
+
+Allow frontend_net to serve SSL/HTTPS, because we can specify a server
+certificate now.
+
 --- 1.3.55 2013/04/10
 
 zoom: Torus setting: authenticationMode which may hold values "basic"
index 6f870a0..ada1153 100644 (file)
@@ -45,11 +45,11 @@ if test -z "$YAZPPLIB"; then
     AC_MSG_ERROR([YAZ++ development libraries missing])
 fi
 CPPFLAGS="$YAZPPINC $CPPFLAGS"
-AC_MSG_CHECKING([if YAZ is version 4.2.50 or later])
+AC_MSG_CHECKING([if YAZ is version 4.2.59 or later])
 AC_COMPILE_IFELSE(
         [AC_LANG_PROGRAM([[#include <yaz/yaz-version.h>]],
                          [[
-#if YAZ_VERSIONL < 0x40232
+#if YAZ_VERSIONL < 0x4023B
 #error too old
 #endif
 ]])],
index 9659d7b..f48ea17 100644 (file)
@@ -1,3 +1,21 @@
+metaproxy (1.3.58-1indexdata) unstable; urgency=low
+
+  * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Wed, 12 Jun 2013 21:47:19 +0200
+
+metaproxy (1.3.57-1indexdata) unstable; urgency=low
+
+  * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Wed, 12 Jun 2013 15:01:35 +0200
+
+metaproxy (1.3.56-1indexdata) unstable; urgency=low
+
+  * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Mon, 27 May 2013 13:14:23 +0200
+
 metaproxy (1.3.55-1indexdata) unstable; urgency=low
 
   * Upstream.
index be118e0..1756ecb 100644 (file)
@@ -4,7 +4,7 @@ Standards-Version: 3.6.2
 Maintainer: Adam Dickmeiss <adam@indexdata.dk>
 Priority: extra
 Build-Depends: debhelper (>= 5),
-       libyaz4-dev (>= 4.2.50),
+       libyaz4-dev (>= 4.2.59),
        libyazpp5-dev (>= 1.4.1),
        libxslt1-dev,
        libboost-dev,
index 17d2355..30fd3f8 100644 (file)
 
  <refsect1><title>DESCRIPTION</title>
   <para>
-   This module implements HTTP client functionality. By default,
-   if proxy element is not given, it should be used as an explicit
-   proxy (non-transparent mode). If proxy element is set, requests
-   will be relayed to the proxy given (transparent mode for HTTP clients
-   accessing this module).
+   This module implements HTTP client functionality. Filter rontend_net
+   + http_client in combo - acts as a normal, non-transparent, proxy.
+  </para>
+  <para>
+   The element default-host of configuration specifies the default host
+   in remote URL. If this is set, frontend_net + http_client acts as a
+   transparent HTTP proxy as well.
+  </para>
+  <para>
+   The configuration element, proxy, is optional and enables a remote
+   HTTP proxy to be in use.
   </para>
  </refsect1>
 
@@ -44,7 +50,7 @@
    A typical configuration looks like this:
    <screen><![CDATA[
    <filter type="http_client">
-    <proxy>localhost:9999</proxy>
+    <proxy>localhost:3128</proxy>
    </filter>
 ]]>
    </screen>
index 2b75022..50e4d4c 100644 (file)
@@ -22,6 +22,7 @@ xmlconfig = $(srcdir)/config-bytarget.xml \
     $(srcdir)/config-cgi.xml \
     $(srcdir)/config-solr.xml \
     $(srcdir)/config-zoom.xml \
+    $(srcdir)/config-proxy.xml \
     $(srcdir)/retrieval-info.xml
 
 config = example.simple-auth example.target-auth pqf2pqf.xsl explain.xml \
diff --git a/etc/config-proxy-with-loggging.xml b/etc/config-proxy-with-loggging.xml
deleted file mode 100644 (file)
index 0e28ab6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0"?>
-<metaproxy xmlns="http://indexdata.com/metaproxy" version="1.0">
-  <start route="start"/>
-  <!-- sample config which illustrates the use of http_file filter.. -->
-  <filters>
-    <filter id="frontend" type="frontend_net">
-      <threads>20</threads>
-      <port>@:9000</port> 
-      <message>FN</message>
-      <stat-req>/fn_stat</stat-req>
-    </filter>
-  </filters>
-  <routes>
-    <route id="start">
-      <filter refid="frontend"/>
-      <filter type="http_file">
-       <mimetypes>/etc/mime.types</mimetypes>
-       <area>
-         <documentroot>.</documentroot>
-         <prefix>/etc</prefix>
-       </area>
-      </filter>
-      <filter type="log"><category access="false" line="true" apdu="true" /></filter>
-<!--
-      <filter type="http_rewrite1">
-        <replace content-type="text/html" pattern="YAZ" replacement="yaz"/>
-      </filter>
--->
-      <filter type="http_client">
-<!--
-       <proxy>localhost:9999</proxy>
--->
-      </filter>
-      <filter type="bounce"/>
-    </route>
-  </routes>
-</metaproxy>
-
diff --git a/etc/config-proxy.xml b/etc/config-proxy.xml
new file mode 100644 (file)
index 0000000..f3b522d
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<metaproxy xmlns="http://indexdata.com/metaproxy" version="1.0">
+  <start route="start"/>
+  <!-- sample config which illustrates the use of http_file filter.. -->
+  <routes>
+    <route id="start">
+      <filter type="frontend_net">
+        <threads>10</threads>
+        <port>tcp:@:9000</port>
+        <port cert_fname="ztest.pem">ssl:@:9001</port>
+      </filter>
+      <filter type="log">
+        <message>M</message>
+        <category apdu="true"/>
+      </filter>
+      <filter type="http_client">
+        <!-- <default-host>https://localhost:9999</default-host> -->
+        <!-- <proxy>localhost:3128</proxy> -->
+      </filter>
+    </route>
+  </routes>
+</metaproxy>
+
index a352aed..c73d362 100644 (file)
@@ -1,15 +1,18 @@
 CONFIG=../metaproxy-config
 SO=metaproxy_filter_myfilter.so
 
-all: $(SO)
+all: $(SO) mytest
 
 $(SO): filter_myfilter.cpp
-       echo $(LIBS)
-       $(CXX) -shared `$(CONFIG) --cflags` -fPIC -I ../src $< \
-               -o $(SO) `$(CONFIG) --libs`
+       $(CXX) -shared `$(CONFIG) --cflags` -fPIC $< \
+               -o $@ `$(CONFIG) --libs`
+
+mytest: mytest.cpp
+       $(CXX) `$(CONFIG) --cflags` $< \
+               -o $@ `$(CONFIG) --libs`
 
 clean:
-       rm -f *.so
+       rm -f *.so mytest
 
 run: all
        ../src/metaproxy -c config.xml
diff --git a/example-module/mytest.cpp b/example-module/mytest.cpp
new file mode 100644 (file)
index 0000000..d4bdf0e
--- /dev/null
@@ -0,0 +1,53 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+
+#include <metaproxy/router_chain.hpp>
+#include <yaz/test.h>
+
+namespace mp = metaproxy_1;
+
+void tst(void)
+{
+    try {
+        mp::RouterChain router;
+    }
+    catch ( ... ) {
+        YAZ_CHECK(0);
+    }
+
+}
+
+int main(int argc, char **argv)
+{
+    YAZ_CHECK_INIT(argc, argv);
+    tst();
+    YAZ_CHECK_TERM;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index d5ecded..9c80072 100644 (file)
@@ -2,5 +2,6 @@
 ## Copyright (C) 2005-2013 Index Data
 
 pkginclude_HEADERS= filter.hpp origin.hpp package.hpp \
-       router.hpp session.hpp util.hpp xmlutil.hpp
+       router.hpp router_chain.hpp router_xml.hpp \
+       session.hpp util.hpp xmlutil.hpp
 
diff --git a/include/metaproxy/router_chain.hpp b/include/metaproxy/router_chain.hpp
new file mode 100644 (file)
index 0000000..2d83729
--- /dev/null
@@ -0,0 +1,58 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef ROUTER_CHAIN_HPP
+#define ROUTER_CHAIN_HPP
+
+
+#include <metaproxy/router.hpp>
+
+#include <boost/scoped_ptr.hpp>
+#include <stdexcept>
+
+namespace metaproxy_1 {
+    class RouterChain : public Router {
+        class Rep;
+        class Pos;
+    public:
+        RouterChain();
+        virtual ~RouterChain();
+        virtual RoutePos *createpos() const;
+        RouterChain & append(const filter::Base &filter);
+        void start();
+        void stop();
+    private:
+        boost::scoped_ptr<Rep> m_p;
+        /// disabled because class is singleton
+        RouterChain(const RouterChain &);
+
+        /// disabled because class is singleton
+        RouterChain& operator=(const RouterChain &);
+    };
+}
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/include/metaproxy/router_xml.hpp b/include/metaproxy/router_xml.hpp
new file mode 100644 (file)
index 0000000..2792ba7
--- /dev/null
@@ -0,0 +1,60 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef ROUTER_XML_HPP
+#define ROUTER_XML_HPP
+
+#include <metaproxy/router.hpp>
+
+#include <libxml/tree.h>
+#include <boost/scoped_ptr.hpp>
+
+namespace metaproxy_1
+{
+    class RouterXML : public metaproxy_1::Router
+    {
+        class Rep;
+        class Route;
+        class Pos;
+    public:
+        RouterXML(xmlDocPtr doc,
+                  bool test_only, const char *file_include_path);
+        RouterXML(std::string xmlconf,
+                  bool test_only);
+
+        ~RouterXML();
+
+        virtual RoutePos *createpos() const;
+        void start();
+        void stop();
+    private:
+        boost::scoped_ptr<Rep> m_p;
+    };
+
+};
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 0365919..e5d2768 100644 (file)
@@ -104,6 +104,9 @@ namespace metaproxy_1 {
         void get_default_diag(Z_DefaultDiagFormat *r,
                               int &error_code, std::string &addinfo);
 
+        Z_RecordComposition *piggyback_to_RecordComposition(
+            ODR odr, Odr_int result_set_size, Z_SearchRequest *sreq);
         void piggyback(int smallSetUpperBound,
                        int largeSetLowerBound,
                        int mediumSetPresentNumber,
index 5a7bf29..80e42a3 100644 (file)
@@ -9,7 +9,7 @@ Vendor: Index Data ApS <info@indexdata.dk>
 Source: metaproxy-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
 Prefix: %{_prefix} /etc/metaproxy
-BuildRequires: pkgconfig, libyaz4-devel >= 4.2.50, libyazpp5-devel >= 1.4.1
+BuildRequires: pkgconfig, libyaz4-devel >= 4.2.59, libyazpp5-devel >= 1.4.1
 BuildRequires: libxslt-devel, boost-devel
 Conflicts: cf-engine <= 2.12.5
 Packager: Adam Dickmeiss <adam@indexdata.dk>
index caad553..a9d9820 100644 (file)
@@ -1,39 +1,5 @@
-.libs
-.deps
-*.lo
-*.la
-stamp-h*
+*
+!*.hpp
+!*.cpp
+!*.am
 config.hpp
-socket
-Makefile
-Makefile.in
-config.hpp.in
-ex_filter_frontend_net
-ex_router_flexml
-test_boost_threads
-test_boost_time
-test_filter_auth_simple
-test_filter1
-test_filter2
-test_filter_frontend_net
-test_filter_log
-test_filter_multi
-test_filter_query_rewrite
-test_package1
-test_pipe
-test_thread_pool_observer
-test_session1
-test_session2
-test_filter_factory
-test_filter_z3950_client
-test_filter_backend_test
-test_filter_virt_db
-test_router_flexml
-test_ses_map
-tstdl
-metaproxy
-test_filter_bounce
-test_filter_record_transform
-test_filter_sru_to_z3950
-*.o
-metaproxy-config
index 08aa695..20ed9be 100644 (file)
@@ -12,8 +12,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include $(USEMARCONINC)
 bin_SCRIPTS = metaproxy-config
 
 filter_src = \
-       factory_filter.cpp factory_filter.hpp \
-       factory_static.cpp factory_static.hpp \
        filter_auth_simple.cpp filter_auth_simple.hpp \
        filter_backend_test.cpp filter_backend_test.hpp \
        filter_bounce.cpp filter_bounce.hpp \
@@ -23,6 +21,7 @@ filter_src = \
        filter_http_client.cpp filter_http_client.hpp \
        filter_http_file.cpp filter_http_file.hpp \
        filter_http_rewrite1.cpp filter_http_rewrite1.hpp \
+       filter_http_rewrite.cpp filter_http_rewrite.hpp \
        filter_limit.cpp filter_limit.hpp \
        filter_load_balance.cpp filter_load_balance.hpp \
        filter_log.cpp filter_log.hpp \
@@ -38,14 +37,15 @@ filter_src = \
        filter_virt_db.cpp filter_virt_db.hpp \
        filter_z3950_client.cpp filter_z3950_client.hpp \
        filter_zeerex_explain.cpp  filter_zeerex_explain.hpp \
-       filter_zoom.cpp filter_zoom.hpp \
-       router_chain.hpp router_chain.cpp \
-        router_flexml.hpp router_flexml.cpp
+       filter_zoom.cpp filter_zoom.hpp
 
 lib_LTLIBRARIES = libmetaproxy.la
 libmetaproxy_la_LDFLAGS = -version-info 4:0:0 -export-dynamic
 
 libmetaproxy_la_SOURCES = \
+       $(filter_src) \
+       factory_filter.cpp factory_filter.hpp \
+       factory_static.cpp factory_static.hpp \
        filter.cpp \
        gduutil.cpp gduutil.hpp \
        origin.cpp \
@@ -58,6 +58,10 @@ libmetaproxy_la_SOURCES = \
        torus.cpp torus.hpp \
        url_recipe.cpp \
        util.cpp \
+       html_parser.hpp html_parser.cpp \
+       router_chain.cpp \
+        router_flexml.hpp router_flexml.cpp \
+       router_xml.cpp \
        xmlutil.cpp
 
 libmetaproxy_la_LIBADD = $(YAZPPLALIB) \
@@ -68,6 +72,8 @@ metaproxy_LDADD = libmetaproxy.la $(YAZPPLALIB) \
        $(BOOST_LIB) $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) \
        $(BOOST_REGEX_LIB) $(USEMARCONLALIB)
 
+tstdl_LDADD = $(metaproxy_LDADD)
+
 LDADD = $(metaproxy_LDADD) $(BOOST_TEST_LIB)
 AM_LDFLAGS = -export-dynamic
 
@@ -75,7 +81,7 @@ bin_PROGRAMS = metaproxy
 noinst_PROGRAMS = tstdl
 
 tstdl_SOURCES = tstdl.cpp
-metaproxy_SOURCES = metaproxy_prog.cpp $(filter_src)
+metaproxy_SOURCES = metaproxy_prog.cpp
 
 # Rules for dl programs
 pkglib_LTLIBRARIES = metaproxy_filter_dl.la
@@ -105,37 +111,41 @@ check_PROGRAMS = \
        test_filter_record_transform \
        test_filter_sru_to_z3950 \
        test_filter_virt_db \
+       test_filter_rewrite \
        test_ses_map \
        test_router_flexml \
+       test_html_parser \
        test_xmlutil
 
 TESTS=$(check_PROGRAMS)
 
 test_package1_SOURCES=test_package1.cpp
 test_pipe_SOURCES=test_pipe.cpp
-test_filter1_SOURCES=test_filter1.cpp $(filter_src)
-test_filter2_SOURCES=test_filter2.cpp $(filter_src)
+test_filter1_SOURCES=test_filter1.cpp
+test_filter2_SOURCES=test_filter2.cpp
 test_session1_SOURCES=test_session1.cpp
 test_session2_SOURCES=test_session2.cpp
 test_boost_threads_SOURCES=test_boost_threads.cpp
 test_thread_pool_observer_SOURCES = test_thread_pool_observer.cpp
-test_filter_auth_simple_SOURCES = test_filter_auth_simple.cpp $(filter_src)
-test_filter_factory_SOURCES = test_filter_factory.cpp $(filter_src)
-test_filter_frontend_net_SOURCES = test_filter_frontend_net.cpp $(filter_src)
-test_filter_log_SOURCES = test_filter_log.cpp $(filter_src)
-test_filter_multi_SOURCES = test_filter_multi.cpp $(filter_src)
-test_filter_query_rewrite_SOURCES = test_filter_query_rewrite.cpp $(filter_src)
-test_filter_z3950_client_SOURCES = test_filter_z3950_client.cpp $(filter_src)
-test_filter_backend_test_SOURCES = test_filter_backend_test.cpp $(filter_src)
-test_filter_bounce_SOURCES = test_filter_bounce.cpp $(filter_src)
-test_filter_record_transform_SOURCES = test_filter_record_transform.cpp \
-       $(filter_src)
-test_filter_sru_to_z3950_SOURCES = test_filter_sru_to_z3950.cpp $(filter_src)
-test_filter_virt_db_SOURCES = test_filter_virt_db.cpp $(filter_src)
+test_filter_auth_simple_SOURCES = test_filter_auth_simple.cpp 
+test_filter_factory_SOURCES = test_filter_factory.cpp 
+test_filter_frontend_net_SOURCES = test_filter_frontend_net.cpp 
+test_filter_log_SOURCES = test_filter_log.cpp 
+test_filter_multi_SOURCES = test_filter_multi.cpp 
+test_filter_query_rewrite_SOURCES = test_filter_query_rewrite.cpp
+test_filter_z3950_client_SOURCES = test_filter_z3950_client.cpp
+test_filter_backend_test_SOURCES = test_filter_backend_test.cpp
+test_filter_bounce_SOURCES = test_filter_bounce.cpp
+test_filter_record_transform_SOURCES = test_filter_record_transform.cpp 
+test_filter_sru_to_z3950_SOURCES = test_filter_sru_to_z3950.cpp
+test_filter_virt_db_SOURCES = test_filter_virt_db.cpp 
 test_ses_map_SOURCES = test_ses_map.cpp
-test_router_flexml_SOURCES = test_router_flexml.cpp $(filter_src)
+test_router_flexml_SOURCES = test_router_flexml.cpp
 test_xmlutil_SOURCES = test_xmlutil.cpp
 
+test_html_parser_SOURCES = test_html_parser.cpp 
+test_filter_rewrite_SOURCES = test_filter_rewrite.cpp 
+
 # doxygen target
 dox:
        (cd $(top_srcdir) ; make dox) 
index 7ea6d3a..3915202 100644 (file)
@@ -101,15 +101,6 @@ mp::filter::Base* mp::FactoryFilter::create(std::string fi)
     return (it->second());
 }
 
-bool mp::FactoryFilter::have_dl_support()
-{
-#if HAVE_DLFCN_H
-    return true;
-#else
-    return false;
-#endif
-}
-
 bool mp::FactoryFilter::add_creator_dl(const std::string &fi,
                                         const std::string &path)
 {
index 0b54e14..5498d75 100644 (file)
@@ -50,8 +50,6 @@ namespace metaproxy_1 {
 
         bool add_creator_dl(const std::string &fi, const std::string &path);
 
-        bool have_dl_support();
-
         class NotFound : public std::runtime_error {
         public:
             NotFound(const std::string msg);
index 044e2a7..9f3bbcf 100644 (file)
@@ -54,12 +54,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_z3950_client.hpp"
 #include "filter_zeerex_explain.hpp"
 #include "filter_zoom.hpp"
+#include "filter_http_rewrite.hpp"
 
 namespace mp = metaproxy_1;
 
 mp::FactoryStatic::FactoryStatic()
 {
-#ifdef HAVE_DLFCN_H
     struct metaproxy_1_filter_struct *buildins[] = {
         &metaproxy_1_filter_auth_simple,
         &metaproxy_1_filter_backend_test,
@@ -67,10 +67,11 @@ mp::FactoryStatic::FactoryStatic()
 #ifndef WIN32
         &metaproxy_1_filter_cgi,
 #endif
-        &metaproxy_1_filter_cql_to_rpn,
+        &metaproxy_1_filter_cql_rpn,
         &metaproxy_1_filter_frontend_net,
         &metaproxy_1_filter_http_client,
         &metaproxy_1_filter_http_file,
+        &metaproxy_1_filter_http_rewrite,
         &metaproxy_1_filter_http_rewrite1,
         &metaproxy_1_filter_limit,
         &metaproxy_1_filter_load_balance,
@@ -82,7 +83,7 @@ mp::FactoryStatic::FactoryStatic()
         &metaproxy_1_filter_sd_remove,
         &metaproxy_1_filter_session_shared,
         &metaproxy_1_filter_sort,
-        &metaproxy_1_filter_sru_to_z3950,
+        &metaproxy_1_filter_sru_z3950,
         &metaproxy_1_filter_template,
         &metaproxy_1_filter_virt_db,
         &metaproxy_1_filter_z3950_client,
@@ -94,8 +95,6 @@ mp::FactoryStatic::FactoryStatic()
 
     for (i = 0; buildins[i]; i++)
         add_creator(buildins[i]->type, buildins[i]->creator);
-// WIN32
-#endif
 }
 
 
index 38fb0e0..996af58 100644 (file)
@@ -188,7 +188,7 @@ static mp::filter::Base* filter_creator()
 }
 
 extern "C" {
-    struct metaproxy_1_filter_struct metaproxy_1_filter_cql_to_rpn = {
+    struct metaproxy_1_filter_struct metaproxy_1_filter_cql_rpn = {
         0,
         "cql_rpn",
         filter_creator
index 9976f5a..a61724a 100644 (file)
@@ -41,7 +41,7 @@ namespace metaproxy_1 {
 }
 
 extern "C" {
-    extern struct metaproxy_1_filter_struct metaproxy_1_filter_cql_to_rpn;
+    extern struct metaproxy_1_filter_struct metaproxy_1_filter_cql_rpn;
 }
 
 #endif
index 7703a97..6cb9633 100644 (file)
@@ -71,11 +71,16 @@ void yf::HTTPClient::Rep::proxy(mp::Package &package)
         Z_GDU *res_gdu = 0;
         mp::odr o;
         yaz_url_t yaz_url = yaz_url_create();
-        std::string uri;
+        const char *http_proxy =
+            z_HTTP_header_remove(&hreq->headers, "X-Metaproxy-Proxy");
+
+        if (!http_proxy)
+            http_proxy = proxy_host.c_str();
 
-        if (proxy_host.length())
-            yaz_url_set_proxy(yaz_url, proxy_host.c_str());
+        if (*http_proxy)
+            yaz_url_set_proxy(yaz_url, http_proxy);
 
+        std::string uri;
         if (hreq->path[0] == '/')
         {
             if (default_host.length())
@@ -92,6 +97,7 @@ void yf::HTTPClient::Rep::proxy(mp::Package &package)
         if (http_response)
         {
             res_gdu = o.create_HTTP_Response(package.session(), hreq, 200);
+            z_HTTP_header_remove(&http_response->headers, "Transfer-Encoding");
             res_gdu->u.HTTP_Response = http_response;
         }
         else
diff --git a/src/filter_http_rewrite.cpp b/src/filter_http_rewrite.cpp
new file mode 100644 (file)
index 0000000..d21b4c8
--- /dev/null
@@ -0,0 +1,453 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "config.hpp"
+#include <metaproxy/filter.hpp>
+#include <metaproxy/package.hpp>
+#include <metaproxy/util.hpp>
+#include "filter_http_rewrite.hpp"
+
+#include <yaz/zgdu.h>
+#include <yaz/log.h>
+
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <vector>
+#include <map>
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+namespace mp = metaproxy_1;
+namespace yf = mp::filter;
+
+namespace metaproxy_1 {
+    namespace filter {
+        class HttpRewrite::RuleScope {
+        public:
+            std::vector<std::string> tags;
+            std::vector<std::string> attrs;
+            std::string content_type;
+        };
+        class HttpRewrite::Rule {
+        public:
+            enum Section { METHOD, HEADER, BODY };
+            std::string regex;
+            std::string recipe;
+            std::map<int, std::string> group_index;
+            std::vector<RuleScope> scopes;
+            Section section;
+            const std::string search_replace(
+                std::map<std::string, std::string> & vars,
+                const std::string & txt) const;
+            std::string sub_vars (
+                const std::map<std::string, std::string> & vars) const;
+            void parse_groups();
+        };
+        class HttpRewrite::Rules {
+        public:
+            std::vector<Rule> rules;
+            void rewrite_reqline (mp::odr & o, Z_HTTP_Request *hreq,
+                std::map<std::string, std::string> & vars) const;
+            void rewrite_headers(mp::odr & o, Z_HTTP_Header *headers,
+                std::map<std::string, std::string> & vars) const;
+            void rewrite_body (mp::odr & o,
+                char **content_buf, int *content_len,
+                std::map<std::string, std::string> & vars) const;
+            const std::string test_patterns(
+                std::map<std::string, std::string> & vars,
+                const std::string & txt) const;
+        };
+    }
+}
+
+yf::HttpRewrite::HttpRewrite() : req_rules(new Rules), res_rules(new Rules)
+{
+}
+
+yf::HttpRewrite::~HttpRewrite()
+{
+}
+
+void yf::HttpRewrite::process(mp::Package & package) const
+{
+    yaz_log(YLOG_LOG, "HttpRewrite begins....");
+    Z_GDU *gdu = package.request().get();
+    //map of request/response vars
+    std::map<std::string, std::string> vars;
+    //we have an http req
+    if (gdu && gdu->which == Z_GDU_HTTP_Request)
+    {
+        Z_HTTP_Request *hreq = gdu->u.HTTP_Request;
+        mp::odr o;
+        req_rules->rewrite_reqline(o, hreq, vars);
+        yaz_log(YLOG_LOG, ">> Request headers");
+        req_rules->rewrite_headers(o, hreq->headers, vars);
+        req_rules->rewrite_body(o,
+                &hreq->content_buf, &hreq->content_len,
+                vars);
+        package.request() = gdu;
+    }
+    package.move();
+    gdu = package.response().get();
+    if (gdu && gdu->which == Z_GDU_HTTP_Response)
+    {
+        Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+        yaz_log(YLOG_LOG, "Response code %d", hres->code);
+        mp::odr o;
+        yaz_log(YLOG_LOG, "<< Respose headers");
+        res_rules->rewrite_headers(o, hres->headers, vars);
+        res_rules->rewrite_body(o, &hres->content_buf,
+                &hres->content_len, vars);
+        package.response() = gdu;
+    }
+}
+
+void yf::HttpRewrite::Rules::rewrite_reqline (mp::odr & o,
+        Z_HTTP_Request *hreq,
+        std::map<std::string, std::string> & vars) const
+{
+    //rewrite the request line
+    std::string path;
+    if (strstr(hreq->path, "http://") == hreq->path)
+    {
+        yaz_log(YLOG_LOG, "Path in the method line is absolute, "
+            "possibly a proxy request");
+        path += hreq->path;
+    }
+    else
+    {
+        //TODO what about proto
+        path += "http://";
+        path += z_HTTP_header_lookup(hreq->headers, "Host");
+        path += hreq->path;
+    }
+    yaz_log(YLOG_LOG, "Proxy request URL is %s", path.c_str());
+    std::string npath =
+        test_patterns(vars, path);
+    if (!npath.empty())
+    {
+        yaz_log(YLOG_LOG, "Rewritten request URL is %s", npath.c_str());
+        hreq->path = odr_strdup(o, npath.c_str());
+    }
+}
+
+void yf::HttpRewrite::Rules::rewrite_headers(mp::odr & o,
+        Z_HTTP_Header *headers,
+        std::map<std::string, std::string> & vars) const
+{
+    for (Z_HTTP_Header *header = headers;
+            header != 0;
+            header = header->next)
+    {
+        std::string sheader(header->name);
+        sheader += ": ";
+        sheader += header->value;
+        yaz_log(YLOG_LOG, "%s: %s", header->name, header->value);
+        std::string out = test_patterns(vars, sheader);
+        if (!out.empty())
+        {
+            size_t pos = out.find(": ");
+            if (pos == std::string::npos)
+            {
+                yaz_log(YLOG_LOG, "Header malformed during rewrite, ignoring");
+                continue;
+            }
+            header->name = odr_strdup(o, out.substr(0, pos).c_str());
+            header->value = odr_strdup(o, out.substr(pos+2,
+                        std::string::npos).c_str());
+        }
+    }
+}
+
+void yf::HttpRewrite::Rules::rewrite_body (mp::odr & o,
+        char **content_buf,
+        int *content_len,
+        std::map<std::string, std::string> & vars) const
+{
+    if (*content_buf)
+    {
+        std::string body(*content_buf);
+        std::string nbody =
+            test_patterns(vars, body);
+        if (!nbody.empty())
+        {
+            *content_buf = odr_strdup(o, nbody.c_str());
+            *content_len = nbody.size();
+        }
+    }
+}
+
+/**
+ * Tests pattern from the vector in order and executes recipe on
+ the first match.
+ */
+const std::string yf::HttpRewrite::Rules::test_patterns(
+        std::map<std::string, std::string> & vars,
+        const std::string & txt) const
+{
+    for (size_t i = 0; i < rules.size(); i++)
+    {
+        std::string out = rules[i].search_replace(vars, txt);
+        if (!out.empty()) return out;
+    }
+    return "";
+}
+
+const std::string yf::HttpRewrite::Rule::search_replace(
+        std::map<std::string, std::string> & vars,
+        const std::string & txt) const
+{
+    //exec regex against value
+    boost::regex re(regex);
+    boost::smatch what;
+    std::string::const_iterator start, end;
+    start = txt.begin();
+    end = txt.end();
+    std::string out;
+    while (regex_search(start, end, what, re)) //find next full match
+    {
+        size_t i;
+        for (i = 1; i < what.size(); ++i)
+        {
+            //check if the group is named
+            std::map<int, std::string>::const_iterator it
+                = group_index.find(i);
+            if (it != group_index.end())
+            {   //it is
+                if (!what[i].str().empty())
+                    vars[it->second] = what[i];
+            }
+
+        }
+        //prepare replacement string
+        std::string rvalue = sub_vars(vars);
+        yaz_log(YLOG_LOG, "! Rewritten '%s' to '%s'",
+                what.str(0).c_str(), rvalue.c_str());
+        out.append(start, what[0].first);
+        out.append(rvalue);
+        start = what[0].second; //move search forward
+    }
+    //if we had a match cat the last part
+    if (start != txt.begin())
+        out.append(start, end);
+    return out;
+}
+
+void yf::HttpRewrite::Rule::parse_groups()
+{
+    int gnum = 0;
+    bool esc = false;
+    const std::string & str = regex;
+    std::string res;
+    yaz_log(YLOG_LOG, "Parsing groups from '%s'", str.c_str());
+    for (size_t i = 0; i < str.size(); ++i)
+    {
+        res += str[i];
+        if (!esc && str[i] == '\\')
+        {
+            esc = true;
+            continue;
+        }
+        if (!esc && str[i] == '(') //group starts
+        {
+            gnum++;
+            if (i+1 < str.size() && str[i+1] == '?') //group with attrs
+            {
+                i++;
+                if (i+1 < str.size() && str[i+1] == ':') //non-capturing
+                {
+                    if (gnum > 0) gnum--;
+                    res += str[i];
+                    i++;
+                    res += str[i];
+                    continue;
+                }
+                if (i+1 < str.size() && str[i+1] == 'P') //optional, python
+                    i++;
+                if (i+1 < str.size() && str[i+1] == '<') //named
+                {
+                    i++;
+                    std::string gname;
+                    bool term = false;
+                    while (++i < str.size())
+                    {
+                        if (str[i] == '>') { term = true; break; }
+                        if (!isalnum(str[i]))
+                            throw mp::filter::FilterException
+                                ("Only alphanumeric chars allowed, found "
+                                 " in '"
+                                 + str
+                                 + "' at "
+                                 + boost::lexical_cast<std::string>(i));
+                        gname += str[i];
+                    }
+                    if (!term)
+                        throw mp::filter::FilterException
+                            ("Unterminated group name '" + gname
+                             + " in '" + str +"'");
+                    group_index[gnum] = gname;
+                    yaz_log(YLOG_LOG, "Found named group '%s' at $%d",
+                            gname.c_str(), gnum);
+                }
+            }
+        }
+        esc = false;
+    }
+    regex = res;
+}
+
+std::string yf::HttpRewrite::Rule::sub_vars (
+        const std::map<std::string, std::string> & vars) const
+{
+    std::string out;
+    bool esc = false;
+    const std::string & in = recipe;
+    for (size_t i = 0; i < in.size(); ++i)
+    {
+        if (!esc && in[i] == '\\')
+        {
+            esc = true;
+            continue;
+        }
+        if (!esc && in[i] == '$') //var
+        {
+            if (i+1 < in.size() && in[i+1] == '{') //ref prefix
+            {
+                ++i;
+                std::string name;
+                bool term = false;
+                while (++i < in.size())
+                {
+                    if (in[i] == '}') { term = true; break; }
+                    name += in[i];
+                }
+                if (!term) throw mp::filter::FilterException
+                    ("Unterminated var ref in '"+in+"' at "
+                     + boost::lexical_cast<std::string>(i));
+                std::map<std::string, std::string>::const_iterator it
+                    = vars.find(name);
+                if (it != vars.end())
+                {
+                    out += it->second;
+                }
+            }
+            else
+            {
+                throw mp::filter::FilterException
+                    ("Malformed or trimmed var ref in '"
+                     +in+"' at "+boost::lexical_cast<std::string>(i));
+            }
+            continue;
+        }
+        //passthru
+        out += in[i];
+        esc = false;
+    }
+    return out;
+}
+
+void yf::HttpRewrite::configure_rules(const xmlNode *ptr,
+        Rules & rules)
+{
+    for (ptr = ptr->children; ptr; ptr = ptr->next)
+    {
+        if (ptr->type != XML_ELEMENT_NODE)
+            continue;
+        else if (!strcmp((const char *) ptr->name, "rewrite"))
+        {
+            Rule rule;
+            const struct _xmlAttr *attr;
+            for (attr = ptr->properties; attr; attr = attr->next)
+            {
+                if (!strcmp((const char *) attr->name,  "from"))
+                    rule.regex = mp::xml::get_text(attr->children);
+                else if (!strcmp((const char *) attr->name,  "to"))
+                    rule.recipe = mp::xml::get_text(attr->children);
+                else
+                    throw mp::filter::FilterException
+                        ("Bad attribute "
+                         + std::string((const char *) attr->name)
+                         + " in rewrite section of http_rewrite");
+            }
+            yaz_log(YLOG_LOG, "Found rewrite rule from '%s' to '%s'",
+                    rule.regex.c_str(), rule.recipe.c_str());
+            rule.parse_groups();
+            if (!rule.regex.empty())
+                rules.rules.push_back(rule);
+        }
+        else
+        {
+            throw mp::filter::FilterException
+                ("Bad element o"
+                 + std::string((const char *) ptr->name)
+                 + " in http_rewrite1 filter");
+        }
+    }
+}
+
+void yf::HttpRewrite::configure(const xmlNode * ptr, bool test_only,
+        const char *path)
+{
+    for (ptr = ptr->children; ptr; ptr = ptr->next)
+    {
+        if (ptr->type != XML_ELEMENT_NODE)
+            continue;
+        else if (!strcmp((const char *) ptr->name, "request"))
+        {
+            configure_rules(ptr, *req_rules);
+        }
+        else if (!strcmp((const char *) ptr->name, "response"))
+        {
+            configure_rules(ptr, *res_rules);
+        }
+        else
+        {
+            throw mp::filter::FilterException
+                ("Bad element "
+                 + std::string((const char *) ptr->name)
+                 + " in http_rewrite1 filter");
+        }
+    }
+}
+
+static mp::filter::Base* filter_creator()
+{
+    return new mp::filter::HttpRewrite;
+}
+
+extern "C" {
+    struct metaproxy_1_filter_struct metaproxy_1_filter_http_rewrite = {
+        0,
+        "http_rewrite",
+        filter_creator
+    };
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/filter_http_rewrite.hpp b/src/filter_http_rewrite.hpp
new file mode 100644 (file)
index 0000000..d611142
--- /dev/null
@@ -0,0 +1,59 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef FILTER_HTTP_REWRITE_HPP
+#define FILTER_HTTP_REWRITE_HPP
+
+#include <metaproxy/filter.hpp>
+#include <boost/scoped_ptr.hpp>
+
+namespace mp = metaproxy_1;
+
+namespace metaproxy_1 {
+    namespace filter {
+        class HttpRewrite : public Base {
+            class Rules;
+            class Rule;
+            class RuleScope;
+            boost::scoped_ptr<Rules> req_rules;
+            boost::scoped_ptr<Rules> res_rules;
+            void configure_rules(const xmlNode *ptr, Rules & rules);
+        public:
+            HttpRewrite();
+            ~HttpRewrite();
+            void process(metaproxy_1::Package & package) const;
+            void configure(const xmlNode * ptr, 
+                    bool test_only, const char *path);
+        };
+    }
+}
+
+extern "C" {
+    extern struct metaproxy_1_filter_struct metaproxy_1_filter_http_rewrite;
+}
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index d7d93ae..e36e8cd 100644 (file)
@@ -111,6 +111,7 @@ namespace metaproxy_1 {
                                 Odr_int start_pos,
                                 ResultSetPtr s,
                                 Odr_oid *syntax,
+                                Z_RecordComposition *comp,
                                 const char *resultSetId);
         public:
             Frontend(Impl *impl);
@@ -500,6 +501,7 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
                                         Odr_int start_pos,
                                         ResultSetPtr s,
                                         Odr_oid *syntax,
+                                        Z_RecordComposition *comp,
                                         const char *resultSetId)
 {
     if (records && records->which == Z_Records_DBOSD && start_pos == 1)
@@ -539,6 +541,7 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
             *p_req->numberOfRecordsRequested = end_pos - pos + 1;
             p_req->preferredRecordSyntax = syntax;
             p_req->resultSetId = odr_strdup(odr, resultSetId);
+            p_req->recordComposition = comp;
 
             present_package.request() = p_apdu;
             present_package.move();
@@ -604,9 +607,12 @@ void yf::Sort::Frontend::handle_search(mp::Package &package, Z_APDU *apdu_req)
         Z_APDU_searchResponse)
     {
         Z_SearchResponse *res = gdu_res->u.z3950->u.searchResponse;
+        Z_RecordComposition *record_comp = 
+            mp::util::piggyback_to_RecordComposition(odr,
+                                                     *res->resultCount, req);
         s->hit_count = *res->resultCount;
         handle_records(b_package, apdu_req, res->records, 1, s,
-                       syntax, resultSetId.c_str());
+                       syntax, record_comp, resultSetId.c_str());
         package.response() = gdu_res;
     }
 }
@@ -677,7 +683,8 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
     {
         Z_PresentResponse *res = gdu_res->u.z3950->u.presentResponse;
         handle_records(b_package, apdu_req, res->records,
-                       start, rset, syntax, resultSetId.c_str());
+                       start, rset, syntax, req->recordComposition,
+                       resultSetId.c_str());
         package.response() = gdu_res;
     }
 }
index 5704479..06305bb 100644 (file)
@@ -93,7 +93,8 @@ namespace metaproxy_1 {
                 mp::odr &odr_en,
                 Z_SRW_PDU *sru_pdu_res,
                 Z_SRW_searchRetrieveRequest const *sr_req,
-                std::string zurl
+                std::string zurl,
+                std::string db_append
                 ) const;
 
             bool z3950_present_request(
@@ -224,6 +225,7 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
 
     bool enable_package_log = false;
     std::string zurl;
+    std::string dbargs;
     Z_SRW_extra_arg *arg;
 
     for ( arg = sru_pdu_req->extra_args; arg; arg = arg->next)
@@ -247,6 +249,15 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
                 package.log_enable();
             }
         }
+        else if (!strncmp(arg->name, "x-client-", 9) && arg->value)
+        {
+            if (dbargs.length())
+                dbargs += '&';
+            dbargs += mp_util::uri_encode(arg->name + 9);
+            dbargs += '=';
+            dbargs += mp_util::uri_encode(arg->value);
+        }
+
     assert(sru_pdu_req);
 
     // filter acts as sink for SRU explain requests
@@ -272,7 +283,7 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
                                      zurl, sru_pdu_res, sru_pdu_req))
         {
             ok = z3950_search_request(package, odr_en,
-                                      sru_pdu_res, sr_req, zurl);
+                                      sru_pdu_res, sr_req, zurl, dbargs);
 
             if (ok
                 && sru_pdu_res->u.response->numberOfRecords
@@ -549,7 +560,8 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,
                                                 Z_SRW_PDU *sru_pdu_res,
                                                 Z_SRW_searchRetrieveRequest
                                                 const *sr_req,
-                                                std::string zurl) const
+                                                std::string zurl,
+                                                std::string dbappend) const
 {
 
     assert(sru_pdu_res->u.response);
@@ -568,16 +580,22 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,
                                           &z_searchRequest->num_databaseNames,
                                           &z_searchRequest->databaseNames))
     {
-        z_searchRequest->num_databaseNames = 1;
-        z_searchRequest->databaseNames = (char**)
-            odr_malloc(odr_en, sizeof(char *));
+        std::string db;
 
         if (sr_req->database)
-            z_searchRequest->databaseNames[0]
-                = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
+            db = sr_req->database;
         else
-            z_searchRequest->databaseNames[0]
-                = odr_strdup(odr_en, "Default");
+            db = "Default";
+
+        if (dbappend.length())
+        {
+            db += ",";
+            db += dbappend;
+        }
+        z_searchRequest->num_databaseNames = 1;
+        z_searchRequest->databaseNames = (char**)
+            odr_malloc(odr_en, sizeof(char *));
+        z_searchRequest->databaseNames[0] = odr_strdup(odr_en, db.c_str());
     }
 
     Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
@@ -928,7 +946,7 @@ static mp::filter::Base* filter_creator()
 }
 
 extern "C" {
-    struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
+    struct metaproxy_1_filter_struct metaproxy_1_filter_sru_z3950 = {
         0,
         "sru_z3950",
         filter_creator
index 7d299f9..20f9d83 100644 (file)
@@ -42,7 +42,7 @@ namespace metaproxy_1 {
 }
 
 extern "C" {
-    extern struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950;
+    extern struct metaproxy_1_filter_struct metaproxy_1_filter_sru_z3950;
 }
 
 #endif
diff --git a/src/html_parser.cpp b/src/html_parser.cpp
new file mode 100644 (file)
index 0000000..8d91a2c
--- /dev/null
@@ -0,0 +1,248 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "config.hpp"
+#include "html_parser.hpp"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define TAG_MAX_LEN 64
+
+#define SPACECHR " \t\r\n\f"
+
+#define DEBUG(x) x
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+namespace mp = metaproxy_1;
+
+mp::HTMLParser::HTMLParser()
+{
+}
+
+mp::HTMLParser::~HTMLParser()
+{
+}
+
+static void parse_str(mp::HTMLParserEvent & event, const char * str);
+
+void mp::HTMLParser::parse(mp::HTMLParserEvent & event, const char *str) const
+{
+    parse_str(event, str);
+}
+
+//static C functions follow would probably make sense to wrap this in PIMPL?
+
+static char* dupe (const char *buff, int len)
+{
+    char *value = (char *) malloc (len + 1);
+    assert (value);
+    memcpy (value, buff, len);
+    value[len] = '\0';
+    return value;
+}
+
+static int skipSpace (const char *cp)
+{
+    int i = 0;
+    while (cp[i] && strchr (SPACECHR, cp[i]))
+        i++;
+    return i;
+}
+
+static int skipName (const char *cp, char *dst)
+{
+    int i;
+    int j = 0;
+    for (i=0; cp[i] && !strchr (SPACECHR "/>=", cp[i]); i++)
+       if (j < TAG_MAX_LEN-1)
+       {
+           dst[j] = tolower(cp[j]);
+           j++;
+       }
+    dst[j] = '\0';
+    return i;
+}
+
+static int skipAttribute (const char *cp, char *name, const char **value, int *val_len)
+{
+    int i = skipName (cp, name);   
+    *value = NULL;
+    if (!i)
+        return skipSpace (cp);
+    i += skipSpace (cp + i);
+    if (cp[i] == '=')
+    {
+        int v0, v1;
+        i++;
+        i += skipSpace (cp + i);
+        if (cp[i] == '\"' || cp[i] == '\'')
+        {
+            char tr = cp[i];
+            v0 = ++i;
+            while (cp[i] != tr && cp[i])
+                i++; 
+            v1 = i;
+            if (cp[i])
+                i++;
+        }
+        else
+        {
+            v0 = i;
+            while (cp[i] && !strchr (SPACECHR ">", cp[i]))
+                i++;
+            v1 = i;
+        }
+        *value = cp + v0;
+        *val_len = v1 - v0;
+    }
+    i += skipSpace (cp + i);
+    return i;
+}
+
+static int tagAttrs (mp::HTMLParserEvent & event, 
+                     const char *tagName,
+                     const char *cp)
+{
+    int i;
+    char attr_name[TAG_MAX_LEN];
+    const char *attr_value;
+    int val_len;
+    i = skipSpace (cp);
+    while (cp[i] && cp[i] != '>')
+    {
+        int nor = skipAttribute (cp+i, attr_name, &attr_value, &val_len);
+        i += nor;
+       if (nor)
+       {
+           DEBUG(printf ("------ attr %s=%s\n", attr_name, dupe(attr_value, val_len)));
+            event.attribute(tagName, attr_name, attr_value, val_len);
+       }
+        else
+        {
+            if (!nor)
+                i++;
+        }
+    }
+    return i;
+}
+
+static int tagStart (mp::HTMLParserEvent & event,
+        char *tagName, const char *cp, const char which)
+{
+    int i = 0;
+    i = skipName (cp, tagName);
+    switch (which) 
+    {
+        case '/' : 
+            DEBUG(printf ("------ tag close %s\n", tagName));
+            event.closeTag(tagName);
+            break;
+        case '!' : 
+            DEBUG(printf ("------ dtd %s\n", tagName)); 
+            break;
+        case '?' : 
+            DEBUG(printf ("------ pi %s\n", tagName)); 
+            break;
+        default :  
+            DEBUG(printf ("------ tag open %s\n", tagName));
+            event.openTagStart(tagName);
+            break;
+    }
+    return i;
+}
+
+static int tagEnd (mp::HTMLParserEvent & event, const char *tagName, const char *cp)
+{
+    int i = 0;
+    while (cp[i] && cp[i] != '>')
+        i++;
+    if (cp[i] == '>')
+    {
+        event.anyTagEnd(tagName);
+        i++;
+    }
+    return i;
+}
+
+static void tagText (mp::HTMLParserEvent & event, const char *text_start, const char *text_end)
+{
+    if (text_end - text_start) //got text to flush
+    {
+        DEBUG(printf ("------ text %s\n", dupe(text_start, text_end-text_start)));
+        event.text(text_start, text_end-text_start);
+    }
+}
+
+static void parse_str (mp::HTMLParserEvent & event, const char *cp)
+{
+    const char *text_start = cp;
+    const char *text_end = cp;
+    while (*cp)
+    {
+        if (cp[0] == '<' && cp[1])  //tag?
+        {
+            char which = cp[1];
+            if (which == '/') cp++;
+            if (!strchr (SPACECHR, cp[1])) //valid tag starts
+            {
+                tagText (event, text_start, text_end); //flush any text
+                char tagName[TAG_MAX_LEN];
+                cp++;
+                if (which == '/')
+                {
+                    cp += tagStart (event, tagName, cp, which);
+                }
+                else if (which == '!' || which == '?') //pi or dtd
+                {
+                    cp++;
+                    cp += tagStart (event, tagName, cp, which);
+                }
+                else
+                {
+                    cp += tagStart (event, tagName, cp, which);
+                    cp += tagAttrs (event, tagName, cp);
+                }
+                cp += tagEnd (event, tagName, cp);
+                text_start = cp;
+                text_end = cp;
+                continue;
+            }
+        }
+        //text
+        cp++;
+        text_end = cp;
+    }
+    tagText (event, text_start, text_end); //flush any text
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/html_parser.hpp b/src/html_parser.hpp
new file mode 100644 (file)
index 0000000..ad46061
--- /dev/null
@@ -0,0 +1,53 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef HTML_PARSER_HPP
+#define HTML_PARSER_HPP
+
+#include <boost/scoped_ptr.hpp>
+
+namespace metaproxy_1 {
+        class HTMLParserEvent {
+        public:
+            virtual void openTagStart(const char *name) = 0;
+            virtual void anyTagEnd(const char *name) = 0;
+            virtual void attribute(const char *tagName, 
+                    const char *name, 
+                    const char *value,
+                    int val_len) = 0;
+            virtual void closeTag(const char *name) = 0;
+            virtual void text(const char *value, int len) = 0;
+        };
+        class HTMLParser {
+        public:
+            HTMLParser();
+            ~HTMLParser();
+            void parse(HTMLParserEvent & event, const char *str) const;
+        };
+}
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index bfa1b77..a4ec7f0 100644 (file)
@@ -30,8 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <metaproxy/filter.hpp>
 #include <metaproxy/package.hpp>
 #include <metaproxy/util.hpp>
-#include "router_flexml.hpp"
-#include "factory_static.hpp"
+#include <metaproxy/router_xml.hpp>
 
 #if HAVE_UNISTD_H
 #include <unistd.h>
@@ -45,7 +44,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 namespace mp = metaproxy_1;
 
-mp::RouterFleXML *routerp = 0;
+mp::RouterXML *routerp = 0;
 
 static void set_log_prefix(void)
 {
@@ -84,7 +83,7 @@ static void work_common(void *data)
     signal(SIGTERM, sig_term_handler);
     signal(SIGUSR1, sig_usr1_handler);
 #endif
-    routerp = (mp::RouterFleXML*) data;
+    routerp = (mp::RouterXML*) data;
     routerp->start();
 
     mp::Package pack;
@@ -247,9 +246,8 @@ static int sc_main(
         wrbuf_puts(base_path, ".");
     ret = 0;
     try {
-        mp::FactoryStatic factory;
-        mp::RouterFleXML *router =
-            new mp::RouterFleXML(doc, factory, test_config, wrbuf_cstr(base_path));
+        mp::RouterXML *router =
+            new mp::RouterXML(doc, test_config, wrbuf_cstr(base_path));
         if (!test_config)
         {
 
index 9a3da41..dd80405 100644 (file)
@@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/filter.hpp>
 
 #include <list>
diff --git a/src/router_chain.hpp b/src/router_chain.hpp
deleted file mode 100644 (file)
index 2d83729..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of Metaproxy.
-   Copyright (C) 2005-2013 Index Data
-
-Metaproxy 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, or (at your option) any later
-version.
-
-Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
-
-#ifndef ROUTER_CHAIN_HPP
-#define ROUTER_CHAIN_HPP
-
-
-#include <metaproxy/router.hpp>
-
-#include <boost/scoped_ptr.hpp>
-#include <stdexcept>
-
-namespace metaproxy_1 {
-    class RouterChain : public Router {
-        class Rep;
-        class Pos;
-    public:
-        RouterChain();
-        virtual ~RouterChain();
-        virtual RoutePos *createpos() const;
-        RouterChain & append(const filter::Base &filter);
-        void start();
-        void stop();
-    private:
-        boost::scoped_ptr<Rep> m_p;
-        /// disabled because class is singleton
-        RouterChain(const RouterChain &);
-
-        /// disabled because class is singleton
-        RouterChain& operator=(const RouterChain &);
-    };
-}
-
-#endif
-/*
- * Local variables:
- * c-basic-offset: 4
- * c-file-style: "Stroustrup"
- * indent-tabs-mode: nil
- * End:
- * vim: shiftwidth=4 tabstop=8 expandtab
- */
-
diff --git a/src/router_xml.cpp b/src/router_xml.cpp
new file mode 100644 (file)
index 0000000..9abba65
--- /dev/null
@@ -0,0 +1,92 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "config.hpp"
+#include <metaproxy/router_xml.hpp>
+#include "router_flexml.hpp"
+#include "factory_static.hpp"
+
+namespace mp = metaproxy_1;
+
+namespace metaproxy_1 {
+    class RouterXML::Rep {
+    public:
+        Rep(xmlDocPtr, bool, const char *);
+        Rep(std::string, bool);
+        ~Rep();
+        FactoryStatic m_factory;
+        boost::scoped_ptr<Router> m_flexml;
+    };
+}
+
+mp::RouterXML::Rep::Rep(xmlDocPtr doc, bool test_only,
+                        const char *include_path)
+    : m_factory(),
+      m_flexml(new RouterFleXML(doc, m_factory, test_only, include_path))
+{
+}
+
+mp::RouterXML::Rep::Rep(std::string xmlconf, bool test_only)
+    : m_factory(),
+      m_flexml(new RouterFleXML(xmlconf, m_factory, test_only))
+{
+}
+
+mp::RouterXML::Rep::~Rep()
+{
+}
+
+mp::RouterXML::RouterXML(xmlDocPtr doc,
+                         bool test_only, const char *file_include_path)
+    : m_p(new Rep(doc, test_only, file_include_path))
+{
+}
+
+mp::RouterXML::RouterXML(std::string xmlconf, bool test_only)
+    : m_p(new Rep(xmlconf, test_only))
+{
+}
+
+mp::RouterXML::~RouterXML()
+{
+}
+
+mp::RoutePos *mp::RouterXML::createpos() const
+{
+    return m_p->m_flexml->createpos();
+}
+
+void mp::RouterXML::start()
+{
+    m_p->m_flexml->start();
+}
+
+void mp::RouterXML::stop()
+{
+    m_p->m_flexml->stop();
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index b6f8e21..3f93001 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <libxml/tree.h>
 
 #include <metaproxy/filter.hpp>
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #include <iostream>
index 938ad58..f66445e 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "filter_auth_simple.hpp"
 #include <metaproxy/util.hpp>
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index 24ab0be..76e4730 100644 (file)
@@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_backend_test.hpp"
 #include "filter_log.hpp"
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #include <yaz/zgdu.h>
index 3b95cea..0748a55 100644 (file)
@@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_bounce.hpp"
 #include <metaproxy/util.hpp>
 #include "gduutil.hpp"
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #include <iostream>
index 50b6f37..49001d7 100644 (file)
@@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <metaproxy/util.hpp>
 #include "filter_frontend_net.hpp"
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index 0defe85..73f637a 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "filter_log.hpp"
 #include <metaproxy/util.hpp>
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index dc9cb39..a9eefbd 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "filter_multi.hpp"
 #include <metaproxy/util.hpp>
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index cbe3441..f9234a7 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "filter_query_rewrite.hpp"
 #include <metaproxy/util.hpp>
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index f12be7f..8f2ffa9 100644 (file)
@@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "config.hpp"
 #include "filter_record_transform.hpp"
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
diff --git a/src/test_filter_rewrite.cpp b/src/test_filter_rewrite.cpp
new file mode 100644 (file)
index 0000000..e3802a7
--- /dev/null
@@ -0,0 +1,358 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "config.hpp"
+#include <iostream>
+#include <stdexcept>
+
+#include "filter_http_client.hpp"
+#include "filter_http_rewrite.hpp"
+#include <metaproxy/util.hpp>
+#include <metaproxy/router_chain.hpp>
+#include <metaproxy/package.hpp>
+
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <yaz/log.h>
+
+#define BOOST_AUTO_TEST_MAIN
+#define BOOST_TEST_DYN_LINK
+
+#include <boost/test/auto_unit_test.hpp>
+
+using namespace boost::unit_test;
+namespace mp = metaproxy_1;
+/*
+ * The global testconfig is commented out, as it won't even compile
+ * on old Centos5 machines
+struct TestConfig {
+    TestConfig()   
+    {
+        std::cout << "global setup\n"; 
+        yaz_log_init_level(YLOG_ALL);
+    }
+    ~TestConfig() 
+    { 
+        std::cout << "global teardown\n"; 
+    }
+};
+
+BOOST_GLOBAL_FIXTURE( TestConfig );
+*/
+
+BOOST_AUTO_TEST_CASE( test_filter_rewrite_1 )
+{
+    try
+    {
+        std::cout << "Running non-xml config test case" << std::endl;
+        mp::RouterChain router;
+        mp::filter::HttpRewrite fhr;
+         
+        std::string xmlconf =
+            "<?xml version='1.0'?>\n"
+            "<filter xmlns='http://indexdata.com/metaproxy'\n"
+            "        id='rewrite1' type='http_rewrite'>\n"
+            " <request>\n"
+            "   <rewrite from='"
+    "(?&lt;proto>https?://)(?&lt;pxhost>[^ /?#]+)/(?&lt;pxpath>[^ /]+)"
+    "/(?&lt;host>[^ /]+)(?&lt;path>[^ ]*)'\n"
+            "            to='${proto}${host}${path}' />\n"
+            "   <rewrite from='(?:Host: )(.*)'\n"
+            "            to='Host: ${host}' />\n" 
+            " </request>\n"
+            " <response>\n"
+            "   <rewrite from='"
+    "(?&lt;proto>https?://)(?&lt;host>[^/?# &quot;&apos;>]+)/(?&lt;path>[^  &quot;&apos;>]+)'\n"
+            "            to='${proto}${pxhost}/${pxpath}/${host}/${path}' />\n" 
+            " </response>\n"
+            "</filter>\n"
+        ;
+
+        std::cout << xmlconf;
+
+        // reading and parsing XML conf
+        xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(), xmlconf.size());
+        BOOST_CHECK(doc);
+        xmlNode *root_element = xmlDocGetRootElement(doc);
+        fhr.configure(root_element, true, "");
+        xmlFreeDoc(doc);
+       
+        router.append(fhr);
+
+        // create an http request
+        mp::Package pack;
+
+        mp::odr odr;
+        Z_GDU *gdu_req = z_get_HTTP_Request_uri(odr, 
+        "http://proxyhost/proxypath/targetsite/page1.html", 0, 1);
+
+        pack.request() = gdu_req;
+
+        //create the http response
+
+        const char *resp_buf =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Length: 441\r\n"
+            "Content-Type: text/html\r\n"
+            "Link: <http://targetsite/file.xml>; rel=absolute\r\n"
+            "Link: </dir/file.xml>; rel=relative\r\n"
+            "\r\n"
+            "<html><head><title>Hello proxy!</title>"
+            "<style>"
+            "body {"
+            "  background-image:url('http://targetsite/images/bg.png');"
+            "}"
+            "</style>"
+            "</head>"
+            "<script>var jslink=\"http://targetsite/webservice.xml\";</script>"
+            "<body>"
+            "<p>Welcome to our website. It doesn't make it easy to get pro"
+            "xified"
+            "<a href=\"http://targetsite/page2.html\">"
+            "  An absolute link</a>"
+            "<a target=_blank href='http://targetsite/page3.html\">"
+            "  Another abs link</a>"
+            "<a href=\"/docs/page4.html\" />"
+            "</body></html>";
+
+        const char *resp_expected =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Length: 521\r\n"
+            "Content-Type: text/html\r\n"
+            "Link: <http://proxyhost/proxypath/targetsite/file.xml>; rel=absolute\r\n"
+            "Link: </dir/file.xml>; rel=relative\r\n"
+            "\r\n"
+            "<html><head><title>Hello proxy!</title>"
+            "<style>"
+            "body {"
+            "  background-image:url('http://proxyhost/proxypath/targetsite/images/bg.png');"
+            "}"
+            "</style>"
+            "</head>"
+            "<script>var jslink=\"http://proxyhost/proxypath/targetsite/webservice.xml\";</script>"
+            "<body>"
+            "<p>Welcome to our website. It doesn't make it easy to get pro"
+            "xified"
+            "<a href=\"http://proxyhost/proxypath/targetsite/page2.html\">"
+            "  An absolute link</a>"
+            "<a target=_blank href='http://proxyhost/proxypath/targetsite/page3.html\">"
+            "  Another abs link</a>"
+            "<a href=\"/docs/page4.html\" />"
+            "</body></html>";
+
+        int r;
+        Z_GDU *gdu_res;
+        ODR dec = odr_createmem(ODR_DECODE);
+        odr_setbuf(dec, (char *) resp_buf, strlen(resp_buf), 0);
+        r = z_GDU(dec, &gdu_res, 0, 0);
+
+        BOOST_CHECK(r);
+        if (r)
+        {
+            BOOST_CHECK_EQUAL(gdu_res->which, Z_GDU_HTTP_Response);
+        }
+
+        pack.response() = gdu_res;
+
+        //feed to the router
+        pack.router(router).move();
+
+        //analyze the response
+        Z_GDU *gdu_res_rew = pack.response().get();
+        BOOST_CHECK(gdu_res_rew);
+        BOOST_CHECK_EQUAL(gdu_res_rew->which, Z_GDU_HTTP_Response);
+        
+        Z_HTTP_Response *hres = gdu_res_rew->u.HTTP_Response;
+        BOOST_CHECK(hres);
+
+        //compare buffers
+        std::cout << "Expected result:\n" << resp_expected << std::endl;
+
+        ODR enc = odr_createmem(ODR_ENCODE);
+        z_GDU(enc, &gdu_res_rew, 0, 0);
+        char *resp_result;
+        int resp_result_len;
+        resp_result = odr_getbuf(enc, &resp_result_len, 0);
+        
+        BOOST_CHECK(resp_result);
+        BOOST_CHECK_EQUAL((size_t) resp_result_len, strlen(resp_expected));
+
+        std::cout << "Rewriten result:\n" << resp_result << std::endl;
+        std::cout << "Rewriten result buf len: " << resp_result_len 
+            << std::endl;
+
+        BOOST_CHECK(memcmp(resp_result, resp_expected, resp_result_len) == 0);
+
+        odr_destroy(dec);
+        odr_destroy(enc);
+    }
+    catch (std::exception & e) {
+        std::cout << e.what();
+        std::cout << std::endl;
+        BOOST_CHECK (false);
+    }
+}
+
+/*
+BOOST_AUTO_TEST_CASE( test_filter_rewrite_2 )
+{
+    try
+    {
+        std::cout << "Running xml config test case" << std::endl;
+        mp::RouterChain router;
+        mp::filter::HttpRewrite fhr;
+
+        std::string xmlconf =
+            "<?xml version='1.0'?>\n"
+            "<filter xmlns='http://indexdata.com/metaproxy'\n"
+            "        id='rewrite1' type='http_rewrite'>\n"
+            " <request>\n"
+            "   <rewrite from='"
+    "(?&lt;proto>https?://)(?&lt;pxhost>[^ /?#]+)/(?&lt;pxpath>[^ /]+)"
+    "/(?&lt;host>[^ /]+)(?&lt;path>[^ ]*)'\n"
+            "            to='${proto}${host}${path}' />\n"
+            "   <rewrite from='(?:Host: )(.*)'\n"
+            "            to='Host: ${host}' />\n" 
+            " </request>\n"
+            " <response>\n"
+            "   <rewrite from='"
+    "(?&lt;proto>https?://)(?&lt;host>[^/?# &quot;&apos;>]+)/(?&lt;path>[^  &quot;&apos;>]+)'\n"
+            "            to='${proto}${pxhost}/${pxpath}/${host}/${path}' />\n" 
+            " </response>\n"
+            "</filter>\n"
+        ;
+
+        std::cout << xmlconf;
+
+        // reading and parsing XML conf
+        xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(), xmlconf.size());
+        BOOST_CHECK(doc);
+        xmlNode *root_element = xmlDocGetRootElement(doc);
+        fhr.configure(root_element, true, "");
+        xmlFreeDoc(doc);
+        
+        router.append(fhr);
+
+        // create an http request
+        mp::Package pack;
+
+        mp::odr odr;
+        Z_GDU *gdu_req = z_get_HTTP_Request_uri(odr, 
+        "http://proxyhost/proxypath/targetsite/page1.html", 0, 1);
+
+        pack.request() = gdu_req;
+
+        //create the http response
+
+        const char *resp_buf =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Length: 50\r\n"
+            "Content-Type: text/html\r\n"
+            "Link: <http://targetsite/file.xml>; rel=absolute\r\n"
+            "Link: </dir/file.xml>; rel=relative\r\n"
+            "\r\n"
+            "<html><head><title>Hello proxy!</title>"
+            "<style>"
+            "body {"
+            "  background-image:url('http://targetsite/images/bg.png');"
+            "}"
+            "</style>"
+            "</head>"
+            "<script>var jslink=\"http://targetsite/webservice.xml\";</script>"
+            "<body>"
+            "<p>Welcome to our website. It doesn't make it easy to get pro"
+            "xified"
+            "<a href=\"http://targetsite/page2.html\">"
+            "  An absolute link</a>"
+            "<a target=_blank href='http://targetsite/page3.html\">"
+            "  Another abs link</a>"
+            "<a href=\"/docs/page4.html\" />"
+            "</body></html>";
+
+        const char *resp_buf_rew =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Length: 50\r\n"
+            "Content-Type: text/html\r\n"
+            "Link: <http://proxyhost/proxypath/targetsite/file.xml>; rel=absolute\r\n"
+            "Link: </dir/file.xml>; rel=relative\r\n"
+            "\r\n"
+            "<html><head><title>Hello proxy!</title>"
+            "<style>"
+            "body {"
+            "  background-image:url('http://proxyhost/proxypath/targetsite/images/bg.png');"
+            "}"
+            "</style>"
+            "</head>"
+            "<script>var jslink=\"http://proxyhost/proxypath/targetsite/webservice.xml\";</script>"
+            "<body>"
+            "<p>Welcome to our website. It doesn't make it easy to get pro"
+            "xified"
+            "<a href=\"http://proxyhost/proxypath/targetsite/page.html\">"
+            "  An absolute link</a>"
+            "<a target=_blank href='http://proxyhost/proxypath/targetsite/anotherpage.html\">"
+            "  Another abs link</a>"
+            "<a href=\"/docs/page2.html\" />"
+            "</body></html>";
+
+        int r;
+        Z_GDU *gdu_res;
+        ODR odr2 = odr_createmem(ODR_DECODE);
+        odr_setbuf(odr2, (char *) resp_buf, strlen(resp_buf), 0);
+        r = z_GDU(odr2, &gdu_res, 0, 0);
+
+        BOOST_CHECK(r == 0);
+        if (r)
+        {
+            BOOST_CHECK_EQUAL(gdu_res->which, Z_GDU_HTTP_Response);
+        }
+
+        pack.response() = gdu_res;
+
+        //feed to the router
+        pack.router(router).move();
+
+        //analyze the response
+        Z_GDU *gdu_res_rew = pack.response().get();
+        BOOST_CHECK(gdu_res_rew);
+        BOOST_CHECK_EQUAL(gdu_res_rew->which, Z_GDU_HTTP_Response);
+        
+        Z_HTTP_Response *hres = gdu_res_rew->u.HTTP_Response;
+        BOOST_CHECK(hres);
+
+        //how to compare the buffers:
+
+        odr_destroy(odr2);
+    }
+    catch (std::exception & e) {
+        std::cout << e.what();
+        std::cout << std::endl;
+        BOOST_CHECK (false);
+    }
+}
+*/
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 56216bb..7ea132b 100644 (file)
@@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_sru_to_z3950.hpp"
 #include <metaproxy/util.hpp>
 #include "sru_util.hpp"
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #include <iostream>
index f8e4a78..f8f66cc 100644 (file)
@@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_backend_test.hpp"
 #include "filter_log.hpp"
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
index 03c29c7..4f001ad 100644 (file)
@@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "filter_z3950_client.hpp"
 #include <metaproxy/util.hpp>
 
-#include "router_chain.hpp"
+#include <metaproxy/router_chain.hpp>
 #include <metaproxy/package.hpp>
 
 #define BOOST_AUTO_TEST_MAIN
diff --git a/src/test_html_parser.cpp b/src/test_html_parser.cpp
new file mode 100644 (file)
index 0000000..aa818f9
--- /dev/null
@@ -0,0 +1,107 @@
+/* This file is part of Metaproxy.
+   Copyright (C) 2005-2013 Index Data
+
+Metaproxy 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, or (at your option) any later
+version.
+
+Metaproxy 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "config.hpp"
+#include <iostream>
+#include <stdexcept>
+
+#include "html_parser.hpp"
+#include <metaproxy/util.hpp>
+
+#include <boost/lexical_cast.hpp>
+
+#include <yaz/log.h>
+
+#define BOOST_AUTO_TEST_MAIN
+#define BOOST_TEST_DYN_LINK
+
+#include <boost/test/auto_unit_test.hpp>
+
+using namespace boost::unit_test;
+namespace mp = metaproxy_1;
+
+class MyEvent : public mp::HTMLParserEvent {
+    public:
+        std::string out;
+        void openTagStart(const char *name)
+        {
+            out += "<";
+            out += name;
+        } 
+        
+        void attribute(const char *tagName, 
+                const char *name, const char *value, int val_len)
+        {
+            out += " ";
+            out += name;
+            out += "=\"";
+            out.append(value, val_len);
+            out += "\"";
+        }
+
+        void anyTagEnd(const char *name)
+        {
+            out += ">";
+        }
+        
+        void closeTag(const char *name)
+        {
+            out += "</";
+            out += name;
+        }
+        
+        void text(const char *value, int len)
+        {
+            out.append(value, len);
+        }
+};
+
+
+BOOST_AUTO_TEST_CASE( test_html_parser_1 )
+{
+    try
+    {
+        mp::HTMLParser hp;
+        const char* html = 
+            "<html><body><a t1=v1 t2='v2' t3=\"v3\">some text</a>"
+            "<hr><table ></table  ></body></html";
+        const char* expected = 
+            "<html><body><a t1=\"v1\" t2=\"v2\" t3=\"v3\">some text</a>"
+            "<hr><table></table></body></html";
+        MyEvent e;
+        hp.parse(e, html);
+        BOOST_CHECK_EQUAL(std::string(expected), e.out);
+    }
+    catch (std::exception & e) 
+    {
+        std::cout << e.what();
+        std::cout << std::endl;
+        BOOST_CHECK (false);
+    }
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 81a27f0..4a3d478 100644 (file)
@@ -163,6 +163,26 @@ std::string mp_util::database_name_normalize(const std::string &s)
 
 }
 
+Z_RecordComposition *mp_util::piggyback_to_RecordComposition(
+    ODR odr, Odr_int result_set_size, Z_SearchRequest *sreq)
+{
+    Z_RecordComposition *comp = 0;
+    Odr_int present_dummy;
+    const char *element_set_name = 0;
+    mp::util::piggyback_sr(sreq, result_set_size,
+                           present_dummy, &element_set_name);
+    if (element_set_name)
+    {
+        comp  = (Z_RecordComposition *) odr_malloc(odr, sizeof(*comp));
+        comp->which = Z_RecordComp_simple;
+        comp->u.simple = (Z_ElementSetNames *)
+            odr_malloc(odr, sizeof(Z_ElementSetNames));
+        comp->u.simple->which = Z_ElementSetNames_generic;
+        comp->u.simple->u.generic = odr_strdup(odr, element_set_name);
+    }
+    return comp;
+}
+
 void mp_util::piggyback_sr(Z_SearchRequest *sreq,
                            Odr_int result_set_size,
                            Odr_int &number_to_present,
index 90707dc..b763485 100644 (file)
@@ -7,7 +7,7 @@
 DEBUG=0   # 0 for release, 1 for debug
 
 # Metaproxy version
-VERSION=1.3.55
+VERSION=1.3.58
 
 # YAZ and YAZ++ directories
 YAZ_DIR=..\..\yaz
@@ -245,6 +245,7 @@ PROJECT_DLL_OBJS = \
        $(OBJDIR)\plainfile.obj \
         $(OBJDIR)\router_chain.obj \
         $(OBJDIR)\router_flexml.obj \
+        $(OBJDIR)\router_xml.obj \
         $(OBJDIR)\session.obj \
         $(OBJDIR)\sru_util.obj \
        $(OBJDIR)\thread_pool_observer.obj \
index 3e75da2..0695261 100644 (file)
@@ -32,8 +32,6 @@ retrievalinfo =
       attribute syntax { xsd:string },
       attribute name { xsd:string }?,
       attribute identifier { xsd:string }?,
-      #attribute backendsyntax { xsd:string }?,
-      #attribute backendname { xsd:string }?,
       element y:backend {
       attribute syntax { xsd:string },
       attribute name { xsd:string }?,