source: yaz/trunk/fuentes/src/zoom-sru.c @ 255

Last change on this file since 255 was 255, checked in by mabarracus, 4 years ago

added trusty code to xenial

File size: 15.8 KB
Line 
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
5/**
6 * \file zoom-sru.c
7 * \brief Implements ZOOM SRU
8 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <assert.h>
14#include <string.h>
15#include <errno.h>
16#include "zoom-p.h"
17
18#include <yaz/log.h>
19#include <yaz/pquery.h>
20
21#if YAZ_HAVE_XML2
22static void set_SRU_error(ZOOM_connection c, Z_SRW_diagnostic *d)
23{
24    const char *uri = d->uri;
25    if (uri)
26        ZOOM_set_dset_error(c, ZOOM_uri_to_code(uri), uri, d->details, 0);
27}
28#endif
29
30
31#if YAZ_HAVE_XML2
32static zoom_ret send_srw(ZOOM_connection c, Z_SRW_PDU *sr)
33{
34    Z_GDU *gdu;
35    const char *database =  ZOOM_options_get(c->options, "databaseName");
36
37    gdu = z_get_HTTP_Request_uri(c->odr_out, c->host_port,
38                                 database, c->proxy_mode);
39
40    if (c->sru_mode == zoom_sru_get)
41    {
42        yaz_sru_get_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
43    }
44    else if (c->sru_mode == zoom_sru_post)
45    {
46        yaz_sru_post_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
47    }
48    else if (c->sru_mode == zoom_sru_soap)
49    {
50        yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
51    }
52    else if (c->sru_mode == zoom_sru_solr)
53    {
54        yaz_solr_encode_request(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
55    }
56    return ZOOM_send_GDU(c, gdu);
57}
58#endif
59
60#if YAZ_HAVE_XML2
61static Z_SRW_PDU *ZOOM_srw_get_pdu(ZOOM_connection c, int type)
62{
63    Z_SRW_PDU *sr = yaz_srw_get_pdu(c->odr_out, type, c->sru_version);
64    if (c->url_authentication && c->user)
65    {
66        Z_SRW_extra_arg **ea = &sr->extra_args;
67        while (*ea)
68            ea = &(*ea)->next;
69        *ea = (Z_SRW_extra_arg *) odr_malloc(c->odr_out, sizeof(**ea));
70        (*ea)->name = "x-username";
71        (*ea)->value = c->user;
72        ea = &(*ea)->next;
73        if (c->password)
74        {
75            *ea = (Z_SRW_extra_arg *) odr_malloc(c->odr_out, sizeof(**ea));
76            (*ea)->name = "x-password";
77            (*ea)->value = c->password;
78            ea = &(*ea)->next;
79        }
80        *ea = 0;
81    }
82    else
83    {
84        sr->username = c->user;
85        sr->password = c->password;
86    }
87    return sr;
88}
89#endif
90
91#if YAZ_HAVE_XML2
92zoom_ret ZOOM_connection_srw_send_scan(ZOOM_connection c)
93{
94    ZOOM_scanset scan;
95    Z_SRW_PDU *sr = 0;
96    const char *option_val = 0;
97    Z_Query *z_query;
98
99    if (!c->tasks)
100        return zoom_complete;
101    assert (c->tasks->which == ZOOM_TASK_SCAN);
102    scan = c->tasks->u.scan.scan;
103
104    sr = ZOOM_srw_get_pdu(c, Z_SRW_scan_request);
105
106    z_query = ZOOM_query_get_Z_Query(scan->query);
107    /* SRU scan can only carry CQL and PQF */
108    if (z_query->which == Z_Query_type_104)
109    {
110        sr->u.scan_request->queryType = "cql";
111        sr->u.scan_request->scanClause =
112            odr_strdup(c->odr_out, ZOOM_query_get_query_string(scan->query));
113    }
114    else if (z_query->which == Z_Query_type_1
115             || z_query->which == Z_Query_type_101)
116    {
117        sr->u.scan_request->queryType = "pqf";
118        sr->u.scan_request->scanClause =
119            odr_strdup(c->odr_out, ZOOM_query_get_query_string(scan->query));
120    }
121    else
122    {
123        ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_QUERY, 0);
124        return zoom_complete;
125    }
126
127    sr->u.scan_request->maximumTerms = odr_intdup(
128        c->odr_out, ZOOM_options_get_int(scan->options, "number", 10));
129
130    sr->u.scan_request->responsePosition = odr_intdup(
131        c->odr_out, ZOOM_options_get_int(scan->options, "position", 1));
132
133    option_val = ZOOM_options_get(scan->options, "extraArgs");
134    yaz_encode_sru_extra(sr, c->odr_out, option_val);
135    return send_srw(c, sr);
136}
137#else
138zoom_ret ZOOM_connection_srw_send_scan(ZOOM_connection c)
139{
140    return zoom_complete;
141}
142#endif
143
144#if YAZ_HAVE_XML2
145zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
146{
147    int i;
148    int *start, *count;
149    ZOOM_resultset resultset = 0;
150    Z_SRW_PDU *sr = 0;
151    const char *option_val = 0;
152    const char *schema = 0;
153    Z_Query *z_query;
154    Z_FacetList *facet_list = 0;
155
156    if (c->error)                  /* don't continue on error */
157        return zoom_complete;
158    assert(c->tasks);
159    if (c->tasks->which != ZOOM_TASK_SEARCH)
160        return zoom_complete;
161
162    resultset = c->tasks->u.search.resultset;
163
164    ZOOM_memcached_search(c, resultset);
165
166    if (!resultset->setname)
167        resultset->setname = odr_strdup(resultset->odr, "default");
168    ZOOM_options_set(resultset->options, "setname", resultset->setname);
169    start = &c->tasks->u.search.start;
170    count = &c->tasks->u.search.count;
171    if (resultset->req_facets)
172        facet_list = yaz_pqf_parse_facet_list(c->odr_out,
173                                              resultset->req_facets);
174    schema = c->tasks->u.search.schema;
175
176    if (resultset->live_set)
177    {
178        if (*start >= resultset->size)
179            return zoom_complete;
180        if (*start + *count > resultset->size)
181            *count = resultset->size - *start;
182    }
183    for (i = 0; i < *count; i++)
184    {
185        ZOOM_record rec =
186            ZOOM_record_cache_lookup(resultset, i + *start,
187                                     c->tasks->u.search.syntax,
188                                     c->tasks->u.search.elementSetName,
189                                     schema);
190        if (!rec)
191            break;
192    }
193    *start += i;
194    *count -= i;
195
196    if (*count == 0 && resultset->live_set)
197        return zoom_complete;
198
199    assert(resultset->query);
200
201    sr = ZOOM_srw_get_pdu(c, Z_SRW_searchRetrieve_request);
202    z_query = ZOOM_query_get_Z_Query(resultset->query);
203
204    if (z_query->which == Z_Query_type_104
205        && z_query->u.type_104->which == Z_External_CQL)
206    {
207        sr->u.request->queryType = "cql";
208        sr->u.request->query = z_query->u.type_104->u.cql;
209    }
210    else if (z_query->which == Z_Query_type_1 && z_query->u.type_1)
211    {
212        sr->u.request->queryType = "pqf";
213        sr->u.request->query =
214            odr_strdup(c->odr_out,
215                       ZOOM_query_get_query_string(resultset->query));
216    }
217    else
218    {
219        ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_QUERY, 0);
220        return zoom_complete;
221    }
222
223    option_val = ZOOM_query_get_sru11(resultset->query);
224    if (option_val)
225    {
226        sr->u.request->sort_type = Z_SRW_sort_type_sort;
227        sr->u.request->sort.sortKeys = odr_strdup(c->odr_out, option_val);
228    }
229    sr->u.request->startRecord = odr_intdup(c->odr_out, *start + 1);
230    sr->u.request->maximumRecords = odr_intdup(
231        c->odr_out, (resultset->step > 0 && resultset->step < *count) ?
232        resultset->step : *count);
233    sr->u.request->recordSchema = odr_strdup_null(c->odr_out, schema);
234    sr->u.request->facetList = facet_list;
235
236    option_val = ZOOM_resultset_option_get(resultset, "recordPacking");
237    if (option_val)
238        sr->u.request->recordPacking = odr_strdup(c->odr_out, option_val);
239
240    option_val = ZOOM_resultset_option_get(resultset, "extraArgs");
241    yaz_encode_sru_extra(sr, c->odr_out, option_val);
242    return send_srw(c, sr);
243}
244#else
245zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
246{
247    return zoom_complete;
248}
249#endif
250
251#if YAZ_HAVE_XML2
252static zoom_ret handle_srw_response(ZOOM_connection c,
253                                    Z_SRW_searchRetrieveResponse *res)
254{
255    ZOOM_resultset resultset = 0;
256    int *start, *count;
257    int i;
258    NMEM nmem;
259    ZOOM_Event event;
260    const char *syntax, *elementSetName, *schema;
261
262    if (!c->tasks)
263        return zoom_complete;
264
265    if (c->tasks->which != ZOOM_TASK_SEARCH)
266        return zoom_complete;
267
268    resultset = c->tasks->u.search.resultset;
269    start = &c->tasks->u.search.start;
270    count = &c->tasks->u.search.count;
271    syntax = c->tasks->u.search.syntax;
272    elementSetName = c->tasks->u.search.elementSetName;
273    schema = c->tasks->u.search.schema;
274
275    if (resultset->live_set == 0)
276    {
277        event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
278        ZOOM_connection_put_event(c, event);
279    }
280    if (res->facetList)
281        ZOOM_handle_facet_list(resultset, res->facetList);
282
283    resultset->size = 0;
284
285    if (res->resultSetId)
286        ZOOM_resultset_option_set(resultset, "resultSetId", res->resultSetId);
287
288    yaz_log(c->log_details, "%p handle_srw_response got SRW response OK", c);
289
290    if (res->num_diagnostics > 0)
291    {
292        resultset->live_set = 2;
293        set_SRU_error(c, &res->diagnostics[0]);
294    }
295    else
296    {
297        if (res->numberOfRecords)
298        {
299            Z_OtherInformation *oi = 0;
300            if (res->facetList)
301            {
302                ODR o = c->odr_in;
303                Z_External *ext = (Z_External *)
304                    odr_malloc(o, sizeof(*ext));
305
306                ext->which = Z_External_userFacets;
307                ext->u.facetList = res->facetList;
308                ext->direct_reference =
309                    odr_oiddup(o, yaz_oid_userinfo_facet_1);
310                ext->indirect_reference = 0;
311                ext->descriptor = 0;
312                oi = (Z_OtherInformation *) odr_malloc(o, sizeof(*oi));
313                oi->num_elements = 1;
314                oi->list = (Z_OtherInformationUnit **)
315                    odr_malloc(o, sizeof(*oi->list));
316                oi->list[0] = (Z_OtherInformationUnit *)
317                    odr_malloc(o, sizeof(**oi->list));
318                oi->list[0]->category = 0;
319                oi->list[0]->which = Z_OtherInfo_externallyDefinedInfo;
320                oi->list[0]->information.externallyDefinedInfo = ext;
321            }
322            resultset->size = *res->numberOfRecords;
323            ZOOM_memcached_hitcount(c, resultset, oi,
324                                    res->resultCountPrecision ?
325                                    res->resultCountPrecision : "exact");
326        }
327        resultset->live_set = 2;
328        if (res->suggestions)
329            ZOOM_resultset_option_set(resultset, "suggestions",
330                                      res->suggestions);
331        for (i = 0; i < res->num_records; i++)
332        {
333            int pos = c->tasks->u.search.start + i;
334            Z_SRW_record *sru_rec;
335            Z_SRW_diagnostic *diag = 0;
336            int num_diag;
337
338            /* only trust recordPosition if >= calculated position */
339            if (res->records[i].recordPosition &&
340                *res->records[i].recordPosition >= pos + 1)
341                pos = *res->records[i].recordPosition - 1;
342
343            if (!ZOOM_record_cache_lookup(resultset,
344                                          pos,
345                                          syntax, elementSetName, schema))
346            {
347                Z_NamePlusRecord *npr = (Z_NamePlusRecord *)
348                    odr_malloc(c->odr_in, sizeof(Z_NamePlusRecord));
349                sru_rec = &res->records[i];
350
351                npr->databaseName = 0;
352                npr->which = Z_NamePlusRecord_databaseRecord;
353                npr->u.databaseRecord = (Z_External *)
354                    odr_malloc(c->odr_in, sizeof(Z_External));
355                npr->u.databaseRecord->descriptor = 0;
356                npr->u.databaseRecord->direct_reference =
357                    odr_oiddup(c->odr_in, yaz_oid_recsyn_xml);
358                npr->u.databaseRecord->indirect_reference = 0;
359                npr->u.databaseRecord->which = Z_External_octet;
360
361                npr->u.databaseRecord->u.octet_aligned =
362                    odr_create_Odr_oct(c->odr_in,
363                                       sru_rec->recordData_buf,
364                                   sru_rec->recordData_len);
365                if (sru_rec->recordSchema
366                    && !strcmp(sru_rec->recordSchema,
367                               "info:srw/schema/1/diagnostics-v1.1"))
368                {
369                    sru_decode_surrogate_diagnostics(sru_rec->recordData_buf,
370                                                     sru_rec->recordData_len,
371                                                     &diag, &num_diag,
372                                                     resultset->odr);
373                }
374                ZOOM_record_cache_add(resultset, npr,
375                                      pos, syntax, elementSetName,
376                                      schema, diag);
377            }
378        }
379        *count -= i;
380        if (*count < 0)
381            *count = 0;
382        *start += i;
383        nmem = odr_extract_mem(c->odr_in);
384        nmem_transfer(odr_getmem(resultset->odr), nmem);
385        nmem_destroy(nmem);
386
387        return ZOOM_connection_srw_send_search(c);
388    }
389    return zoom_complete;
390}
391#endif
392
393#if YAZ_HAVE_XML2
394static zoom_ret handle_srw_scan_response(ZOOM_connection c,
395                                         Z_SRW_scanResponse *res)
396{
397    NMEM nmem = odr_extract_mem(c->odr_in);
398    ZOOM_scanset scan;
399
400    if (!c->tasks || c->tasks->which != ZOOM_TASK_SCAN)
401        return zoom_complete;
402    scan = c->tasks->u.scan.scan;
403
404    if (res->num_diagnostics > 0)
405        set_SRU_error(c, &res->diagnostics[0]);
406
407    scan->scan_response = 0;
408    scan->srw_scan_response = res;
409    nmem_transfer(odr_getmem(scan->odr), nmem);
410
411    ZOOM_options_set_int(scan->options, "number", res->num_terms);
412    nmem_destroy(nmem);
413    return zoom_complete;
414}
415#endif
416
417int ZOOM_handle_sru(ZOOM_connection c, Z_HTTP_Response *hres,
418                    zoom_ret *cret, char **addinfo)
419{
420#if YAZ_HAVE_XML2
421    int ret = 0;
422
423    /* not redirect (normal response) */
424    if (!yaz_srw_check_content_type(hres))
425    {
426        *addinfo = "content-type";
427        ret = -1;
428    }
429    else if (c->sru_mode == zoom_sru_solr)
430    {
431        Z_SRW_PDU *sr;
432        ret = yaz_solr_decode_response(c->odr_in, hres, &sr);
433        if (ret == 0)
434        {
435            if (sr->which == Z_SRW_searchRetrieve_response)
436                *cret = handle_srw_response(c, sr->u.response);
437            else if (sr->which == Z_SRW_scan_response)
438                *cret = handle_srw_scan_response(c, sr->u.scan_response);
439        }
440    }
441    else
442    {
443        Z_SOAP *soap_package = 0;
444        ODR o = c->odr_in;
445        Z_SOAP_Handler soap_handlers[4] = {
446            {YAZ_XMLNS_SRU_v1_response, 0, (Z_SOAP_fun) yaz_srw_codec},
447            {YAZ_XMLNS_SRU_v2_mask, 0, (Z_SOAP_fun) yaz_srw_codec},
448            {"searchRetrieveResponse", 0, (Z_SOAP_fun) yaz_srw_codec},
449            {0, 0, 0}
450        };
451        ret = z_soap_codec(o, &soap_package,
452                           &hres->content_buf, &hres->content_len,
453                           soap_handlers);
454        if (!ret && soap_package->which == Z_SOAP_generic)
455        {
456            Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p;
457
458            ZOOM_options_set(c->options, "sru_version", sr->srw_version);
459            ZOOM_options_setl(c->options, "sru_extra_response_data",
460                              sr->extraResponseData_buf, sr->extraResponseData_len);
461            if (sr->which == Z_SRW_searchRetrieve_response)
462                *cret = handle_srw_response(c, sr->u.response);
463            else if (sr->which == Z_SRW_scan_response)
464                *cret = handle_srw_scan_response(c, sr->u.scan_response);
465            else
466                ret = -1;
467        }
468        else if (!ret && (soap_package->which == Z_SOAP_fault
469                          || soap_package->which == Z_SOAP_error))
470        {
471            ZOOM_set_HTTP_error(c, hres->code,
472                                soap_package->u.fault->fault_code,
473                                soap_package->u.fault->fault_string);
474        }
475        else
476        {
477            size_t max_chars = 1000;
478            size_t sz = hres->content_len;
479            if (sz > max_chars - 1)
480                sz = max_chars;
481            *addinfo = odr_malloc(c->odr_in, sz + 4);
482            memcpy(*addinfo, hres->content_buf, sz);
483            if (sz == max_chars)
484                strcpy(*addinfo + sz, "...");
485            else
486                strcpy(*addinfo + sz, "");
487            ret = -1;
488        }
489    }
490    return ret;
491#else
492    return -1;
493#endif
494}
495
496/*
497 * Local variables:
498 * c-basic-offset: 4
499 * c-file-style: "Stroustrup"
500 * indent-tabs-mode: nil
501 * End:
502 * vim: shiftwidth=4 tabstop=8 expandtab
503 */
504
Note: See TracBrowser for help on using the repository browser.