Fix yaz_use_attribute_create (uninit memory)
[yaz-moved-to-github.git] / src / srwutil.c
index 2cf49c3..493a7a3 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2013 Index Data
+ * Copyright (C) Index Data
  * See the file LICENSE for details.
  */
 /**
@@ -39,30 +39,37 @@ char *yaz_encode_sru_dbpath_odr(ODR out, const char *db)
     return dst;
 }
 
-Z_AttributeList *yaz_use_attribute_create(ODR o, const char *name)
+Z_AttributeElement *yaz_string_element_create(ODR o, int type,
+                                              const char *value)
 {
-    Z_AttributeList *attributes= (Z_AttributeList *)
-        odr_malloc(o, sizeof(*attributes));
-    Z_AttributeElement ** elements;
-    attributes->num_attributes = 1;
-    elements = (Z_AttributeElement**)
-        odr_malloc(o, attributes->num_attributes * sizeof(*elements));
-    elements[0] = (Z_AttributeElement*) odr_malloc(o,sizeof(**elements));
-    elements[0]->attributeType = odr_intdup(o, 1);
-    elements[0]->attributeSet = odr_nullval();
-    elements[0]->which = Z_AttributeValue_complex;
-    elements[0]->value.complex = (Z_ComplexAttribute *)
+    Z_AttributeElement *element = (Z_AttributeElement*)
+        odr_malloc(o, sizeof(*element));
+    element->attributeType = odr_intdup(o, type);
+    element->attributeSet = 0;
+    element->which = Z_AttributeValue_complex;
+    element->value.complex = (Z_ComplexAttribute *)
         odr_malloc(o, sizeof(Z_ComplexAttribute));
-    elements[0]->value.complex->num_list = 1;
-    elements[0]->value.complex->list = (Z_StringOrNumeric **)
+    element->value.complex->num_list = 1;
+    element->value.complex->list = (Z_StringOrNumeric **)
         odr_malloc(o, 1 * sizeof(Z_StringOrNumeric *));
-    elements[0]->value.complex->list[0] = (Z_StringOrNumeric *)
+    element->value.complex->list[0] = (Z_StringOrNumeric *)
         odr_malloc(o, sizeof(Z_StringOrNumeric));
-    elements[0]->value.complex->list[0]->which = Z_StringOrNumeric_string;
-    elements[0]->value.complex->list[0]->u.string = odr_strdup(o, name);
-    elements[0]->value.complex->semanticAction = 0;
-    elements[0]->value.complex->num_semanticAction = 0;
-    attributes->attributes = elements;
+    element->value.complex->list[0]->which = Z_StringOrNumeric_string;
+    element->value.complex->list[0]->u.string = odr_strdup(o, value);
+    element->value.complex->semanticAction = 0;
+    element->value.complex->num_semanticAction = 0;
+    return element;
+}
+
+Z_AttributeList *yaz_use_attribute_create(ODR o, const char *name)
+{
+    Z_AttributeList *attributes = (Z_AttributeList *)
+        odr_malloc(o, sizeof(*attributes));
+
+    attributes->num_attributes = 1;
+    attributes->attributes = (Z_AttributeElement**)
+        odr_malloc(o, sizeof(*attributes->attributes));
+    attributes->attributes[0] = yaz_string_element_create(o, 1, name);
     return attributes;
 }
 
@@ -141,13 +148,6 @@ static void yaz_srw_decodeauth(Z_SRW_PDU *sr, Z_HTTP_Request *hreq,
     }
 }
 
-void yaz_uri_val_int(const char *path, const char *name, ODR o, Odr_int **intp)
-{
-    const char *v = yaz_uri_val(path, name, o);
-    if (v)
-        *intp = odr_intdup(o, atoi(v));
-}
-
 void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d,
                            const char *uri, const char *message,
                            const char *details)
@@ -241,14 +241,21 @@ static void grab_charset(ODR o, const char *content_type, char **charset)
         const char *charset_p = 0;
         if (content_type && (charset_p = strstr(content_type, "; charset=")))
         {
-            int i = 0;
-            charset_p += 10;
-            while (i < 20 && charset_p[i] &&
-                   !strchr("; \n\r", charset_p[i]))
-                i++;
-            *charset = (char*) odr_malloc(o, i+1);
-            memcpy(*charset, charset_p, i);
-            (*charset)[i] = '\0';
+            int j = 0, i = 0;
+            int sep = 0;
+            charset_p += 10; /* skip ; charset=  */
+            if (charset_p[i] == '"' || charset_p[i] == '\'')
+                sep = charset_p[i++];
+            *charset = odr_strdup(o, charset_p);
+            while (charset_p[i] && charset_p[i] != sep)
+            {
+                if (!sep && strchr("; \n\r", charset_p[i]))
+                    break;
+                if (charset_p[i] == '\\' && charset_p[i+1])
+                    i++;
+                (*charset)[j++] = charset_p[i++];
+            }
+            (*charset)[j] = '\0';
         }
     }
 }
@@ -286,7 +293,6 @@ int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                 p1 = p0 + strlen(p0);
             if (p1 != p0)
                 db = yaz_decode_sru_dbpath_odr(decode, p0, p1 - p0);
-            grab_charset(decode, content_type, charset);
 
             ret = z_soap_codec(decode, soap_package,
                                &hreq->content_buf, &hreq->content_len,
@@ -296,7 +302,9 @@ int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
                 yaz_srw_decodeauth(*srw_pdu, hreq, 0, 0, decode);
 
-                if ((*soap_package)->u.generic->no == 3) /* SRU 2 ! */
+                /* last entry in handlers - SRU 2.0 - is turned into
+                   offset 0.. due to other pieces relying on it */
+                if ((*soap_package)->u.generic->no == 3)
                     (*soap_package)->u.generic->no = 0;
                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
                     (*srw_pdu)->u.request->database == 0)
@@ -395,6 +403,9 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
         char *startRecord = 0;
         char *maximumTerms = 0;
         char *responsePosition = 0;
+        const char *facetLimit = 0;
+        const char *facetStart = 0;
+        const char *facetSort = 0;
         Z_SRW_extra_arg *extra_args = 0;
 #endif
         char **uri_name;
@@ -466,6 +477,12 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                     maximumTerms = v;
                 else if (!strcmp(n, "responsePosition"))
                     responsePosition = v;
+                else if (!strcmp(n, "facetLimit"))
+                    facetLimit = v;
+                else if (!strcmp(n, "facetStart"))
+                    facetStart = v;
+                else if (!strcmp(n, "facetSort"))
+                    facetSort = v;
                 else if (!strcmp(n, "extraRequestData"))
                     ; /* ignoring extraRequestData */
                 else if (n[0] == 'x' && n[1] == '-')
@@ -486,8 +503,13 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                 }
             }
         }
-        if (!operation && query)
-            operation = "searchRetrieve";
+        if (!operation)
+        {
+            if (query)
+                operation = "searchRetrieve";
+            else if (scanClause)
+                operation = "scan";
+        }
         version = yaz_negotiate_sru_version(version);
 
         if (!version)
@@ -545,6 +567,8 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
             sr->u.request->recordPacking = recordXMLEscaping;
             sr->u.request->packing = recordPacking;
             sr->u.request->stylesheet = stylesheet;
+            yaz_sru_facet_request(decode , &sr->u.request->facetList,
+                                  &facetLimit, &facetStart, &facetSort);
 
             yaz_sru_decode_integer(decode, "maximumRecords", maximumRecords,
                                    &sr->u.request->maximumRecords,
@@ -771,6 +795,7 @@ Z_SRW_PDU *yaz_srw_get_pdu(ODR o, int which, const char *version)
         sr->u.response = (Z_SRW_searchRetrieveResponse *)
             odr_malloc(o, sizeof(*sr->u.response));
         sr->u.response->numberOfRecords = 0;
+        sr->u.response->resultCountPrecision = 0;
         sr->u.response->resultSetId = 0;
         sr->u.response->resultSetIdleTime = 0;
         sr->u.response->records = 0;
@@ -881,19 +906,19 @@ static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
     int version2 = strcmp(srw_pdu->srw_version, "2.") > 0;
     int i = 0;
     char *queryType;
-    if (!version2)
-        yaz_add_name_value_str(encode, name, value, &i, "version", srw_pdu->srw_version);
+    yaz_add_name_value_str(encode, name, value, &i, "version",
+                           srw_pdu->srw_version);
     name[i] = "operation";
     switch (srw_pdu->which)
     {
     case Z_SRW_searchRetrieve_request:
-        if (!version2)
-            value[i++] = "searchRetrieve";
+        value[i++] = "searchRetrieve";
         queryType = srw_pdu->u.request->queryType;
         if (version2)
         {
-            yaz_add_name_value_str(encode, name, value, &i, "queryType",
-                                   queryType);
+            if (queryType && strcmp(queryType, "cql"))
+                yaz_add_name_value_str(encode, name, value, &i, "queryType",
+                                       queryType);
             yaz_add_name_value_str(encode, name, value, &i, "query",
                                    srw_pdu->u.request->query);
         }
@@ -909,7 +934,7 @@ static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
                 yaz_add_name_value_str(encode, name, value, &i, "x-pquery",
                                        srw_pdu->u.request->query);
             }
-            else if (!strcmp(queryType, "pqf"))
+            else if (!strcmp(queryType, "xcql"))
             {
                 yaz_add_name_value_str(encode, name, value, &i, "x-cql",
                                        srw_pdu->u.request->query);
@@ -946,6 +971,19 @@ static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
                                srw_pdu->u.request->stylesheet);
         yaz_add_name_value_int(encode, name, value, &i, "resultSetTTL",
                                srw_pdu->u.request->resultSetTTL);
+        {
+            const char *facetLimit = 0;
+            const char *facetStart = 0;
+            const char *facetSort = 0;
+            yaz_sru_facet_request(encode, &srw_pdu->u.request->facetList,
+                                  &facetLimit, &facetStart, &facetSort);
+            yaz_add_name_value_str(encode, name, value, &i, "facetLimit",
+                                   (char *) facetLimit);
+            yaz_add_name_value_str(encode, name, value, &i, "facetStart",
+                                   (char *) facetStart);
+            yaz_add_name_value_str(encode, name, value, &i, "facetSort",
+                                   (char *) facetSort);
+        }
         break;
     case Z_SRW_explain_request:
         value[i++] = "explain";
@@ -965,14 +1003,14 @@ static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
         break;
     case Z_SRW_scan_request:
         value[i++] = "scan";
-        queryType = srw_pdu->u.request->queryType;
+        queryType = srw_pdu->u.scan_request->queryType;
         if (version2)
         {
             if (queryType && strcmp(queryType, "cql"))
                 yaz_add_name_value_str(encode, name, value, &i, "queryType",
                                        queryType);
-            yaz_add_name_value_str(encode, name, value, &i, "query",
-                                   srw_pdu->u.request->query);
+            yaz_add_name_value_str(encode, name, value, &i, "scanClause",
+                                   srw_pdu->u.scan_request->scanClause);
         }
         else
         {
@@ -1021,6 +1059,7 @@ int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
     char *name[MAX_SRU_PARAMETERS], *value[MAX_SRU_PARAMETERS]; /* definite upper limit for SRU params */
     char *uri_args;
     char *path;
+    char *cp;
 
     z_HTTP_header_add_basic_auth(encode, &hreq->headers,
                                  srw_pdu->username, srw_pdu->password);
@@ -1030,11 +1069,15 @@ int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
 
     hreq->method = "GET";
 
+    cp = strchr(hreq->path, '#');
+    if (cp)
+        *cp = '\0';
+
     path = (char *)
         odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 4);
 
-    sprintf(path, "%s?%s", hreq->path, uri_args);
-    yaz_log(YLOG_DEBUG, "SRU HTTP Get Request %s", path);
+    sprintf(path, "%s%c%s", hreq->path, strchr(hreq->path, '?') ? '&' : '?', 
+            uri_args);
     hreq->path = path;
 
     z_HTTP_header_add_content_type(encode, &hreq->headers,
@@ -1082,7 +1125,7 @@ int yaz_sru_soap_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
                                  srw_pdu->username, srw_pdu->password);
     z_HTTP_header_add_content_type(odr,
                                    &hreq->headers,
-                                   "text/xml", charset);
+                                   "text/xml", 0 /* no charset in MIME */);
 
     z_HTTP_header_add(odr, &hreq->headers,
                       "SOAPAction", "\"\"");
@@ -1151,6 +1194,9 @@ void yaz_encode_sru_extra(Z_SRW_PDU *sr, ODR odr, const char *extra_args)
         Z_SRW_extra_arg **ea = &sr->extra_args;
         yaz_uri_to_array(extra_args, odr, &name, &val);
 
+        /** append rather than override */
+        while (*ea)
+            ea = &(*ea)->next;
         while (*name)
         {
             *ea = (Z_SRW_extra_arg *) odr_malloc(odr, sizeof(**ea));