continued iplementation of SRU searchRetrieve, added SRU decoding
[metaproxy-moved-to-github.git] / src / filter_sru_to_z3950.cpp
1 /* $Id: filter_sru_to_z3950.cpp,v 1.4 2006-09-14 11:51:08 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8 #include "filter.hpp"
9 #include "package.hpp"
10 #include "util.hpp"
11 #include "filter_sru_to_z3950.hpp"
12
13 #include <yaz/zgdu.h>
14 #include <yaz/srw.h>
15
16 #include <boost/thread/mutex.hpp>
17
18 #include <iostream>
19 #include <sstream>
20 #include <string>
21
22
23 namespace mp = metaproxy_1;
24 namespace yf = mp::filter;
25
26 namespace metaproxy_1 
27 {
28
29     template<typename T>
30     std::string to_string(const T& t)
31     {
32         std::ostringstream o;
33         if(o << t)
34             return o.str();
35         
36         return std::string();
37     }
38
39     std::string http_header_value(const Z_HTTP_Header* header, 
40                                   const std::string name)
41     {
42         while (header && header->name
43                && std::string(header->name) !=  name)
44             header = header->next;
45         
46         if (header && header->name && std::string(header->name) == name
47             && header->value)
48             return std::string(header->value);
49
50         return std::string();
51     }
52     
53
54 }
55
56
57 namespace metaproxy_1 {
58     namespace filter {
59         class SRUtoZ3950::Rep {
60             //friend class SRUtoZ3950;
61         public:
62             void configure(const xmlNode *xmlnode);
63             void process(metaproxy_1::Package &package) const;
64         private:
65             std::string sru_protocol(const Z_HTTP_Request &http_req) const;
66             std::string debug_http(const Z_HTTP_Request &http_req) const;
67             void http_response(metaproxy_1::Package &package, 
68                                const std::string &content, 
69                                int http_code = 200) const;
70         };
71     }
72 }
73
74 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Rep)
75 {
76 }
77
78 yf::SRUtoZ3950::~SRUtoZ3950()
79 {  // must have a destructor because of boost::scoped_ptr
80 }
81
82 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
83 {
84     m_p->configure(xmlnode);
85 }
86
87 void yf::SRUtoZ3950::process(mp::Package &package) const
88 {
89     m_p->process(package);
90 }
91
92 void yf::SRUtoZ3950::Rep::configure(const xmlNode *xmlnode)
93 {
94 }
95
96 void yf::SRUtoZ3950::Rep::process(mp::Package &package) const
97 {
98     Z_GDU *zgdu_req = package.request().get();
99
100     // ignoring all non HTTP_Request packages
101     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
102         package.move();
103         return;
104     }
105     
106     // only working on  HTTP_Request packages now
107     Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
108
109     // SRU request package checking
110  
111     // std::cout << "Detected " << sru_protocol(*http_req) << "\n";
112
113     Z_SRW_PDU *sru_pdu_req = 0;
114     Z_SOAP *soap_req = 0;
115     char *charset = 0;
116     Z_SRW_diagnostic *diag = 0;
117     int num_diags = 0;
118     mp::odr odr(ODR_DECODE);
119     
120     if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap_req, 
121                             odr, &charset, &diag, &num_diags))
122     {
123         std::cout << "SRU GET/POST \n";
124     }
125     else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap_req, 
126                                  odr, &charset))
127     {
128         std::cout << "SRU SOAP \n";
129     } 
130     else 
131     {
132         std::cout << "SRU DECODING ERROR - SHOULD NEVER HAPPEN\n";
133         package.session().close();
134         return;
135     }
136
137     if (num_diags)
138     {
139         std::cout << "SRU DIAGNOSTICS " << num_diags << "\n";
140         // TODO: make nice diagnostic return package 
141         //Z_SRW_PDU *srw_pdu_res =
142         //            yaz_srw_get(odr(ODR_ENCODE),
143         //                        Z_SRW_searchRetrieve_response);
144         //        Z_SRW_searchRetrieveResponse *srw_res = srw_pdu_res->u.response;
145
146         //        srw_res->diagnostics = diagnostic;
147         //        srw_res->num_diagnostics = num_diagnostic;
148         //        send_srw_response(srw_pdu_res);
149         //        return;
150
151         // package.session().close();
152         return;
153     }
154
155     
156     // SRU request package translation to Z3950 package
157
158     // searchRetrieve
159     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_searchRetrieve_request)
160     {
161         Z_SRW_searchRetrieveRequest *srw_req = sru_pdu_req->u.request;   
162
163         // recordXPath unsupported.
164         //if (srw_req->recordXPath)
165         //    yaz_add_srw_diagnostic(odr_decode(),
166         //                           &diag, &num_diags, 72, 0);
167         // sort unsupported
168         //    if (srw_req->sort_type != Z_SRW_sort_type_none)
169         //        yaz_add_srw_diagnostic(odr_decode(),
170         //                               &diag, &num_diags, 80, 0);
171     }
172     else
173     {
174         std::cout << "SRU OPERATION NOT SUPPORTED \n";
175         // TODO: make nice diagnostic return package 
176         // package.session().close();
177         return;
178     }
179     
180
181
182     // sending Z3950 package through pipeline
183     package.move();
184
185
186     // TODO: Z3950 response parsing and translation to SRU package
187     //Z_HTTP_Response* http_res = 0;
188
189     std::string content = debug_http(*http_req);
190     int http_code = 200;
191     
192     http_response(package, content, http_code);
193
194     //package.response() = zgdu_res;
195 }
196
197 std::string 
198 yf::SRUtoZ3950::Rep::sru_protocol(const Z_HTTP_Request &http_req) const
199 {
200     const std::string mime_urlencoded("application/x-www-form-urlencoded");
201     const std::string mime_text_xml("text/xml");
202     const std::string mime_soap_xml("application/soap+xml");
203
204     const std::string http_method(http_req.method);
205     const std::string http_type 
206         =  http_header_value(http_req.headers, "Content-Type");
207
208     if (http_method == "GET")
209         return "SRU GET";
210
211     if (http_method == "POST"
212               && http_type  == mime_urlencoded)
213         return "SRU POST";
214     
215     if ( http_method == "POST"
216          && (http_type  == mime_text_xml
217              || http_type  == mime_soap_xml))
218         return "SRU SOAP";
219
220     return "HTTP";
221 }
222
223 std::string 
224 yf::SRUtoZ3950::Rep::debug_http(const Z_HTTP_Request &http_req) const
225 {
226     std::string message("<html>\n<body>\n<h1>"
227                         "Metaproxy SRUtoZ3950 filter"
228                         "</h1>\n");
229     
230     message += "<h3>HTTP Info</h3><br/>\n";
231     message += "<p>\n";
232     message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
233     message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
234     message += "<b>Path:   </b> " + std::string(http_req.path) + "<br/>\n";
235
236     message += "<b>Content-Type:</b>"
237         + http_header_value(http_req.headers, "Content-Type")
238         + "<br/>\n";
239     message += "<b>Content-Length:</b>"
240         + http_header_value(http_req.headers, "Content-Length")
241         + "<br/>\n";
242     message += "</p>\n";    
243     
244     message += "<h3>Headers</h3><br/>\n";
245     message += "<p>\n";    
246     Z_HTTP_Header* header = http_req.headers;
247     while (header){
248         message += "<b>Header: </b> <i>" 
249             + std::string(header->name) + ":</i> "
250             + std::string(header->value) + "<br/>\n";
251         header = header->next;
252     }
253     message += "</p>\n";    
254     message += "</body>\n</html>\n";
255     return message;
256 }
257
258 void yf::SRUtoZ3950::Rep::http_response(metaproxy_1::Package &package, 
259                                         const std::string &content, 
260                                         int http_code) const
261 {
262
263     Z_GDU *zgdu_req = package.request().get(); 
264     Z_GDU *zgdu_res = 0; 
265     mp::odr odr;
266     zgdu_res 
267        = odr.create_HTTP_Response(package.session(), 
268                                   zgdu_req->u.HTTP_Request, 
269                                   http_code);
270         
271     zgdu_res->u.HTTP_Response->content_len = content.size();
272     zgdu_res->u.HTTP_Response->content_buf 
273         = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
274     
275     strncpy(zgdu_res->u.HTTP_Response->content_buf, 
276             content.c_str(),  zgdu_res->u.HTTP_Response->content_len);
277     
278     //z_HTTP_header_add(odr, &hres->headers,
279     //                  "Content-Type", content_type.c_str());
280     package.response() = zgdu_res;
281 }
282
283
284
285
286 static mp::filter::Base* filter_creator()
287 {
288     return new mp::filter::SRUtoZ3950;
289 }
290
291 extern "C" {
292     struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
293         0,
294         "SRUtoZ3950",
295         filter_creator
296     };
297 }
298
299
300 /*
301  * Local variables:
302  * c-basic-offset: 4
303  * indent-tabs-mode: nil
304  * c-file-style: "stroustrup"
305  * End:
306  * vim: shiftwidth=4 tabstop=8 expandtab
307  */